This commit is contained in:
Zack Buhman 2026-08-01 20:19:00 -05:00
parent 136a752e04
commit 6e5576cd07
12 changed files with 217 additions and 55 deletions

53
flat.js
View File

@ -135,43 +135,43 @@ class FlatRenderer {
return density; return density;
} }
createParticles(device) createBuffers(device)
{ {
this.maxDim = 32; this.maxDim = 32;
this.maxParticles = this.maxDim * this.maxDim; this.maxParticles = this.maxDim * this.maxDim;
this.particleStride = 4 * 3; // in elements this.particleStride = this.module.instance.exports.particle__stride(); // bytes
this.particles = new Float32Array(this.maxParticles * this.particleStride); this.particlesSize = this.maxParticles * this.particleStride; // bytes
this.maxGradientsDim = 32; this.maxGradientsDim = 32;
this.maxGradients = this.maxGradientsDim * this.maxGradientsDim; this.maxGradients = this.maxGradientsDim * this.maxGradientsDim;
this.gradientStride = 4 * 2; this.gradientStride = 4 * 2;
this.gradients = new Float32Array(this.maxGradients * this.gradientStride);
this.particleConfigurationStride = this.module.instance.exports.particle_configuration__stride();
this.particleBuffers = []; this.particleBuffers = [];
this.gradientBuffers = []; this.gradientBuffers = [];
this.particleBindGroups = [];
this.particleConfiguration = new Float32Array(4 * 4);
this.particleConfigurationBuffers = []; this.particleConfigurationBuffers = [];
this.particleBindGroups = [];
for (let i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
const particleBuffer = device.createBuffer({ const particleBuffer = device.createBuffer({
label: `particle buffer ${i}`, label: `particle buffer ${i}`,
size: this.particles.byteLength, size: this.particlesSize,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
}); });
this.particleBuffers.push(particleBuffer); this.particleBuffers.push(particleBuffer);
const gradientBuffer = device.createBuffer({ const gradientBuffer = device.createBuffer({
label: `gradient buffer ${i}`, label: `gradient buffer ${i}`,
size: this.gradients.byteLength, size: 4 * 4 * 2,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
}); });
this.gradientBuffers.push(gradientBuffer); this.gradientBuffers.push(gradientBuffer);
const configBuffer = device.createBuffer({ const configBuffer = device.createBuffer({
label: `particle configuration buffer ${i}`, label: `particle configuration buffer ${i}`,
size: this.particleConfiguration.byteLength, size: this.particleConfigurationStride,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
}); });
this.particleConfigurationBuffers.push(configBuffer); this.particleConfigurationBuffers.push(configBuffer);
@ -192,21 +192,16 @@ class FlatRenderer {
}); });
this.particleBindGroups.push(bindGroup); this.particleBindGroups.push(bindGroup);
} }
for (let i = 0; i < this.maxParticles; i++) {
// position
const position = [Math.random(), Math.random()];
this.particles[i * this.particleStride + 0] = position[0];
this.particles[i * this.particleStride + 1] = position[1];
this.particles[i * this.particleStride + 2] = 0.0;
this.particles[i * this.particleStride + 3] = 1.0;
// value.x
this.particles[i * this.particleStride + 4] = test(position);
}
} }
constructor(device, canvasFormat, viewUniformBuffer, shaderModule) initializeState()
{ {
}
constructor(device, canvasFormat, viewUniformBuffer, shaderModule, module)
{
this.module = module;
const label = "flat"; const label = "flat";
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -296,7 +291,7 @@ class FlatRenderer {
// particles // particles
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
this.createParticles(device); this.createBuffers(device);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// bind group // bind group
@ -434,10 +429,10 @@ class FlatRenderer {
render(device, renderPass, frameNumber, configuration) render(device, renderPass, frameNumber, configuration)
{ {
// particle update must be before gradient update // particle update must be before gradient update
this.updateParticles(device, frameNumber, configuration); //this.updateParticles(device, frameNumber, configuration);
this.updateGradients(device, frameNumber, configuration); //this.updateGradients(device, frameNumber, configuration);
this.updateSimulation(device, frameNumber, configuration); //this.updateSimulation(device, frameNumber, configuration);
this.updateConfiguration(device, frameNumber, configuration); //this.updateConfiguration(device, frameNumber, configuration);
renderPass.setPipeline(this.renderPipeline); renderPass.setPipeline(this.renderPipeline);
renderPass.setIndexBuffer(this.buffer, "uint16"); renderPass.setIndexBuffer(this.buffer, "uint16");
@ -447,7 +442,7 @@ class FlatRenderer {
} }
} }
async function loadFlat(device, canvasFormat, viewUniformBuffer) async function loadFlat(device, canvasFormat, viewUniformBuffer, module)
{ {
const flatWgsl = await getPath("flat.wgsl"); const flatWgsl = await getPath("flat.wgsl");
const shaderModule = device.createShaderModule({ const shaderModule = device.createShaderModule({
@ -455,7 +450,7 @@ async function loadFlat(device, canvasFormat, viewUniformBuffer)
code: flatWgsl, code: flatWgsl,
}); });
const renderer = new FlatRenderer(device, canvasFormat, viewUniformBuffer, shaderModule); const renderer = new FlatRenderer(device, canvasFormat, viewUniformBuffer, shaderModule, module);
return renderer; return renderer;
} }

View File

@ -47,6 +47,7 @@ const module = await WebAssembly.instantiateStreaming(fetch("src/module.wasm"),
log: console.log, log: console.log,
} }
}); });
module.memory = memory;
function createDepthTexture() { function createDepthTexture() {
return device.createTexture({ return device.createTexture({
@ -98,7 +99,7 @@ module.instance.exports.camera_init(cameraStateAddress);
//const gltfRenderer = await loadGltf(device, canvasFormat, viewUniformBuffer, memory, module); //const gltfRenderer = await loadGltf(device, canvasFormat, viewUniformBuffer, memory, module);
//const lightRenderer = await loadLight(device, canvasFormat, viewUniformBuffer); //const lightRenderer = await loadLight(device, canvasFormat, viewUniformBuffer);
const flatRenderer = await loadFlat(device, canvasFormat, viewUniformBuffer); const flatRenderer = await loadFlat(device, canvasFormat, viewUniformBuffer, module);
const KEY = { const KEY = {

View File

@ -32,6 +32,10 @@ LDFLAGS = \
-Wl,--export=camera_move \ -Wl,--export=camera_move \
-Wl,--export=camera_init \ -Wl,--export=camera_init \
-Wl,--export=camera_view_projection \ -Wl,--export=camera_view_projection \
-Wl,--export=particle_system__create \
-Wl,--export=particle_system__update \
-Wl,--export=particle__stride \
-Wl,--export=particle_configuration__stride \
-Wl,--import-undefined \ -Wl,--import-undefined \
-Wl,--print-map \ -Wl,--print-map \
-Wl,--import-memory \ -Wl,--import-memory \
@ -49,7 +53,10 @@ PNG_OBJ = \
$(MINIZ)/miniz_tinfl.o \ $(MINIZ)/miniz_tinfl.o \
memory.o \ memory.o \
node.o \ node.o \
camera.o camera.o \
fluid/particle.o \
fluid/particle_system.o \
fluid/api.o
module.wasm: $(PNG_OBJ) module.wasm: $(PNG_OBJ)
clang++ $(CFLAGS) $(LDFLAGS) -o $@ $^ clang++ $(CFLAGS) $(LDFLAGS) -o $@ $^

26
src/builtin_math.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#define acosf(x) __builtin_acosf(x)
#define asinf(x) __builtin_asinf(x)
#define atan2f(x, y) __builtin_atan2f(x, y)
#define atanf(x) __builtin_atanf(x)
#define ceilf(x) __builtin_ceilf(x)
#define cosf(x) __builtin_cosf(x)
#define coshf(x) __builtin_coshf(x)
#define exp2f(x) __builtin_exp2f(x)
#define expf(x) __builtin_expf(x)
#define fabsf(x) __builtin_fabsf(x)
#define floorf(x) __builtin_floorf(x)
#define isinf(x) (false)
#define isnan(x) (false)
#define log10f(x) __builtin_log10f(x)
#define log2f(x) __builtin_log2f(x)
#define logf(x) __builtin_logf(x)
#define modff(x, y) __builtin_modff(x, y)
#define powf(x, y) __builtin_powf(x, y)
#define sinf(x) __builtin_sinf(x)
#define sinhf(x) __builtin_sinhf(x)
#define sqrtf(x) __builtin_sqrtf(x)
#define tanf(x) __builtin_tanf(x)
#define tanhf(x) __builtin_tanhf(x)
#define sign(x) ((x > 0) - (x < 0))

View File

@ -154,32 +154,9 @@
#endif // !_XM_NO_INTRINSICS_ #endif // !_XM_NO_INTRINSICS_
#include "sal.h" #include "sal.h"
//#include <assert.h>
#define assert(x) #define assert(x)
#define isnan(x) (false)
#define floorf(x) __builtin_floorf(x)
#define sqrtf(x) __builtin_sqrtf(x)
#define expf(x) __builtin_expf(x)
#define exp2f(x) __builtin_exp2f(x)
#define logf(x) __builtin_logf(x)
#define log2f(x) __builtin_log2f(x)
#define log10f(x) __builtin_log10f(x)
#define powf(x, y) __builtin_powf(x, y)
#define fabsf(x) __builtin_fabsf(x)
#define sinf(x) __builtin_sinf(x)
#define sinhf(x) __builtin_sinhf(x)
#define tanf(x) __builtin_tanf(x)
#define tanhf(x) __builtin_tanhf(x)
#define cosf(x) __builtin_cosf(x)
#define asinf(x) __builtin_asinf(x)
#define acosf(x) __builtin_acosf(x)
#define coshf(x) __builtin_coshf(x)
#define atanf(x) __builtin_atanf(x)
#define atan2f(x, y) __builtin_atan2f(x, y)
#define isinf(x) (false)
#define ceilf(x) __builtin_ceilf(x)
#define modff(x, y) __builtin_modff(x, y)
#include <stddef.h> #include <stddef.h>
#include "builtin_math.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)

29
src/fluid/api.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "particle_system.h"
#include "new.h"
using namespace fluid;
extern "C" {
ParticleSystem * particle_system__create(int maxParticles)
{
auto particleSystem = New<ParticleSystem>();
particleSystem->init(maxParticles);
return particleSystem;
}
void particle_system__update(ParticleSystem * particleSystem)
{
particleSystem->update();
}
int particle__stride()
{
return (sizeof (Particle));
}
int particle_configuration__stride()
{
return (sizeof (ParticleConfiguration));
}
};

32
src/fluid/particle.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "particle.h"
namespace fluid
{
void Particle::update(ParticleConfiguration * configuration)
{
XMVECTOR nextPosition = XMLoadFloat4(&position);
XMVECTOR nextVelocity = XMLoadFloat4(&velocity);
nextVelocity += XMVectorSet(0, 1, 0, 0) * configuration->gravity;
nextPosition += nextVelocity;
resolveCollision(configuration);
XMStoreFloat4(&position, nextPosition);
XMStoreFloat4(&velocity, nextVelocity);
}
void Particle::resolveCollision(ParticleConfiguration * configuration)
{
XMVECTOR halfExtents = XMLoadFloat2(&configuration->halfExtents) - XMVectorReplicate(configuration->particleRadius);
if (fabsf(position.x) > XMVectorGetX(halfExtents)) {
position.x = XMVectorGetX(halfExtents) * sign(position.x);
velocity.x *= -1;
}
if (fabsf(position.y) > XMVectorGetX(halfExtents)) {
position.y = XMVectorGetX(halfExtents) * sign(position.y);
velocity.y *= -1;
}
}
}

17
src/fluid/particle.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "directxmath/DirectXMath.h"
#include "particle_configuration.h"
namespace fluid {
struct Particle {
XMFLOAT4 position;
XMFLOAT4 velocity;
XMFLOAT4 value;
void update(ParticleConfiguration * configuration);
void resolveCollision(ParticleConfiguration * configuration);
};
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "directxmath/DirectXMath.h"
namespace fluid {
struct ParticleConfiguration {
float particleCount;
float particleRadius;
float particleMass1;
float particleMass2;
float smoothingRadius;
float lineThickness;
float lineLength;
float _padding1;
float targetDensity;
float pressure;
float gravity;
float _padding2;
XMFLOAT2 testSamplePosition;
XMFLOAT2 halfExtents;
};
}

View File

@ -0,0 +1,25 @@
#include "particle_system.h"
#include "new.h"
namespace fluid {
void ParticleSystem::init(int maxParticles)
{
this->maxParticles = maxParticles;
configuration = New<ParticleConfiguration>();
particles = New<Particle>(maxParticles);
for (int i = 0; i < maxParticles; i++) {
XMStoreFloat4(&particles[i].position, XMVectorZero());
XMStoreFloat4(&particles[i].velocity, XMVectorZero());
XMStoreFloat4(&particles[i].value, XMVectorZero());
}
}
void ParticleSystem::update()
{
for (int i = 0; i < configuration->particleCount; i++) {
particles[i].update(configuration);
}
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "particle.h"
namespace fluid {
struct ParticleSystem {
ParticleConfiguration * configuration;
Particle * particles;
int maxParticles;
void init(int maxParticles);
void update();
};
};

11
src/new.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "memory.h"
template <typename T>
T * New(int count = 1)
{
size_t size = size_t(count) * (sizeof (T));
T * ptr = reinterpret_cast<T *>(mem_alloc(size));
return ptr;
}