Work on static lighting code

This commit is contained in:
James Lambert 2023-06-05 21:11:06 -06:00
parent 57e4544fee
commit 0e2a45665d
4 changed files with 249 additions and 4 deletions

View file

@ -325,6 +325,13 @@ function Box3.lerp(box, lerp)
return Vector3.lerp(box.min, box.max, lerp)
end
--- Finds a lerp value, x, such that box:lerp(x) == pos
--- @function pos
--- @treturn Vector3
function Box3.unlerp(box, pos)
return (pos - box.min) / (box.max - box.min)
end
--- Linearly interpolates between the min and max of the box
--- @function union
@ -436,6 +443,102 @@ local function isColor4(obj)
return type(obj) == 'table' and type(obj.r) == 'number' and type(obj.g) == 'number' and type(obj.b) == 'number' and type(obj.a) == 'number'
end
--- @type Color4
--- @tfield number r
--- @tfield number g
--- @tfield number b
--- @tfield number a
Color4.__index = Color4;
--- @function __eq
--- @tparam number|Color4 b
--- @treturn Color4
function Color4.__eq(a, b)
if (type(a) == 'number') then
return a == b.r and a == b.g and a == b.b and a == b.a
end
if (type(b) == 'number') then
return a.r == b and a.g == b and a.b + b and a.a == b
end
if (not isColor4(b)) then
error('Color4.__eq expected another vector as second operand', 2)
end
return a.r == b.r and a.g == b.g and a.b == b.b and a.a == a.a
end
--- @function __add
--- @tparam number|Color4 b
--- @treturn Color4
function Color4.__add(a, b)
if (type(a) == 'number') then
return color4(a + b.r, a + b.g, a + b.b, a + b.a)
end
if (type(b) == 'number') then
return color4(a.r + b, a.g + b, a.b + b, a.a + b)
end
if (not isColor4(b)) then
error('Color4.__add expected another vector as second operand got ' .. type(b), 2)
end
return color4(a.r + b.r, a.g + b.g, a.b + b.b, a.a + b.a)
end
--- @function __sub
--- @tparam number|Color4 b
--- @treturn Color4
function Color4.__sub(a, b)
if (type(a) == 'number') then
return color4(a - b.r, a - b.g, a - b.b, a - b.a)
end
if (type(b) == 'number') then
return color4(a.r - b, a.g - b, a.b - b, a.a - b)
end
if (not isColor4(b)) then
error('Color4.__sub expected another vector as second operand', 2)
end
if (a == nil) then
print(debug.traceback())
end
return color4(a.r - b.r, a.g - b.g, a.b - b.b, a.a - b.a)
end
--- @function __mul
--- @tparam number|Color4 b
--- @treturn Color4
function Color4.__mul(a, b)
if (type(a) == 'number') then
return color4(a * b.r, a * b.g, a * b.b, a * b.a)
end
if (type(b) == 'number') then
return color4(a.r * b, a.g * b, a.b * b, a.a * b)
end
if (not isColor4(b)) then
error('Color4.__mul expected another vector or number as second operand got ' .. type(b), 2)
end
return color4(a.r * b.r, a.g * b.g, a.b * b.b, a.a * b.a)
end
--- Linearly interpolates between two points
--- @function lerp
--- @tparam Color4 b
--- @treturn Color4
function Color4.lerp(a, b, lerp)
return a * (1 - lerp) + b * lerp
end
return {
vector3 = vector3,
Vector3 = Vector3,

View file

@ -219,10 +219,17 @@ void meshToLua(lua_State* L, std::shared_ptr<ExtendedMesh> mesh) {
toLua(L, mesh->mMesh->mFaces, mesh->mMesh->mNumFaces);
lua_setfield(L, -2, "faces");
if (mesh->mMesh->mColors[0]) {
toLuaLazyArray<aiColor4D>(L, mesh->mMesh->mColors[0], mesh->mMesh->mNumVertices);
} else {
lua_pushnil(L);
lua_createtable(L, AI_MAX_NUMBER_OF_COLOR_SETS, 0);
for (int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
if (!mesh->mMesh->mColors[i]) {
mesh->mMesh->mColors[i] = new aiColor4D[mesh->mMesh->mNumVertices];
for (unsigned vertexIndex = 0; vertexIndex < mesh->mMesh->mNumVertices; ++vertexIndex) {
mesh->mMesh->mColors[i][vertexIndex] = aiColor4D(1.0, 1.0, 1.0, 1.0);
}
}
toLuaLazyArray<aiColor4D>(L, mesh->mMesh->mColors[i], mesh->mMesh->mNumVertices);
lua_seti(L, -2, i + 1);
}
lua_setfield(L, -2, "colors");

View file

@ -10,6 +10,7 @@ local entities = require('tools.level_scripts.entities')
local signals = require('tools.level_scripts.signals')
local animation = require('tools.level_scripts.animation')
local dynamic_collision = require('tools.level_scripts.dynamic_collision_export')
local static_lighting = require('tools.level_scripts.static_lighting')
sk_definition_writer.add_definition("level", "struct LevelDefinition", "_geo", {
collisionQuads = sk_definition_writer.reference_to(collision_export.collision_objects, 1),

View file

@ -0,0 +1,134 @@
local sk_scene = require('sk_scene')
local sk_math = require('sk_math');
local ambient_nodes = sk_scene.nodes_for_type('@ambient')
local ambient_blocks = {}
local function build_ambient_block(ambient_mesh)
local midpoint = sk_math.vector3(0, 0, 0)
local min = ambient_mesh.vertices[1]
local max = ambient_mesh.vertices[1]
for _, vector in pairs(ambient_mesh.vertices) do
midpoint = midpoint + vector
min = min:min(vector)
max = max:max(vector)
end
midpoint = midpoint * (1 / #ambient_mesh.vertices)
local colors = {}
for index, vector in pairs(ambient_mesh.vertices) do
local corner_index = 1
if (vector.x > midpoint.x) then
corner_index = corner_index + 1
end
if (vector.y > midpoint.y) then
corner_index = corner_index + 2
end
if (vector.z > midpoint.z) then
corner_index = corner_index + 4
end
colors[corner_index] = ambient_mesh.colors[1] and ambient_mesh.colors[1][index]
end
return {
bb = sk_math.box3(min, max),
colors = colors,
}
end
local function evaluate_ambient_block(block, pos, normal)
local lerp_values = block.bb:unlerp(pos)
local x0 = block.colors[1]:lerp(block.colors[2], lerp_values.x)
local x1 = block.colors[3]:lerp(block.colors[4], lerp_values.x)
local x2 = block.colors[5]:lerp(block.colors[6], lerp_values.x)
local x3 = block.colors[7]:lerp(block.colors[8], lerp_values.x)
local y0 = x0:lerp(x1, lerp_values.y)
local y1 = x2:lerp(x3, lerp_values.y)
return y0:lerp(y1, lerp_values.z)
end
for index, ambient_node in pairs(ambient_nodes) do
for _, mesh in pairs(ambient_node.node.meshes) do
local global_mesh = mesh:transform(ambient_node.node.full_transformation)
table.insert(ambient_blocks, build_ambient_block(global_mesh))
end
end
local function find_nearest_ambient_boxes(pos, max_count)
local boxes = {};
local distances = {};
for _, ambient_block in pairs(ambient_blocks) do
local distance = ambient_block.bb:distance_to_point(pos)
-- if inside a block just return it
if distance <= 0 then
return {ambient_block}, {1}
end
local insert_index = #boxes + 1
for index, other_distance in pairs(distances) do
if distance < other_distance then
insert_index = index
end
end
if insert_index < max_count then
table.insert(boxes, insert_index, ambient_block)
table.insert(distances, insert_index, distance)
if #boxes > max_count then
table.remove(boxes)
table.remove(distances)
end
end
end
local weights = {}
local total_weight = 0
for index, distance in pairs(distances) do
total_weight = total_weight + distance
weights[index] = distance
end
for index, _ in pairs(weights) do
weights[index] = 1 - weights[index] / total_weight
end
return boxes, weights
end
local function light_vertex(pos, normal)
local boxes, weights = find_nearest_ambient_boxes(pos, 2)
if #boxes == 0 then
return sk_math.color4(1, 1, 1, 1)
end
local result = sk_math.color4(0, 0, 0, 0)
for index, block in pairs(boxes) do
result = result + evaluate_ambient_block(block, pos, normal) * weights[index]
end
return result
end
return {
light_vertex = light_vertex,
}