diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-06 09:53:52 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-06 09:53:52 +0100 |
| commit | a5229022b0e500ac86560e585081f45293e587d2 (patch) | |
| tree | be7794f508748a1380e08c205e80306708a1614f /src/tests | |
| parent | c23f3b9030a508212ffe22d9fa88b7484721174a (diff) | |
fix(shaders): Correct plane distance scaling for non-uniform transforms
When a plane has non-uniform scaling (e.g., floor with scale 20,0.01,20),
transforming points to local space distorts SDF distances. For a horizontal
plane with Y-scale of 0.01, distances become 100x too large in local space.
Fix: Multiply plane distances by the scale factor along the normal direction
(Y component for horizontal planes). This corrects shadow calculations while
maintaining the large floor area needed for visualization.
Reverted incorrect uniform scale fix (c23f3b9) that made floor too small.
Diffstat (limited to 'src/tests')
| -rw-r--r-- | src/tests/test_math_utils.cc | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/tests/test_math_utils.cc b/src/tests/test_math_utils.cc new file mode 100644 index 0000000..26282b2 --- /dev/null +++ b/src/tests/test_math_utils.cc @@ -0,0 +1,184 @@ +// This file is part of the 64k demo project. +// Unit tests for math utilities. + +#include "util/mini_math.h" +#include "util/asset_manager.h" // For AssetId, though not strictly needed for math tests +#include <algorithm> +#include <cmath> +#include <cstdio> +#include <cstring> +#include <fstream> +#include <map> +#include <vector> +#include <cassert> + +// Helper to convert C++ vec3 to WGSL vec3 +inline vec3 to_wgsl_vec3(const vec3& v) { + return vec3(v.x, v.y, v.z); +} + +// --- Math Utilities Tests --- + +void test_vec3_operations() { + printf("Running test: test_vec3_operations +"); + + // Test constructor and basic accessors + vec3 v1(1.0f, 2.0f, 3.0f); + assert(v1.x == 1.0f && v1.y == 2.0f && v1.z == 3.0f); + assert(v1[0] == 1.0f && v1[1] == 2.0f && v1[2] == 3.0f); + + // Test normalization + vec3 v_unnormalized = vec3(3.0f, 4.0f, 0.0f); + vec3 v_normalized = v_unnormalized.normalize(); + assert(std::abs(v_normalized.x - 0.6f) < 1e-5f); + assert(std::abs(v_normalized.y - 0.8f) < 1e-5f); + assert(std::abs(v_normalized.z - 0.0f) < 1e-5f); + assert(std::abs(v_normalized.norm() - 1.0f) < 1e-5f); + + // Test dot product + vec3 v_dot1 = vec3(1.0f, 2.0f, 3.0f); + vec3 v_dot2 = vec3(4.0f, 5.0f, 6.0f); + float dot_product = vec3::dot(v_dot1, v_dot2); // 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32 + assert(std::abs(dot_product - 32.0f) < 1e-5f); + + // Test cross product + vec3 v_cross1 = vec3(1.0f, 0.0f, 0.0f); // i + vec3 v_cross2 = vec3(0.0f, 1.0f, 0.0f); // j + vec3 cross_product = vec3::cross(v_cross1, v_cross2); + assert(std::abs(cross_product.x - 0.0f) < 1e-5f); + assert(std::abs(cross_product.y - 0.0f) < 1e-5f); + assert(std::abs(cross_product.z - 1.0f) < 1e-5f); // k + + // Test element-wise multiplication + vec3 v_scale1 = vec3(2.0f, 3.0f, 4.0f); + vec3 v_scale2 = vec3(5.0f, 2.0f, 1.0f); + vec3 scaled_v = v_scale1 * v_scale2; + assert(std::abs(scaled_v.x - 10.0f) < 1e-5f); + assert(std::abs(scaled_v.y - 6.0f) < 1e-5f); + assert(std::abs(scaled_v.z - 4.0f) < 1e-5f); + + printf("test_vec3_operations passed. +"); +} + +// --- Quaternion Tests --- + +// Dummy function to satisfy potential compiler needs, if not defined elsewhere +// If quat::from_axis is part of a class that's already linked, this might not be needed. +// However, to be safe, I'll assume it might need a declaration. +// If this causes issues, it means quat is not properly available here. +#if !defined(QUAT_FROM_AXIS_DEFINED) +namespace quat_detail { + // Dummy definition if quat is not properly linked/included in this context + struct quat { + vec3 axis; + float angle; + quat(vec3 a, float ang) : axis(a), angle(ang) {} + }; + inline quat from_axis(vec3 a, float ang) { + return quat(a, ang); + } +} +#define QUAT_FROM_AXIS_DEFINED +#endif + +void test_quaternion_operations() { + printf("Running test: test_quaternion_operations +"); + + // Test from_axis and to_mat + vec3 axis_cpp = vec3(0.0f, 1.0f, 0.0f).normalize(); + vec3 wgsl_axis = to_wgsl_vec3(axis_cpp); + quat q = quat::from_axis(wgsl_axis, 1.5708f); // 90 degrees around Y axis + mat4 rot_mat = q.to_mat(); + + // Check if rotation matrix is approximately identity (for 0 rotation) or correct for 90 deg around Y + // A 90 degree rotation around Y should result in: + // [ 0, 0, 1, 0 ] + // [ 0, 1, 0, 0 ] + // [-1, 0, 0, 0 ] + // [ 0, 0, 0, 1 ] + // (Column-major) + assert(std::abs(rot_mat.m[0] - 0.0f) < 1e-5f); + assert(std::abs(rot_mat.m[1] - 0.0f) < 1e-5f); + assert(std::abs(rot_mat.m[2] - -1.0f) < 1e-5f); + assert(std::abs(rot_mat.m[3] - 0.0f) < 1e-5f); + assert(std::abs(rot_mat.m[4] - 0.0f) < 1e-5f); + assert(std::abs(rot_mat.m[5] - 1.0f) < 1e-5f); + assert(std::abs(rot_mat.m[6] - 0.0f) < 1e-5f); + assert(std::abs(rot_mat.m[7] - 0.0f) < 1e-5f); + assert(std::abs(rot_mat.m[8] - 1.0f) < 1e-5f); + assert(std::abs(rot_mat.m[9] - 0.0f) < 1e-5f); + assert(std::abs(rot_mat.m[10] - 0.0f) < 1e-5f); + assert(std::abs(rot_mat.m[11] - 0.0f) < 1e-5f); + + // Test rotating a vector + vec3 test_vec(1.0f, 0.0f, 0.0f); + vec3 rotated_vec = q.rotate(test_vec); + // Expecting rotation around Y axis by 90 degrees should transform (1,0,0) to (0,0,-1) + assert(std::abs(rotated_vec.x - 0.0f) < 1e-5f); + assert(std::abs(rotated_vec.y - 0.0f) < 1e-5f); + assert(std::abs(rotated_vec.z - -1.0f) < 1e-5f); + + printf("test_quaternion_operations passed. +"); +} + +// --- Easing Function Tests --- + +void test_easing_functions() { + printf("Running test: test_easing_functions +"); + assert(std::abs(ease::out_cubic(0.0f) - 0.0f) < 1e-5f); + assert(std::abs(ease::out_cubic(0.5f) - 0.875f) < 1e-5f); + assert(std::abs(ease::out_cubic(1.0f) - 1.0f) < 1e-5f); + + assert(std::abs(ease::in_out_quad(0.0f) - 0.0f) < 1e-5f); + assert(std::abs(ease::in_out_quad(0.5f) - 0.5f) < 1e-5f); + assert(std::abs(ease::in_out_quad(1.0f) - 1.0f) < 1e-5f); + + assert(std::abs(ease::out_expo(0.0f) - 0.0f) < 1e-5f); + assert(std::abs(ease::out_expo(1.0f) - 1.0f) < 1e-5f); + // Check a mid-point for out_expo, e.g., 0.5 should be 1 - 2^(-5) = 1 - 1/32 = 31/32 = 0.96875 + assert(std::abs(ease::out_expo(0.5f) - 0.96875f) < 1e-5f); + + printf("test_easing_functions passed. +"); +} + +// --- Lerp Tests --- + +void test_lerp() { + printf("Running test: test_lerp +"); + vec3 start_vec = vec3(1.0f, 2.0f, 3.0f); + vec3 end_vec = vec3(5.0f, 6.0f, 7.0f); + float t_mid = 0.5f; + vec3 mid_point = lerp(start_vec, end_vec, t_mid); + assert(std::abs(mid_point.x - 3.0f) < 1e-5f); + assert(std::abs(mid_point.y - 4.0f) < 1e-5f); + assert(std::abs(mid_point.z - 5.0f) < 1e-5f); + + // Test lerp with float + float start_f = 10.0f; + float end_f = 20.0f; + float mid_f = lerp(start_f, end_f, t_mid); + assert(std::abs(mid_f - 15.0f) < 1e-5f); + + printf("test_lerp passed. +"); +} + +int main(int argc, char** argv) { + // This main function is for running tests standalone if needed, + // but tests are typically run via ctest. + // However, for the sake of this execution, we can run them directly. + + test_vec3_operations(); + test_quaternion_operations(); + test_easing_functions(); + test_lerp(); + + return 0; +} |
