Skip to content

Instantly share code, notes, and snippets.

@jmiskovic
Last active March 10, 2023 21:12
Show Gist options
  • Save jmiskovic/cf2713b6b476f2c49f10e701ae3fe545 to your computer and use it in GitHub Desktop.
Save jmiskovic/cf2713b6b476f2c49f10e701ae3fe545 to your computer and use it in GitHub Desktop.
A testbed for light probe generation from a dynamically rendered skybox
local skybox = {} -- from https://github.com/jmiskovic/lovr-atmo
skybox.__index = skybox
function skybox.new(resolution)
local self = setmetatable({}, skybox)
self.resolution = math.floor(resolution or 256)
assert(self.resolution > 0 and self.resolution < 6000)
self.cubetex = lovr.graphics.newTexture(
self.resolution, self.resolution, 6,
{type='cube', mipmaps=false, usage = {'render', 'sample', 'transfer'}})
self.horizon_color = lovr.math.newVec3()
return self
end
function skybox:bake(drawfn)
-- render scene to cubemap texture
local render_pass = lovr.graphics.getPass('render', {self.cubetex, samples=1, mipmap=false})
local projection = mat4():perspective(math.pi / 2, 1, 0, 0)
local transforms = {
mat4():lookAt(vec3(), vec3( 1, 0, 0), vec3(0, 1, 0)),
mat4():lookAt(vec3(), vec3(-1, 0, 0), vec3(0, 1, 0)),
mat4():lookAt(vec3(), vec3( 0, 1, 0), vec3(0, 0,-1)),
mat4():lookAt(vec3(), vec3( 0,-1, 0), vec3(0, 0, 1)),
mat4():lookAt(vec3(), vec3( 0, 0, 1), vec3(0, 1, 0)),
mat4():lookAt(vec3(), vec3( 0, 0,-1), vec3(0, 1, 0))
}
for i, transform in ipairs(transforms) do
render_pass:setProjection(i, projection)
render_pass:setViewPose(i, transform)
end
drawfn(render_pass)
-- read back the horizon color
local transfer_pass = lovr.graphics.getPass('transfer')
local readbacks = {
transfer_pass:read(self.cubetex, 0, 0, 1, 1, self.resolution, self.resolution),
transfer_pass:read(self.cubetex, 0, 0, 2, 1, self.resolution, self.resolution),
transfer_pass:read(self.cubetex, 0, 0, 3, 1, self.resolution, self.resolution),
transfer_pass:read(self.cubetex, 0, 0, 4, 1, self.resolution, self.resolution),
transfer_pass:read(self.cubetex, 0, 0, 5, 1, self.resolution, self.resolution),
transfer_pass:read(self.cubetex, 0, 0, 6, 1, self.resolution, self.resolution)
}
lovr.graphics.submit(render_pass, transfer_pass)
self.images = {}
for i, readback in ipairs(readbacks) do
readback:wait()
self.images[i] = readback:getImage()
--lovr.filesystem.write('img'..i..'.png', self.images[i]:encode())
end
end
function skybox:draw(pass)
pass:setColor(1,1,1)
pass:skybox(self.cubetex)
end
--------------------------------------
local box = skybox.new(64)
probeShader = lovr.graphics.newShader('unlit', [[
layout(set = 2, binding = 0, std140) uniform LightProbe { vec3 lightProbe[9]; };
vec3 evaluateLightProbe(vec3 probe[9], vec3 dir) {
return
.88622692545276 * probe[0] +
1.0233267079465 * probe[1] * dir.y +
1.0233267079465 * probe[2] * dir.z +
1.0233267079465 * probe[3] * dir.x +
.85808553080978 * probe[4] * dir.x * dir.y +
.85808553080978 * probe[5] * dir.y * dir.z +
.24770795610038 * probe[6] * (3. * dir.z * dir.z - 1.) +
.85808553080978 * probe[7] * dir.x * dir.z +
.42904276540489 * probe[8] * (dir.x * dir.x - dir.y * dir.y)
;
}
vec4 lovrmain() {
vec3 lpc = evaluateLightProbe(lightProbe, normalize(Normal));
float bias = 0;
float scl = 1;
lpc = (lpc - bias) * scl + bias;
return vec4(lpc, 1.);
}
]])
probe = lovr.math.newLightProbe()
light_pos = lovr.math.newVec3(0, 10, 0)
function drawLight(pass)
local t = lovr.timer.getTime() * 0.2
pass:setColor(1,1,1)
pass:sphere(light_pos, 2)
end
function lovr.update(dt)
if lovr.headset.isDown('left', 'trigger') then
local v = vec3(quat(lovr.headset.getOrientation('left')):direction()):mul(5)
light_pos:lerp(v, dt)
end
local t = lovr.timer.getTime()
if lovr.system.isKeyDown('1') then
light_pos:lerp(0, 1, 0, dt * 4):normalize():mul(5)
elseif lovr.system.isKeyDown('2') then
light_pos:lerp(1, 0, 0, dt * 4):normalize():mul(5)
elseif lovr.system.isKeyDown('3') then
light_pos:lerp(0, -1, 0, dt * 4):normalize():mul(5)
end
box:bake(drawLight)
probe = lovr.math.newLightProbe(box.images)
probe:scale(1 / math.pi)
end
function lovr.draw(pass)
pass:skybox(box.cubetex)
pass:setColor(0.2, 0.2, 0.2)
pass:setColor(1,1,1)
pass:setShader(probeShader)
pass:send('LightProbe', lovr.graphics.getBuffer(probe:getCoefficients(), {'vec3s', layout='std140'}))
pass:monkey(mat4(0, 0, -1):scale(0.3))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment