+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()
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()
uniform float dt;
+uniform vec3 handPos[2];
+uniform vec3 handVel[2];
struct particle_t {
vec4 positionAndSize;
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;
}