main.lua 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. -- This demo renders a scene into a cubemap, then displays the rendered screen reflected on a sphere surface within the screen.
  2. --
  3. -- Sample contributed by andi mcc with help from holo
  4. -- First a simple scene, a checkerboard floor and some floating cubes
  5. -- Want to see how the cubemap is done? Skip this whole section
  6. local scene = {}
  7. function scene.load()
  8. scene.floorSize = 6
  9. scene.cubeCount = 60
  10. scene.boundMin = lovr.math.newVec3(-10, -1, -10)
  11. scene.boundMax = lovr.math.newVec3(10, 9, 10)
  12. scene.speed = 1
  13. scene.rotateSpeed = 1
  14. scene.cubeSize = 0.2
  15. scene.cubes = {}
  16. scene.sphereCenter = lovr.math.newVec3(0, 1.5, -0.5)
  17. scene.sphereRad = 0.125
  18. for i=1,scene.cubeCount do
  19. scene.generate(i, true)
  20. end
  21. end
  22. local function randomQuaternion()
  23. -- Formula from http://planning.cs.uiuc.edu/node198.html
  24. local u,v,w = math.random(), math.random(), math.random()
  25. return lovr.math.newQuat( math.sqrt(1-u)*math.sin(2*v*math.pi),
  26. math.sqrt(1-u)*math.cos(2*v*math.pi),
  27. math.sqrt(u)*math.sin(2*w*math.pi),
  28. math.sqrt(u)*math.cos(2*w*math.pi),
  29. true ) -- Raw components
  30. end
  31. function scene.generate(i, randomZ) -- Generate each cube with random position and color and a random rotational velocity
  32. local cube = {}
  33. cube.at = lovr.math.newVec3()
  34. cube.at.x = scene.boundMin.x + math.random()*(scene.boundMax.x-scene.boundMin.x)
  35. cube.at.y = scene.boundMin.y + math.random()*(scene.boundMax.y-scene.boundMin.y)
  36. if randomZ then
  37. cube.at.z = scene.boundMin.z + math.random()*(scene.boundMax.z-scene.boundMin.z)
  38. else
  39. cube.at.z = scene.boundMin.z
  40. end
  41. cube.rotateBasis = randomQuaternion()
  42. cube.rotateTarget = lovr.math.newQuat(cube.rotateBasis:conjugate())
  43. cube.rotate = cube.rotateBasis
  44. cube.color = {math.random()*0.8, math.random()*0.8, math.random()*0.8}
  45. scene.cubes[i] = cube
  46. end
  47. function scene.update(dt) -- On each frame, move each cube and spin it a little
  48. for i,cube in ipairs(scene.cubes) do
  49. cube.at.z = cube.at.z + scene.speed*dt
  50. if cube.at.z > scene.boundMax.z then -- If cube left the scene bounds respawn it
  51. scene.generate(i)
  52. else
  53. local rotateAmount = (cube.at.z - scene.boundMin.z)/(scene.boundMax.z-scene.boundMin.z)
  54. cube.rotate = cube.rotateBasis:slerp( cube.rotateTarget, rotateAmount )
  55. end
  56. end
  57. end
  58. function scene.draw(pass)
  59. -- First, draw a floor
  60. local floorRecenter = scene.floorSize/2 + 0.5
  61. for x=1,scene.floorSize do for y=1,scene.floorSize do
  62. if (x+y)%2==0 then
  63. pass:setColor(0.25,0.25,0.25)
  64. else
  65. pass:setColor(0.5,0.5,0.5)
  66. end
  67. pass:plane(x-floorRecenter,0,y-floorRecenter, 1,1, math.pi/2,1,0,0)
  68. end end
  69. -- Draw cubes
  70. for _,cube in ipairs(scene.cubes) do
  71. pass:setColor(unpack(cube.color))
  72. pass:cube(cube.at.x, cube.at.y, cube.at.z, scene.cubeSize, cube.rotate:unpack())
  73. end
  74. end
  75. -- Now the cubemap stuff
  76. local cubemap = {}
  77. local unitX = lovr.math.newVec3(1,0,0)
  78. local unitY = lovr.math.newVec3(0,1,0)
  79. local unitZ = lovr.math.newVec3(0,0,1)
  80. function cubemap.load()
  81. -- Create cubemap textures
  82. local cubemapWidth, cubemapHeight = 256, 256
  83. cubemap.texture = lovr.graphics.newTexture(cubemapWidth, cubemapHeight, 6, { type = "cube" })
  84. cubemap.faces = {}
  85. -- Precalculate cubemap View-Projection matrices
  86. local center = scene.sphereCenter
  87. cubemap.facePerspective = lovr.math.newMat4():perspective(math.rad(90.0), 1, .1, 0)
  88. for i,matrix in ipairs{
  89. -- Not sure why the x flip is needed!
  90. lovr.math.mat4():lookAt(center, center - unitX, vec3(0, 1, 0)),
  91. lovr.math.mat4():lookAt(center, center + unitX, vec3(0, 1, 0)),
  92. lovr.math.mat4():lookAt(center, center + unitY, vec3(0, 0, -1)),
  93. lovr.math.mat4():lookAt(center, center - unitY, vec3(0, 0, 1)),
  94. lovr.math.mat4():lookAt(center, center + unitZ, vec3(0, 1, 0)),
  95. lovr.math.mat4():lookAt(center, center - unitZ, vec3(0, 1, 0))
  96. } do
  97. -- Each face will contain a matrix
  98. local face = {}
  99. face.matrix = lovr.math.newMat4(matrix)
  100. cubemap.faces[i] = face
  101. end
  102. -- Create reflection shader
  103. cubemap.shader = lovr.graphics.newShader('unlit', [[
  104. uniform textureCube cubemap;
  105. vec4 lovrmain() {
  106. vec3 V = normalize(CameraPositionWorld - PositionWorld);
  107. vec3 N = normalize(Normal);
  108. vec3 R = reflect(-V, N);
  109. vec4 sphereColor = Color * getPixel(cubemap, R * vec3(-1, 1, 1));
  110. float ndi = dot(N, V) * 0.5 + 0.5; // Darken the sphere a little around the edges to give it apparent depth
  111. return vec4(sphereColor.rgb * ndi, 1.);
  112. }
  113. ]])
  114. -- Set up a render pass that renders to the cubemap
  115. cubemap.pass = lovr.graphics.newPass(cubemap.texture)
  116. cubemap.pass:setClear(lovr.graphics.getBackgroundColor())
  117. end
  118. function cubemap.draw()
  119. cubemap.pass:reset()
  120. for i = 1, 6 do
  121. cubemap.pass:setProjection(i, cubemap.facePerspective)
  122. cubemap.pass:setViewPose(i,cubemap.faces[i].matrix,true)
  123. end
  124. scene.draw(cubemap.pass)
  125. end
  126. -- Handle lovr
  127. function lovr.load()
  128. lovr.graphics.setBackgroundColor(0.9,0.9,0.9)
  129. scene.load()
  130. cubemap.load()
  131. end
  132. function lovr.update(dt)
  133. scene.update(dt)
  134. end
  135. function lovr.draw(pass)
  136. cubemap.draw()
  137. scene.draw(pass)
  138. -- Draw sphere textured with cube map
  139. pass:setColor(1,0.6,0.6)
  140. pass:setShader(cubemap.shader)
  141. pass:send("cubemap", cubemap.texture)
  142. pass:sphere(scene.sphereCenter.x, scene.sphereCenter.y, scene.sphereCenter.z, scene.sphereRad)
  143. return lovr.graphics.submit(cubemap.pass, pass)
  144. end