main.lua 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. -- Surround yourself with monkeys and efficiently move them with compute shaders
  2. ASSUME_FRAMERATE = 1/120
  3. function lovr.load()
  4. MONKEYS = 500
  5. if not lovr.graphics.getFeatures().compute then
  6. error("This example requires compute shaders to run, but compute shaders are not supported on this machine.")
  7. end
  8. -- Create a ShaderBlock to store positions for lots of models
  9. block = lovr.graphics.newShaderBlock('compute', {
  10. modelTransforms = { 'mat4', MONKEYS },
  11. modelTransformsPerFrame = { 'mat4', MONKEYS }
  12. }, { usage = 'dynamic' }) -- "Dynamic" means "compute shaders can write to this"
  13. -- Write some random transforms to the block
  14. local random, randomNormal = lovr.math.random, lovr.math.randomNormal
  15. do
  16. local transforms = {}
  17. for i = 1, MONKEYS do
  18. local position = vec3(randomNormal(8), randomNormal(8), randomNormal(8))
  19. local orientation = quat(random(2 * math.pi), random(), random(), random())
  20. local scale = vec3(.75)
  21. transforms[i] = mat4(position, scale, orientation)
  22. end
  23. block:send('modelTransforms', transforms)
  24. end
  25. -- More random transforms-- this will correspond to the transform applied to each monkey per frame
  26. do
  27. local transforms = {}
  28. for i = 1, MONKEYS do
  29. local position = vec3(randomNormal(1), randomNormal(8), randomNormal(8)):mul(ASSUME_FRAMERATE)
  30. local radianSwing = ASSUME_FRAMERATE * math.pi / 2
  31. local orientation = quat(random(-radianSwing, radianSwing), random(), random(), random())
  32. local scale = vec3(1)
  33. transforms[i] = mat4(position, scale, orientation)
  34. end
  35. block:send('modelTransformsPerFrame', transforms)
  36. end
  37. -- Create the compute shader, we will run this once per frame
  38. computeShader = lovr.graphics.newComputeShader(
  39. string.format(block:getShaderCode('ModelBlock') .. [[
  40. #define MONKEYS %d
  41. layout(local_size_x = MONKEYS, local_size_y = 1, local_size_z = 1) in;
  42. void compute() {
  43. uint i = gl_LocalInvocationID.x;
  44. modelTransforms[i] = modelTransforms[i] * modelTransformsPerFrame[i];
  45. }
  46. ]], MONKEYS)
  47. )
  48. computeShader:sendBlock('ModelBlock', block)
  49. -- Create the display shader, injecting the shader code for the block
  50. shader = lovr.graphics.newShader(
  51. block:getShaderCode('ModelBlock') .. [[
  52. out vec3 vNormal;
  53. vec4 position(mat4 projection, mat4 transform, vec4 vertex) {
  54. vNormal = lovrNormal;
  55. return projection * transform * modelTransforms[lovrInstanceID] * vertex;
  56. }
  57. ]], [[
  58. in vec3 vNormal;
  59. vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) {
  60. return vec4(vNormal * .5 + .5, 1.);
  61. }
  62. ]])
  63. -- Bind the block to the shader
  64. shader:sendBlock('ModelBlock', block)
  65. model = lovr.graphics.newModel('monkey.obj')
  66. lovr.graphics.setCullingEnabled(true)
  67. lovr.graphics.setBlendMode(nil)
  68. end
  69. function lovr.update()
  70. lovr.graphics.compute(computeShader,1,1,1)
  71. end
  72. -- Draw many copies of the model using instancing, with transforms from the shader block
  73. function lovr.draw()
  74. lovr.graphics.setShader(shader)
  75. model:draw(mat4(), MONKEYS)
  76. lovr.graphics.setShader()
  77. end