1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
// This file is part of the 64k demo project.
// It tests the 3D system components (Camera, Object, Scene).
#include "3d/camera.h"
#include "3d/object.h"
#include "3d/scene.h"
#include <cassert>
#include <cmath>
#include <iostream>
bool near(float a, float b, float e = 0.001f) {
return std::abs(a - b) < e;
}
void test_camera() {
std::cout << "Testing Camera..." << std::endl;
Camera cam;
cam.position = vec3(0, 0, 10);
cam.target = vec3(0, 0, 0);
mat4 view = cam.get_view_matrix();
// Camera at (0,0,10) looking at (0,0,0). World (0,0,0) -> View (0,0,-10)
assert(near(view.m[14], -10.0f));
// Test Camera::set_look_at
cam.set_look_at({5, 0, 0}, {0, 0, 0}, {0, 1, 0}); // Look at origin from (5,0,0)
mat4 view_shifted = cam.get_view_matrix();
// The camera's forward vector (0,0,-1) should now point towards (-1,0,0) in world space.
// The translation part of the view matrix should be based on -dot(s, eye), -dot(u, eye), dot(f, eye)
// s = (0,0,-1), u = (0,1,0), f = (-1,0,0)
// m[12] = -dot({0,0,-1}, {5,0,0}) = 0
// m[13] = -dot({0,1,0}, {5,0,0}) = 0
// m[14] = dot({-1,0,0}, {5,0,0}) = -5
assert(near(view_shifted.m[12], 0.0f));
assert(near(view_shifted.m[13], 0.0f));
assert(near(view_shifted.m[14], -5.0f));
// Test Camera::get_projection_matrix with varied parameters
// Change FOV and aspect ratio
mat4 proj = cam.get_projection_matrix();
cam.fov_y_rad = 1.0472f; // 60 degrees
cam.aspect_ratio = 0.5f; // Narrower aspect ratio
mat4 proj_varied = cam.get_projection_matrix();
// m[0] should increase due to narrower aspect ratio (1/tan(30deg)/0.5)
assert(proj_varied.m[0] > proj.m[0]);
// m[5] should increase due to larger FOV (1/tan(30deg))
assert(proj_varied.m[5] < proj.m[5]);
}
void test_object_transform() {
std::cout << "Testing Object Transform..." << std::endl;
Object3D obj;
obj.position = vec3(10, 0, 0);
// Model matrix should translate by (10,0,0)
mat4 m = obj.get_model_matrix();
assert(near(m.m[12], 10.0f));
// Test composed transformations (translate then rotate)
obj.position = vec3(5, 0, 0);
obj.rotation = quat::from_axis({0, 1, 0}, 1.570796f); // 90 deg Y rotation
m = obj.get_model_matrix();
// Transform point (1,0,0). Rotation around Y maps (1,0,0) to (0,0,-1).
// Translation moves it by (5,0,0). Final world pos: (5,0,-1).
vec4 p_comp(1, 0, 0, 1);
vec4 res_comp = m * p_comp;
assert(near(res_comp.x, 5.0f));
assert(near(res_comp.z, -1.0f));
// Test Object3D::inv_model calculation
// Model matrix for translation (5,0,0) is just translation
obj.position = vec3(5, 0, 0);
obj.rotation = quat(); // Identity rotation
mat4 model_t = obj.get_model_matrix();
mat4 inv_model_t = model_t.inverse();
// Applying inv_model to a translated point should undo the translation.
// Point (5,0,0) should go to (0,0,0)
vec4 translated_point(5,0,0,1);
vec4 original_space_t = inv_model_t * vec4(translated_point.x, translated_point.y, translated_point.z, 1.0);
assert(near(original_space_t.x, 0.0f) && near(original_space_t.y, 0.0f) && near(original_space_t.z, 0.0f));
// Model matrix with rotation (90 deg Y) and translation (5,0,0)
obj.position = vec3(5, 0, 0);
obj.rotation = quat::from_axis({0, 1, 0}, 1.570796f);
mat4 model_trs = obj.get_model_matrix();
mat4 inv_model_trs = model_trs.inverse();
// Transform point (1,0,0) (local right) via TRS: Rotates to (0,0,-1), Translates to (5,0,-1)
vec4 p_trs(1,0,0,1);
vec4 transformed_p = model_trs * p_trs;
assert(near(transformed_p.x, 5.0f) && near(transformed_p.z, -1.0f));
// Apply inverse to transformed point to get back original point
vec4 original_space_trs = inv_model_trs * transformed_p;
assert(near(original_space_trs.x, 1.0f) && near(original_space_trs.y, 0.0f) && near(original_space_trs.z, 0.0f));
}
void test_scene() {
std::cout << "Testing Scene..." << std::endl;
Scene scene;
scene.add_object(Object3D());
assert(scene.objects.size() == 1);
scene.clear();
assert(scene.objects.empty());
// Add multiple objects and check count
scene.add_object(Object3D());
scene.add_object(Object3D());
assert(scene.objects.size() == 2);
// Test clearing the scene
scene.clear();
assert(scene.objects.empty());
}
int main() {
test_camera();
test_object_transform();
test_scene();
std::cout << "--- 3D SYSTEM TESTS PASSED ---" << std::endl;
return 0;
}
|