main.lua 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. -- This demo renders four examples of mesh drawing:
  2. -- A plain mesh (one triangle, white)
  3. -- A mesh with a vertex map, in other words indexed triangles (a cube, magenta)
  4. -- An instanced mesh with its size controlled by gl_InstanceID and an equation (512 cubes animated, cyan)
  5. -- An instanced mesh with its size controlled by an attached attribute (512 cubes with random sizes, yellow)
  6. --
  7. -- Sample contributed by andi mcc
  8. local fragmentShader = require("shader")
  9. local mesh1, mesh2, mesh4
  10. local mesh4Instance
  11. local mesh1Program, mesh3Program, mesh4Program
  12. local gridSize = 8
  13. local gridSizeCubed = gridSize*gridSize*gridSize
  14. -- This reproduces the simple shader from the Physics example, but in the vertex shader
  15. -- the mesh coordinate is run through a customized function first.
  16. -- Call this function with a string containing a glsl function preTransform()
  17. -- which maps world space coordinates to world space coordinates to construct a shader.
  18. local function makeShader(prefix)
  19. return lovr.graphics.newShader(prefix .. [[
  20. out vec3 lightDirection;
  21. out vec3 normalDirection;
  22. out vec3 vertexPosition;
  23. vec3 lightPosition = vec3(10., 10., 3.);
  24. vec4 position(mat4 projection, mat4 transform, vec4 _vertex) {
  25. vec4 vertex = preTransform(_vertex);
  26. vec4 vVertex = transform * vertex;
  27. vec4 vLight = lovrView * vec4(lightPosition, 1.);
  28. lightDirection = normalize(vec3(vLight - vVertex));
  29. normalDirection = normalize(lovrNormalMatrix * lovrNormal);
  30. vertexPosition = vVertex.xyz;
  31. return projection * transform * vertex;
  32. }
  33. ]], fragmentShader)
  34. end
  35. local animate = 0
  36. function lovr.load()
  37. lovr.graphics.setCullingEnabled(true)
  38. -- This "standard" program is the same as the standard light shader from the other examples-- it does nothing.
  39. mesh1Program = makeShader("vec4 preTransform(vec4 v) { return v; }")
  40. -- This mesh is a single triangle
  41. mesh1 = lovr.graphics.newMesh({{ 'lovrPosition', 'float', 3 }, { 'lovrNormal', 'float', 3 }}, 3, 'triangles')
  42. mesh1:setVertices({{0,0,0, 0,0,1}, {1,0,0, 0,0,1}, {0,1,0, 0,0,1}})
  43. -- This mesh is a cube
  44. mesh2 = lovr.graphics.newMesh({{ 'lovrPosition', 'float', 3 }, { 'lovrNormal', 'float', 3 }}, 24, 'triangles')
  45. local mesh2Vertices = {
  46. {0,0,0, 0,0,-1}, -- Face front
  47. {0,1,0, 0,0,-1},
  48. {1,1,0, 0,0,-1},
  49. {1,0,0, 0,0,-1},
  50. {1,1,0, 0,1,0}, -- Face top
  51. {0,1,0, 0,1,0},
  52. {0,1,1, 0,1,0},
  53. {1,1,1, 0,1,0},
  54. {1,0,0, 1,0,0}, -- Face right
  55. {1,1,0, 1,0,0},
  56. {1,1,1, 1,0,0},
  57. {1,0,1, 1,0,0},
  58. {0,0,0, -1,0,0}, -- Face left
  59. {0,0,1, -1,0,0},
  60. {0,1,1, -1,0,0},
  61. {0,1,0, -1,0,0},
  62. {1,1,1, 0,0,1}, -- Face back
  63. {0,1,1, 0,0,1},
  64. {0,0,1, 0,0,1},
  65. {1,0,1, 0,0,1},
  66. {0,0,0, 0,-1,0}, -- Face bottom
  67. {1,0,0, 0,-1,0},
  68. {1,0,1, 0,-1,0},
  69. {0,0,1, 0,-1,0}
  70. }
  71. -- The cube specified above covers the space 0..1, so it's centered at (0.5, 0.5, 0.5). That's not right.
  72. -- Let's edit the first three coordinates of each vertex to center it at (0,0,0):
  73. for _, v in ipairs(mesh2Vertices) do
  74. for i=1,3 do
  75. v[i] = v[i] - 0.5
  76. end
  77. end
  78. mesh2:setVertices(mesh2Vertices)
  79. -- Indices to draw the faces of the cube out of triangles
  80. local mesh2Indexes = {
  81. 1, 2, 3, 1, 3, 4, -- Face front
  82. 5, 6, 7, 5, 7, 8, -- Face top
  83. 9, 10, 11, 9, 11, 12, -- Face right
  84. 13, 14, 15, 13, 15, 16, -- Face left
  85. 17, 18, 19, 17, 19, 20, -- Face back
  86. 21, 22, 23, 21, 23, 24, -- Face bottom
  87. }
  88. mesh2:setVertexMap(mesh2Indexes)
  89. -- This program draws many "instances" of a single model (in this example, a cube, but it could be anything)
  90. -- but uses the instance ID to recenter the model so that the various copies pack the volume of a cube.
  91. -- The model is resized according to a uniform and a little equation to make them wave nicely.
  92. mesh3Program = makeShader([[
  93. uniform int gridSize;
  94. uniform float animate;
  95. vec4 preTransform(vec4 v) {
  96. int instance = lovrInstanceID;
  97. int x = instance % gridSize;
  98. int y = (instance / gridSize) % gridSize;
  99. int z = (instance / gridSize) / gridSize;
  100. float cubeSize = (sin(float(x + y + z) + animate) + 1.) / 2.;
  101. return v * vec4(cubeSize,cubeSize,cubeSize,1) + vec4(x,y,z,0.) - vec4(gridSize, gridSize, gridSize, 0.)/2.;
  102. }
  103. ]])
  104. mesh3Program:send("gridSize", gridSize)
  105. -- This is exactly like the last program-- many instances of one model, packed into a cube volume.
  106. -- The difference is instead of the size being set by a single uniform, we'll pass in a list of sizes.
  107. -- We only have to pass in the cube mesh once, and it matches a copy of the cube for each size in the list.
  108. mesh4Program = makeShader([[
  109. uniform int gridSize;
  110. in float cubeSize;
  111. vec4 preTransform(vec4 v) {
  112. int instance = lovrInstanceID;
  113. int x = instance % gridSize;
  114. int y = (instance / gridSize) % gridSize;
  115. int z = (instance / gridSize) / gridSize;
  116. return v * vec4(cubeSize,cubeSize,cubeSize,1.) + vec4(x,y,z,0.) - vec4(gridSize, gridSize, gridSize, 0.)/2.;
  117. }
  118. ]])
  119. mesh4Program:send("gridSize", gridSize)
  120. -- Here we make an alternate version of mesh 2 (the cube) with the size list attached.
  121. mesh4 = lovr.graphics.newMesh({}, 24, 'triangles')
  122. mesh4Instance = lovr.graphics.newMesh({{'cubeSize', 'float', 1}}, gridSizeCubed, 'points')
  123. local mesh4Vertices = {}
  124. for i=1,gridSizeCubed do -- Hmm, what sizes should we use?
  125. table.insert(mesh4Vertices, {math.random()}) -- Let's just make them random.
  126. end
  127. mesh4Instance:setVertices(mesh4Vertices)
  128. mesh4:setVertexMap(mesh2Indexes)
  129. mesh4:attachAttributes(mesh2)
  130. mesh4:attachAttributes(mesh4Instance, 1)
  131. end
  132. function lovr.update(dt)
  133. animate = animate + dt/math.pi*2
  134. end
  135. function lovr.draw(eye)
  136. lovr.graphics.setShader(mesh1Program)
  137. lovr.graphics.push() -- White triangle
  138. lovr.graphics.setColor(1,1,1)
  139. lovr.graphics.translate(0, 0, -2)
  140. mesh1:draw(0,0,0)
  141. lovr.graphics.pop()
  142. lovr.graphics.push() -- Magenta cube
  143. lovr.graphics.setColor(1,0,1)
  144. lovr.graphics.rotate(1 * math.pi/2, 0, 1, 0)
  145. lovr.graphics.translate(0, 0, -2)
  146. mesh2:draw(0,0,0)
  147. lovr.graphics.pop()
  148. lovr.graphics.setShader(mesh3Program) -- Cyan cubes with size animated by uniform
  149. lovr.graphics.setColor(0,1,1)
  150. lovr.graphics.push()
  151. lovr.graphics.rotate(2 * math.pi/2, 0, 1, 0)
  152. lovr.graphics.translate(0, 0, -2)
  153. lovr.graphics.scale(1/gridSize)
  154. mesh3Program:send("animate", animate)
  155. mesh2:draw(lovr.math.mat4(), gridSizeCubed)
  156. lovr.graphics.pop()
  157. lovr.graphics.setShader(mesh4Program) -- Yellow cubes with size specified by mesh4
  158. lovr.graphics.setColor(1,1,0)
  159. lovr.graphics.push()
  160. lovr.graphics.rotate(3 * math.pi/2, 0, 1, 0)
  161. lovr.graphics.translate(0, 0, -2)
  162. lovr.graphics.scale(1/gridSize)
  163. mesh4:draw(lovr.math.mat4(), gridSizeCubed)
  164. lovr.graphics.pop()
  165. lovr.graphics.setColor(1,1,1)
  166. lovr.graphics.setShader()
  167. end