Skip to content

Instantly share code, notes, and snippets.

@jmiskovic
Created December 21, 2022 16:55
Show Gist options
  • Save jmiskovic/aaa905da484ab6a770d1fa518651ff18 to your computer and use it in GitHub Desktop.
Save jmiskovic/aaa905da484ab6a770d1fa518651ff18 to your computer and use it in GitHub Desktop.
directional shadow mapping in lovr
local light_pose = lovr.math.newMat4()
local light_view = lovr.math.newMat4()
local light_projection = lovr.math.newMat4():perspective(math.rad(120), 1, 0.01)
--light_projection:orthographic(-5, 5, -5, 5, 100, -100) -- why is near and far inverted? ¯\_(ツ)_/¯
local depthBufferSize = 1024
local depthtex = lovr.graphics.newTexture(depthBufferSize, depthBufferSize, {format = 'd32f', mipmaps = false, usage = {'render', 'sample'}})
local shadowmapper = lovr.graphics.newShader(
[[
layout( push_constant ) uniform constants {
mat4 LightSpaceMatrix;
} PushConstants;
layout(location = 1) out vec4 PositionLight;
vec4 lovrmain() {
PositionLight = PushConstants.LightSpaceMatrix * Transform * vec4(VertexPosition.xyz, 1.f);
return DefaultPosition;
}
]],[[
layout(set = 2, binding = 0) uniform texture2D DepthBuffer;
layout(location = 1) in vec4 PositionLight; // fragment position inside the light-space
vec4 lovrmain() {
vec2 projCoords = PositionLight.xy / PositionLight.w * 0.5 + 0.5;
float closestDepth;
if ((projCoords.x > 0.) && (projCoords.x < 1.) &&
(projCoords.y > 0.) && (projCoords.y < 1.))
closestDepth = getPixel(DepthBuffer, projCoords).r;
else
closestDepth = 0.;
float currentDepth = PositionLight.z / PositionLight.w;
float currentDepth_biased = currentDepth + 0.00003;
float shadow = (currentDepth_biased < 0. || closestDepth < currentDepth_biased) ? 1.0 : 0.3;
vec4 color = DefaultColor;
return color * vec4(vec3(shadow), 1.0);
}
]])
function drawScene(pass, depthFromLight)
local t = lovr.timer.getTime()
pass:setColor(0xf2b63d) -- rotating fan
pass:box(mat4(0, 1.75, -4):rotate(t, 0,1,0):rotate(math.pi / 3 * 0, 0,1,0):rotate(math.rad(10), 1,0,0):scale(1, 0.05, 0.15))
pass:box(mat4(0, 1.75, -4):rotate(t, 0,1,0):rotate(math.pi / 3 * 1, 0,1,0):rotate(math.rad(10), 1,0,0):scale(1, 0.05, 0.15))
pass:box(mat4(0, 1.75, -4):rotate(t, 0,1,0):rotate(math.pi / 3 * 2, 0,1,0):rotate(math.rad(10), 1,0,0):scale(1, 0.05, 0.15))
pass:setColor(0x8fcccb) -- a vertical box
lovr.math.setRandomSeed(1)
for _ = 1, 20 do -- some boxy columns
local height = lovr.math.randomNormal(0.2, 1)
local shade = 0.3 + 0.4 * lovr.math.random()
pass:setColor(shade, shade, shade)
pass:box(
lovr.math.randomNormal(5, 0),
height / 2,
lovr.math.randomNormal(5, -4),
0.3, height, 0.3)
end
pass:setColor(0xd46e33) -- the floor
pass:box(0, 0, 0, 50, 0.2, 50)
end
function lovr.update(dt)
local t = lovr.timer.getTime() / 8
light_pose:target(
vec3(1, 2.5, -4):add(2 * math.sin(t), 0, math.cos(t)),
vec3(0, 0, -4))
light_view:set(light_pose):invert()
-- render to depth buffer from light perspective
local pass = lovr.graphics.getPass('render', {depth = {texture=depthtex}, samples = 1})
pass:setCullMode('front')
pass:setProjection(1, light_projection)
pass:setViewPose(1, light_pose)
drawScene(pass)
lovr.graphics.submit(pass)
end
function lovr.draw(pass)
--[[ debug-output of depth buffer texture
local w, h = lovr.system.getWindowDimensions()
local size = h / 4
pass:setViewport(0, 0, size, size)
pass:fill(depthtex)
pass:setViewport(0, 0, w, h)
--]]
pass:setCullMode('back')
pass:setColor(0xfff4e0)
pass:cone(mat4(light_pose):rotate(math.pi, 0,1,0):scale(0.07)) -- light position
pass:setShader(shadowmapper)
local light_space_matrix = light_projection * light_view
pass:send('LightSpaceMatrix', light_space_matrix)
pass:send('DepthBuffer', depthtex)
drawScene(pass)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment