directionalLight.lua 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. local m = {}
  2. m.view = Mat4()
  3. m.projection = Mat4()
  4. m.lightMatrix = Mat4()
  5. m.direction = Vec3()
  6. local vS = "/directionalLight/glsl/dirLightVert.glsl"
  7. local fS = "/directionalLight/glsl/dirLightFrag.glsl"
  8. local shadowmapper = lovr.graphics.newShader(vS,fS)
  9. function m.load(resolution)
  10. m.resolution = resolution or 1024
  11. m.texture = lovr.graphics.newTexture(m.resolution, m.resolution, { format = 'd32f' })
  12. m.pass = lovr.graphics.newPass({ depth = m.texture, samples = 1 })
  13. m.sampler = lovr.graphics.newSampler({ wrap = 'clamp', compare = 'gequal' })
  14. end
  15. function m.getPass()
  16. -- render to depth buffer from light perspective
  17. m.pass:setClear({ depth = 1 })
  18. m.pass:reset()
  19. m.pass:setCullMode('front')
  20. m.pass:setDepthTest('lequal')
  21. m.pass:setProjection(1, m.projection)
  22. m.pass:setViewPose(1, m.view, true)
  23. return m.pass
  24. end
  25. function m.setShader(pass)
  26. pass:setShader(shadowmapper)
  27. pass:send('LightSpaceMatrix', m.lightMatrix)
  28. pass:send('shadowSampler', m.sampler)
  29. pass:send('LightDirection', m.direction)
  30. pass:send('DepthBuffer', m.texture)
  31. end
  32. function m.debugDraw(pass)
  33. if lovr.system.isKeyDown('`') then
  34. pass:push('state')
  35. pass:setShader()
  36. pass:setDepthTest()
  37. pass:setColor(1, 1, 1)
  38. pass:fill(m.texture)
  39. pass:pop('state')
  40. end
  41. end
  42. function m.setLightMatrix(lightDirection, cameraView, cameraProjection)
  43. m.direction:set(lightDirection):normalize()
  44. -- Get the 8 points of the camera's frustum in NDC space
  45. m.points = {
  46. vec3(-1, -1, 0),
  47. vec3( 1, -1, 0),
  48. vec3(-1, 1, 0),
  49. vec3( 1, 1, 0),
  50. vec3(-1, -1, 1),
  51. vec3( 1, -1, 1),
  52. vec3(-1, 1, 1),
  53. vec3( 1, 1, 1)
  54. }
  55. local viewProjection = cameraProjection * cameraView
  56. local worldFromClip = mat4(viewProjection):invert()
  57. -- Convert the NDC points to world space frustum vertices
  58. for i, point in ipairs(m.points) do
  59. point:transform(worldFromClip)
  60. end
  61. -- Get the center of the frustum
  62. local frustumCenter = vec3()
  63. for i, point in ipairs(m.points) do
  64. frustumCenter:add(point)
  65. end
  66. frustumCenter:mul(1 / #m.points)
  67. -- Make a temp lookAt matrix that can be used to rotate points into the light's coordinate space
  68. local tempMatrix = mat4():lookAt(frustumCenter, frustumCenter + m.direction)
  69. -- Convert all the points into light space
  70. for i, point in ipairs(m.points) do
  71. point:transform(tempMatrix)
  72. end
  73. -- Find AABB around camera corners, from light's perspective
  74. local minx, miny, minz = math.huge, math.huge, math.huge
  75. local maxx, maxy, maxz = -math.huge, -math.huge, -math.huge
  76. for i = 1, #m.points do
  77. local x, y, z = m.points[i]:unpack()
  78. minx, miny, minz = math.min(minx, x), math.min(miny, y), math.min(minz, z)
  79. maxx, maxy, maxz = math.max(maxx, x), math.max(maxy, y), math.max(maxz, z)
  80. end
  81. local lightPosition = frustumCenter
  82. m.view:lookAt(frustumCenter, frustumCenter + m.direction)
  83. m.projection:orthographic(minx, maxx, maxy, miny, -maxz, -minz)
  84. m.lightMatrix:set(m.projection * m.view)
  85. end
  86. return m