/** * Inline WGSL shader for the WebGPU physics benchmark. * Mirrors packages/engine/src/gpu/shaders/particle-physics.wgsl. * Keep in sync with the canonical shader. */ export declare const PARTICLE_PHYSICS_WGSL = "\nstruct Uniforms {\n dt: f32,\n gravity: f32,\n groundY: f32,\n restitution: f32,\n friction: f32,\n particleCount: u32,\n _pad1: f32,\n _pad2: f32,\n};\n\n@group(0) @binding(0) var uniforms: Uniforms;\n\n@group(0) @binding(1) var positions_in: array>;\n@group(0) @binding(2) var velocities_in: array>;\n@group(0) @binding(3) var states_in: array>;\n\n@group(0) @binding(4) var positions_out: array>;\n@group(0) @binding(5) var velocities_out: array>;\n@group(0) @binding(6) var states_out: array>;\n\nconst SLEEP_VELOCITY_THRESHOLD: f32 = 0.01;\nconst SLEEP_FRAMES_REQUIRED: f32 = 10.0;\nconst COLLISION_DAMPING: f32 = 0.8;\n\nfn resolveGroundCollision(\n position: vec3,\n velocity: vec3,\n radius: f32\n) -> vec4 {\n var pos = position;\n var vel = velocity;\n if (pos.y < uniforms.groundY + radius) {\n pos.y = uniforms.groundY + radius;\n vel.y = -vel.y * uniforms.restitution;\n vel.x *= uniforms.friction;\n vel.z *= uniforms.friction;\n if (abs(vel.y) < 0.05) {\n vel.y = 0.0;\n }\n }\n return vec4(vel, f32(pos.y <= uniforms.groundY + radius + 0.01));\n}\n\nfn checkParticleCollision(\n myIdx: u32,\n myPos: vec3,\n myVel: vec3,\n myRadius: f32,\n myMass: f32\n) -> vec3 {\n var resultVel = myVel;\n let checkRadius: u32 = 100u;\n let startIdx = max(0u, myIdx - checkRadius);\n let endIdx = min(uniforms.particleCount, myIdx + checkRadius);\n for (var i = startIdx; i < endIdx; i = i + 1u) {\n if (i == myIdx) { continue; }\n let otherPos = positions_in[i].xyz;\n let otherRadius = positions_in[i].w;\n let otherVel = velocities_in[i].xyz;\n let otherMass = velocities_in[i].w;\n let delta = myPos - otherPos;\n let dist = length(delta);\n let minDist = myRadius + otherRadius;\n if (dist < minDist && dist > 0.0001) {\n let normal = delta / dist;\n let relVel = myVel - otherVel;\n let velAlongNormal = dot(relVel, normal);\n if (velAlongNormal < 0.0) {\n let impulse = -(1.0 + COLLISION_DAMPING) * velAlongNormal / (1.0 / myMass + 1.0 / otherMass);\n resultVel += impulse * normal / myMass;\n }\n }\n }\n return resultVel;\n}\n\n@compute @workgroup_size(256)\nfn main(@builtin(global_invocation_id) id: vec3) {\n let idx = id.x;\n if (idx >= uniforms.particleCount) { return; }\n\n let pos_in = positions_in[idx];\n let vel_in = velocities_in[idx];\n let state_in = states_in[idx];\n\n var pos = pos_in.xyz;\n let radius = pos_in.w;\n var vel = vel_in.xyz;\n let mass = vel_in.w;\n let active_flag = state_in.x;\n let sleeping = state_in.y;\n let health = state_in.z;\n let userData = state_in.w;\n\n if (active_flag < 0.5 || sleeping > 0.5) {\n positions_out[idx] = pos_in;\n velocities_out[idx] = vel_in;\n states_out[idx] = state_in;\n return;\n }\n\n vel.y -= uniforms.gravity * uniforms.dt;\n pos += vel * uniforms.dt;\n\n let groundResult = resolveGroundCollision(pos, vel, radius);\n vel = groundResult.xyz;\n let hitGround = groundResult.w;\n if (hitGround > 0.5) {\n pos.y = uniforms.groundY + radius;\n }\n\n vel = checkParticleCollision(idx, pos, vel, radius, mass);\n\n var sleepCounter = userData;\n let speed = length(vel);\n if (speed < SLEEP_VELOCITY_THRESHOLD) {\n sleepCounter += 1.0;\n } else {\n sleepCounter = 0.0;\n }\n var newSleeping = sleeping;\n if (sleepCounter >= SLEEP_FRAMES_REQUIRED) {\n newSleeping = 1.0;\n vel = vec3(0.0, 0.0, 0.0);\n }\n if (hitGround > 0.5 && speed > 0.1) {\n newSleeping = 0.0;\n sleepCounter = 0.0;\n }\n\n positions_out[idx] = vec4(pos, radius);\n velocities_out[idx] = vec4(vel, mass);\n states_out[idx] = vec4(active_flag, newSleeping, health, sleepCounter);\n}\n"; //# sourceMappingURL=particle-physics-shader.d.ts.map