WebGPU Example Mixing compute shader and renderer flocking example Simple first pass at a SPH simulation smooth particle hydrodynamics predefines const numParticles 300 const circleRadius 0 04 0 1 let canvas document createElement canvas document body appendChild canvas canvas width 400 canvas height 400 console log canvas width console log canvas height const adapter await navigator gpu requestAdapter const device await adapter requestDevice GRAPHICS GRAPHICS GRAPHICS GRAPHICS GRAPHICS GRAPHICS GRAPHICS const context canvas getContext webgpu const devicePixelRatio window devicePixelRatio 1 const presentationSize canvas clientWidth devicePixelRatio canvas clientHeight devicePixelRatio context getPreferredFormat adapter no longer supported const presentationFormat navigator gpu getPreferredCanvasFormat context configure device format presentationFormat size presentationSize var spriteWGSL struct VertexOutput builtin position Position vec4 f32 location 0 vel vec2 f32 vertex fn vert_main location 0 a_particlePos vec2 f32 location 1 a_particleVel vec2 f32 location 2 a_pos vec2 f32 VertexOutput var output VertexOutput output Position vec4 f32 a_pos a_particlePos 0 0 1 0 output vel a_particleVel return output fragment fn frag_main location 0 vel vec2 f32 location 0 vec4 f32 let c clamp length vel 10 0 0 0 1 0 return vec4 f32 c 0 1 0 1 1 0 const spriteShaderModule device createShaderModule code spriteWGSL const renderPipeline device createRenderPipeline layout auto vertex module spriteShaderModule entryPoint vert_main buffers instanced particles buffer arrayStride 4 4 stepMode instance attributes instance position shaderLocation 0 offset 0 format float32x2 instance velocity shaderLocation 1 offset 2 4 format float32x2 vertex buffer arrayStride 2 4 stepMode vertex attributes vertex positions shaderLocation 2 offset 0 format float32x2 fragment module spriteShaderModule entryPoint frag_main targets format presentationFormat primitive topology triangle list const renderPassDescriptor GPURenderPassDescriptor colorAttachments view undefined Assigned later loadValue r 1 0 g 1 0 b 1 0 a 1 0 clear color loadOp clear clearValue 0 1 1 1 clear screen storeOp store small circle let circleVerts 20 let points for let k 0 k circleVerts k points push 0 points push 0 points push circleRadius Math cos k 0 circleVerts circleVerts Math PI 2 points push circleRadius Math sin k 0 circleVerts circleVerts Math PI 2 points push circleRadius Math cos k 1 circleVerts circleVerts Math PI 2 points push circleRadius Math sin k 1 circleVerts circleVerts Math PI 2 const vertexBufferData new Float32Array points const spriteVertexBuffer device createBuffer size vertexBufferData byteLength usage GPUBufferUsage VERTEX mappedAtCreation true new Float32Array spriteVertexBuffer getMappedRange set vertexBufferData spriteVertexBuffer unmap COMPUTE COMPUTE COMPUTE COMPUTE COMPUTE COMPUTE COMPUTE COMPUTE COMPUTE var updateWGSL struct Particle pos vec2 f32 vel vec2 f32 struct SimParams deltaT f32 rule1Distance f32 rule2Distance f32 rule3Distance f32 rule1Scale f32 rule2Scale f32 rule3Scale f32 radius f32 struct Particles particles array Particle binding 0 group 0 var uniform params SimParams binding 1 group 0 var storage read particlesA Particles binding 2 group 0 var storage read_write particlesB Particles compute workgroup_size 64 fn main builtin global_invocation_id GlobalInvocationID vec3 u32 var index u32 GlobalInvocationID x var vPos particlesA particles index pos var vVel particlesA particles index vel var cMass vec2 f32 0 0 0 0 var cVel vec2 f32 0 0 0 0 var colVel vVel vec2 f32 0 0 0 0 var cMassCount u32 0u var cVelCount u32 0u var pos vec2 f32 var vel vec2 f32 for var i u32 0u i arrayLength particlesA particles i i 1u if i index continue pos particlesA particles i pos xy if distance pos vPos params radius 2 0 let dir normalize pos vPos if the objects are moving towards one another if dot dir vVel 0 0 let d5 params radius 0 5 let pen clamp length pos vPos 10 0 d5 d5 colVel colVel dir pen colVel y colVel y 0 005 small downward pull Repell boundary edges let s params radius 0 5 if vPos x 1 0 params radius colVel x colVel x s if vPos x 1 0 params radius colVel x colVel x s if vPos y 1 0 params radius colVel y colVel y s if vPos y 1 0 params radius colVel y colVel y s clamp velocity for a more pleasing simulation vVel normalize colVel clamp length colVel 0 0 0 5 kinematic update vPos vPos vVel params deltaT Write back particlesB particles index pos vPos particlesB particles index vel vVel const computePipeline device createComputePipeline layout auto compute module device createShaderModule code updateWGSL entryPoint main const simParams deltaT 0 02 rule1Distance 0 1 rule2Distance 0 025 rule3Distance 0 025 rule1Scale 0 02 rule2Scale 0 05 rule3Scale 0 005 radius circleRadius const simParamBufferSize 8 Float32Array BYTES_PER_ELEMENT const simParamBuffer device createBuffer size simParamBufferSize usage GPUBufferUsage UNIFORM GPUBufferUsage COPY_DST device queue writeBuffer simParamBuffer 0 new Float32Array simParams deltaT simParams rule1Distance simParams rule2Distance simParams rule3Distance simParams rule1Scale simParams rule2Scale simParams rule3Scale simParams radius const initialParticleData new Float32Array numParticles 4 for let i 0 i numParticles i initialParticleData 4 i 0 2 Math random 0 5 posx initialParticleData 4 i 1 2 Math random 0 5 posy initialParticleData 4 i 2 2 Math random 0 5 0 1 velx initialParticleData 4 i 3 2 Math random 0 5 0 1 vely const particleBuffers new Array 2 GPUBuffer const particleBindGroups new Array 2 GPUBindGroup for let i 0 i 2 i particleBuffers i device createBuffer size initialParticleData byteLength usage GPUBufferUsage VERTEX GPUBufferUsage STORAGE mappedAtCreation true new Float32Array particleBuffers i getMappedRange set initialParticleData particleBuffers i unmap for let i 0 i 2 i particleBindGroups i device createBindGroup layout computePipeline getBindGroupLayout 0 entries binding 0 resource buffer simParamBuffer binding 1 resource buffer particleBuffers i offset 0 size initialParticleData byteLength binding 2 resource buffer particleBuffers i 1 2 offset 0 size initialParticleData byteLength let tt 0 function frame Sample is no longer the active page if canvas return renderPassDescriptor colorAttachments 0 view context getCurrentTexture createView const commandEncoder device createCommandEncoder update compute shader using compute buffer 1 const passEncoder commandEncoder beginComputePass passEncoder setPipeline computePipeline passEncoder setBindGroup 0 particleBindGroups tt 2 passEncoder dispatch Math ceil numParticles 64 no longer supported passEncoder dispatchWorkgroups Math ceil numParticles 64 passEncoder endPass no longer supported passEncoder end render to screen using computer buffer 2 const passEncoder commandEncoder beginRenderPass renderPassDescriptor passEncoder setPipeline renderPipeline passEncoder setVertexBuffer 0 particleBuffers tt 1 2 passEncoder setVertexBuffer 1 spriteVertexBuffer passEncoder draw points length 2 numParticles 0 0 passEncoder endPass no longer supported passEncoder end device queue submit commandEncoder finish tt switch buffers requestAnimationFrame frame frame setInterval frame 200 console log ready
vec2 f32 0 0 0 0 var colVel vVel vec2 f32 0 0 0 0 var cMassCount u32 0u var cVelCount u32 0u var pos vec2 f32 var vel vec2 f32 for var i u32 0u i arrayLength particlesA particles i i 1u if i index continue pos particlesA particles i pos xy if distance pos vPos params radius 2 0 let dir normalize pos vPos if the objects are moving towards one another if dot dir vVel 0 0 let d5 params radius 0 5 let pen clamp length pos vPos 10 0 d5 d5 colVel colVel dir pen colVel y colVel y 0 005 small downward pull Repell boundary edges let s params radius 0 5 if vPos x 1 0 params radius colVel x colVel x s if vPos x 1 0 params radius colVel x colVel x s if vPos y 1 0 params radius colVel y colVel y s if vPos y 1 0 params radius colVel y colVel y s clamp velocity for a more pleasing simulation vVel normalize colVel clamp length colVel 0 0 0 5 kinematic update vPos vPos vVel params deltaT Write back particlesB particles index pos vPos particlesB particles index vel vVel const computePipeline device createComputePipeline layout auto compute module device createShaderModule code updateWGSL entryPoint main const simParams deltaT 0 02 rule1Distance 0 1 rule2Distance 0 025 rule3Distance 0 025 rule1Scale 0 02 rule2Scale 0 05 rule3Scale 0 005 radius circleRadius const simParamBufferSize 8 Float32Array BYTES_PER_ELEMENT const simParamBuffer device createBuffer size simParamBufferSize usage GPUBufferUsage UNIFORM GPUBufferUsage COPY_DST device queue writeBuffer simParamBuffer 0 new Float32Array simParams deltaT simParams rule1Distance simParams rule2Distance simParams rule3Distance simParams rule1Scale simParams rule2Scale simParams rule3Scale simParams radius const initialParticleData new Float32Array numParticles 4 for let i 0 i numParticles i initialParticleData 4 i 0 2 Math random 0 5 posx initialParticleData 4 i 1 2 Math random 0 5 posy initialParticleData 4 i 2 2 Math random 0 5 0 1 velx initialParticleData 4 i 3 2 Math random 0 5 0 1 vely const particleBuffers new Array 2 GPUBuffer const particleBindGroups new Array 2 GPUBindGroup for let i 0 i 2 i particleBuffers i device createBuffer size initialParticleData byteLength usage GPUBufferUsage VERTEX GPUBufferUsage STORAGE mappedAtCreation true new Float32Array particleBuffers i getMappedRange set initialParticleData particleBuffers i unmap for let i 0 i 2 i particleBindGroups i device createBindGroup layout computePipeline getBindGroupLayout 0 entries binding 0 resource buffer simParamBuffer binding 1 resource buffer particleBuffers i offset 0 size initialParticleData byteLength binding 2 resource buffer particleBuffers i 1 2 offset 0 size initialParticleData byteLength let tt 0 function frame Sample is no longer the active page if canvas return renderPassDescriptor colorAttachments 0 view context getCurrentTexture createView const commandEncoder device createCommandEncoder update compute shader using compute buffer 1 const passEncoder commandEncoder beginComputePass passEncoder setPipeline computePipeline passEncoder setBindGroup 0 particleBindGroups tt 2 passEncoder dispatch Math ceil numParticles 64 no longer supported passEncoder dispatchWorkgroups Math ceil numParticles 64 passEncoder endPass no longer supported passEncoder end render to screen using computer buffer 2 const passEncoder commandEncoder beginRenderPass renderPassDescriptor passEncoder setPipeline renderPipeline passEncoder setVertexBuffer 0 particleBuffers tt 1 2 passEncoder setVertexBuffer 1 spriteVertexBuffer passEncoder draw points length 2 numParticles 0 0 passEncoder endPass no longer supported passEncoder end device queue submit commandEncoder finish tt switch buffers requestAnimationFrame frame frame setInterval frame 200 console log ready