-- Surround yourself with monkeys and efficiently move them with compute shaders ASSUME_FRAMERATE = 1/120 function lovr.load() MONKEYS = 500 -- Create some random transforms local random, randomNormal = lovr.math.random, lovr.math.randomNormal local transforms = {} for i = 1, MONKEYS do local position = vec3(randomNormal(8), randomNormal(8), randomNormal(8)) local orientation = quat(random(2 * math.pi), random(), random(), random()) local scale = vec3(.75) transforms[i] = mat4(position, scale, orientation) end -- More random transforms-- this will correspond to the transform applied to each monkey per frame local offsets = {} for i = 1, MONKEYS do local position = vec3(randomNormal(1), randomNormal(8), randomNormal(8)):mul(ASSUME_FRAMERATE) local radianSwing = ASSUME_FRAMERATE * math.pi / 2 local orientation = quat(random(-radianSwing, radianSwing), random(), random(), random()) local scale = vec3(1) offsets[i] = mat4(position, scale, orientation) end -- Create a Buffer to store positions for lots of models transformBuffer = lovr.graphics.newBuffer('mat4', transforms) offsetBuffer = lovr.graphics.newBuffer('mat4', offsets) -- Create the compute shader, we will run this once per frame computeShader = lovr.graphics.newShader([[ layout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in; buffer TransformBuffer { mat4 Transforms[]; }; buffer OffsetBuffer { mat4 Offsets[]; }; uniform uint monkeyCount; void lovrmain() { uint i = GlobalThreadID.x; if (i >= monkeyCount) return; Transforms[i] = Transforms[i] * Offsets[i]; } ]]) -- Create the display shader, injecting the shader code for the block shader = lovr.graphics.newShader([[ buffer TransformBuffer { mat4 Transforms[]; }; vec4 lovrmain() { return Projection * View * Transforms[InstanceIndex] * Transform * VertexPosition; } ]], 'normal') model = lovr.graphics.newModel('monkey.obj') end -- Draw many copies of the model using instancing, with transforms from a buffer function lovr.draw(pass) pass:setShader(computeShader) pass:send('monkeyCount', MONKEYS) pass:send('TransformBuffer', transformBuffer) pass:send('OffsetBuffer', offsetBuffer) pass:compute(math.ceil(MONKEYS / 32)) pass:setShader(shader) pass:send('TransformBuffer', transformBuffer) pass:setCullMode('back') pass:setBlendMode(nil) pass:draw(model, mat4(), MONKEYS) end