From: Cassie Jones Date: Sat, 1 Feb 2020 06:33:50 +0000 (-0500) Subject: Use hand motion to influence particle motion X-Git-Url: https://git.witchoflight.com/lovr-particles/commitdiff_plain Use hand motion to influence particle motion We upload the hand motion (position and velocity) and use it to move particles. The area of influence is based on the velocity of the hands: faster moving hands affect a wider area, slower affect a smaller area. This is intended to simulate the wake of the hand in a fluid, and has the bonus effect that when your hands aren't moving they don't affect many particles. The particles are accelerated by mixing their velocity with the hand's velocity, with the weight for that depending on the distance and the velocity of the hand. Using mixing instead of direct accelerating prevents you from accelerating particles faster than your hands move, which simulates the feeling of them being pulled along in a current in the fluid. --- diff --git a/main.lua b/main.lua index b931f2f..5c56689 100644 --- a/main.lua +++ b/main.lua @@ -1,14 +1,18 @@ +local vec3 = lovr.math.vec3 local mat4 = lovr.math.mat4 +local quat = lovr.math.quat local nParticles = 2 ^ 14 local batchSize = 128 local batches = nParticles / batchSize +local dt = 0.01 local features local shaders = {} local blocks = {} local meshes = {} local compute = {} +local hands = {} function lovr.load() features = lovr.graphics.getFeatures() @@ -30,27 +34,50 @@ function lovr.load() compute.particles = lovr.graphics.newComputeShader("shaders/particles.comp") compute.particles:sendBlock('particleData', blocks.particles) - compute.particles:send("dt", 0.01) + compute.particles:send("dt", dt) - local xr, yr, zr = range(-1, 1), range(1, 3), range(-2, 0) + local xr, yr, zr = range(-1, 1), range(1, 3), range(-1, -0.5) local sr, vr = range(0.005, 0.01), range(-0.05, 0.05) local initial = initialParticleData(nParticles, xr, yr, zr, sr, vr) blocks.particles:send("particles", initial) + + for _, hand in ipairs(lovr.headset.getHands()) do + local x, y, z = lovr.headset.getPose(hand) + hands[hand] = { + pos = lovr.math.newVec3(x, y, z), + vel = lovr.math.newVec3(0, 0, 0), + rot = lovr.math.newQuat(), + } + end end function lovr.draw() lovr.graphics.clear() local x, y, z = lovr.headset.getPose("head") + shaders.particles:send("headPos", vec3(x, y, z)) + local positions = {} + local velocities = {} + for _, hand in ipairs(lovr.headset.getHands()) do + local x, y, z, a, ax, ay, az = lovr.headset.getPose(hand) + local pos = vec3(x, y, z) + hands[hand].vel:set((pos - hands[hand].pos) / dt) + hands[hand].pos:set(pos) + hands[hand].rot:set(a, ax, ay, az) + table.insert(positions, pos) + table.insert(velocities, hands[hand].vel) + end + compute.particles:send("handPos", positions) + compute.particles:send("handVel", velocities) + lovr.graphics.compute(compute.particles, batches) -- Read the buffer to force SSBO synch of some sort. blocks.particles:read("reloadFlag") - shaders.particles:send("headPos", {x, y, z}) lovr.graphics.setColor(0.6, 0.1, 0) lovr.graphics.setShader(nil) - for _, hand in ipairs(lovr.headset.getHands()) do - local x, y, z, a, ax, ay, az = lovr.headset.getPose(hand) - lovr.graphics.cube("fill", x, y, z, 0.1, a, ax, ay, az) + for _, hand in pairs(hands) do + -- local x, y, z = hand.pos:unpack() + lovr.graphics.cube("fill", hand.pos, 0.1, hand.rot) end withDepthTest("lequal", false, function() diff --git a/shaders/particles.comp b/shaders/particles.comp index 6e136b4..c16ddd2 100644 --- a/shaders/particles.comp +++ b/shaders/particles.comp @@ -1,4 +1,6 @@ uniform float dt; +uniform vec3 handPos[2]; +uniform vec3 handVel[2]; struct particle_t { vec4 positionAndSize; @@ -11,10 +13,19 @@ layout(std430) buffer particleData { particle_t particles[]; }; +vec3 wrap(vec3 v) { return mod(v, 2.0) - 1.0 + vec3(0.0, 1.0, 0.0); } + layout(local_size_x = 128) in; void compute() { uint id = gl_GlobalInvocationID.x; vec3 vel = particles[id].velocity.xyz; - particles[id].positionAndSize.xyz += vel * dt; - particles[id].velocity.xyz -= vel * length(vel) * dt; + vec3 pos = particles[id].positionAndSize.xyz; + for (int i = 0; i < 2; i++) { + float speed = clamp(length(handVel[i]), 0.0, 3.0); + float dist = distance(handPos[i], pos); + float factor = 1.0 - smoothstep(0.0, speed * 0.1, dist); + vel = mix(vel, handVel[i], factor * 0.01); + } + particles[id].positionAndSize.xyz = wrap(pos + vel * dt); + particles[id].velocity.xyz = vel - vel * length(vel) * dt; }