From 844f5d32f37877bf65e72bcfb994d39b713a7317 Mon Sep 17 00:00:00 2001 From: skal Date: Mon, 2 Feb 2026 13:54:23 +0100 Subject: feat(3d): Support non-uniform scale and shadows on rasterized objects - Implemented full support for non-uniform scaling by calculating and passing the 'model_inverse_transpose' matrix to the shader for correct normal transformation. - Added 'transpose()' and 'inverse()' methods to the 'mat4' class in 'mini_math.h'. - Refactored the shader to use the new matrix for lighting rasterized objects. - Updated the test scene to use a rasterized floor (CUBE) instead of an SDF one, ensuring it receives correct lighting and shadows even with non-uniform scale. --- src/3d/renderer.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/3d/renderer.cc') diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc index 267c165..b655588 100644 --- a/src/3d/renderer.cc +++ b/src/3d/renderer.cc @@ -20,6 +20,7 @@ struct GlobalUniforms { struct ObjectData { model: mat4x4, + model_inv_tr: mat4x4, color: vec4, params: vec4, }; @@ -152,13 +153,13 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { var normal: vec3; let light_dir = normalize(vec3(1.0, 1.0, 1.0)); - if (obj_type == 0.0) { // Rasterized object (like the floor) + if (obj_type == 0.0) { // Rasterized object p = in.world_pos; let local_normal = normalize(cross(dpdx(in.local_pos), dpdy(in.local_pos))); - // Simplified normal transform (incorrect for non-uniform scale, but works for axis-aligned floor) - let model_mat3 = mat3x3(obj.model[0].xyz, obj.model[1].xyz, obj.model[2].xyz); - normal = normalize(model_mat3 * local_normal); + // Correct normal transformation using inverse transpose + let mat3_it = mat3x3(obj.model_inv_tr[0].xyz, obj.model_inv_tr[1].xyz, obj.model_inv_tr[2].xyz); + normal = normalize(mat3_it * local_normal); } else { // SDF object let center = vec3(obj.model[3].x, obj.model[3].y, obj.model[3].z); let scale = length(vec3(obj.model[0].x, obj.model[0].y, obj.model[0].z)); @@ -420,6 +421,11 @@ void Renderer3D::update_uniforms(const Scene& scene, const Camera& camera, for (const auto& obj : scene.objects) { ObjectData data; data.model = obj.get_model_matrix(); + + // Calculate Inverse Transpose for correct normal transformation + mat4 inverse = data.model.inverse(); + data.model_inverse_transpose = mat4::transpose(inverse); + data.color = obj.color; float type_id = 0.0f; if (obj.type == ObjectType::SPHERE) -- cgit v1.2.3