]> git.localhorst.tv Git - gong.git/blob - tst/geometry/IntersectionTest.cpp
7aac189f58fda280209cd5677f23c7cdb85aa708
[gong.git] / tst / geometry / IntersectionTest.cpp
1 #include "IntersectionTest.hpp"
2
3 #include "geometry/const.hpp"
4 #include "geometry/primitive.hpp"
5
6 #include <limits>
7 #include <glm/gtx/io.hpp>
8 #include <glm/gtx/transform.hpp>
9
10 CPPUNIT_TEST_SUITE_REGISTRATION(gong::geometry::test::IntersectionTest);
11
12
13 namespace gong {
14 namespace geometry {
15 namespace test {
16
17 void IntersectionTest::setUp() {
18 }
19
20 void IntersectionTest::tearDown() {
21 }
22
23
24 void IntersectionTest::testSimpleRayBoxIntersection() {
25         Ray ray{ { 0, 0, 0 }, { 1, 0, 0 }, { } }; // at origin, pointing right
26         ray.Update();
27         AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin
28
29         const float delta = std::numeric_limits<float>::epsilon();
30
31         float distance = 0;
32
33         CPPUNIT_ASSERT_MESSAGE(
34                 "ray at origin not intersecting box at origin",
35                 Intersection(ray, box, distance)
36         );
37
38         // move ray outside the box, but have it still point at it
39         // should be 4 units to the left now
40         ray.orig.x = -5;
41         CPPUNIT_ASSERT_MESSAGE(
42                 "ray pointing at box doesn't intersect",
43                 Intersection(ray, box, distance)
44         );
45         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
46                 "intersection distance way off",
47                 4.0f, distance, delta
48         );
49
50         // move ray to the other side, so it's pointing away now
51         ray.orig.x = 5;
52         CPPUNIT_ASSERT_MESSAGE(
53                 "ray pointing away from box still intersects",
54                 !Intersection(ray, box, distance)
55         );
56
57         // 45 deg down from 4 units away, so should be about 4 * sqrt(2)
58         ray.orig = { -5.0f, 4.5f, 0.0f };
59         ray.dir = { 0.70710678118654752440f, -0.70710678118654752440f, 0.0f };
60         ray.Update();
61         CPPUNIT_ASSERT_MESSAGE(
62                 "ray pointing at box doesn't intersect",
63                 Intersection(ray, box, distance)
64         );
65         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
66                 "intersection distance way off",
67                 5.65685424949238019520f, distance, delta
68         );
69 }
70
71 void IntersectionTest::testRayBoxIntersection() {
72         Ray ray{ { 0, 0, 0 }, { 1, 0, 0 }, { } }; // at origin, pointing right
73         AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin
74         glm::mat4 M(1); // no transformation
75
76         const float delta = std::numeric_limits<float>::epsilon();
77
78         float distance = 0;
79         glm::vec3 normal(0);
80
81         CPPUNIT_ASSERT_MESSAGE(
82                 "ray at origin not intersecting box at origin",
83                 Intersection(ray, box, M, &distance)
84         );
85         // normal undefined, so can't test
86
87         // move ray outside the box, but have it still point at it
88         // should be 4 units to the left now
89         ray.orig.x = -5;
90         CPPUNIT_ASSERT_MESSAGE(
91                 "ray pointing at box to the right doesn't intersect",
92                 Intersection(ray, box, M, &distance, &normal)
93         );
94         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
95                 "intersection distance way off",
96                 4.0f, distance, delta
97         );
98         CPPUNIT_ASSERT_EQUAL_MESSAGE(
99                 "wrong surface normal at intersection point",
100                 glm::vec3(-1, 0, 0), normal
101         );
102
103         // move ray to the other side, so it's pointing away now
104         ray.orig.x = 5;
105         CPPUNIT_ASSERT_MESSAGE(
106                 "ray pointing away from box to the left still intersects",
107                 !Intersection(ray, box, M)
108         );
109
110         // turn ray around
111         ray.dir.x = -1;
112         CPPUNIT_ASSERT_MESSAGE(
113                 "ray pointing at box to the left does not intersect",
114                 Intersection(ray, box, M, &distance, &normal)
115         );
116         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
117                 "intersection distance way off",
118                 4.0f, distance, delta
119         );
120         CPPUNIT_ASSERT_EQUAL_MESSAGE(
121                 "wrong surface normal at intersection point",
122                 glm::vec3(1, 0, 0), normal
123         );
124
125         // ray below
126         ray.orig = { 0, -5, 0 };
127         ray.dir = { 0, 1, 0 };
128         CPPUNIT_ASSERT_MESSAGE(
129                 "ray pointing at box above does not intersect",
130                 Intersection(ray, box, M, &distance, &normal)
131         );
132         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
133                 "intersection distance way off",
134                 4.0f, distance, delta
135         );
136         CPPUNIT_ASSERT_EQUAL_MESSAGE(
137                 "wrong surface normal at intersection point",
138                 glm::vec3(0, -1, 0), normal
139         );
140
141         // turn ray around
142         ray.dir.y = -1;
143         CPPUNIT_ASSERT_MESSAGE(
144                 "ray pointing away from box above still intersects",
145                 !Intersection(ray, box, M)
146         );
147
148         // move ray above
149         ray.orig.y = 5;
150         CPPUNIT_ASSERT_MESSAGE(
151                 "ray pointing at box below does not intersect",
152                 Intersection(ray, box, M, &distance, &normal)
153         );
154         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
155                 "intersection distance way off",
156                 4.0f, distance, delta
157         );
158         CPPUNIT_ASSERT_EQUAL_MESSAGE(
159                 "wrong surface normal at intersection point",
160                 glm::vec3(0, 1, 0), normal
161         );
162
163         // ray behind
164         ray.orig = { 0, 0, -5 };
165         ray.dir = { 0, 0, 1 };
166         CPPUNIT_ASSERT_MESSAGE(
167                 "ray pointing at box in front does not intersect",
168                 Intersection(ray, box, M, &distance, &normal)
169         );
170         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
171                 "intersection distance way off",
172                 4.0f, distance, delta
173         );
174         CPPUNIT_ASSERT_EQUAL_MESSAGE(
175                 "wrong surface normal at intersection point",
176                 glm::vec3(0, 0, -1), normal
177         );
178
179         // turn ray around
180         ray.dir.z = -1;
181         CPPUNIT_ASSERT_MESSAGE(
182                 "ray pointing away from box in front still intersects",
183                 !Intersection(ray, box, M)
184         );
185
186         // move ray in front
187         ray.orig.z = 5;
188         CPPUNIT_ASSERT_MESSAGE(
189                 "ray pointing at box behind does not intersect",
190                 Intersection(ray, box, M, &distance, &normal)
191         );
192         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
193                 "intersection distance way off",
194                 4.0f, distance, delta
195         );
196         CPPUNIT_ASSERT_EQUAL_MESSAGE(
197                 "wrong surface normal at intersection point",
198                 glm::vec3(0, 0, 1), normal
199         );
200
201         // 45 deg down from 4 units away, so should be about 4 * sqrt(2)
202         ray.orig = { -5.0f, 4.5f, 0.0f };
203         ray.dir = { 0.70710678118654752440f, -0.70710678118654752440f, 0.0f };
204         CPPUNIT_ASSERT_MESSAGE(
205                 "ray pointing at box doesn't intersect",
206                 Intersection(ray, box, M, &distance, &normal)
207         );
208         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
209                 "intersection distance way off",
210                 5.65685424949238019520f, distance, delta
211         );
212         CPPUNIT_ASSERT_EQUAL_MESSAGE(
213                 "wrong surface normal at intersection point",
214                 glm::vec3(-1, 0, 0), normal
215         );
216 }
217
218 void IntersectionTest::testBoxBoxIntersection() {
219         const float delta = std::numeric_limits<float>::epsilon();
220         float depth = 0;
221         glm::vec3 normal(0);
222
223         AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin
224         glm::mat4 Ma(1); // identity
225         glm::mat4 Mb(1); // identity
226         // they're identical, so should probably intersect ^^
227
228         CPPUNIT_ASSERT_MESSAGE(
229                 "identical OBBs don't intersect",
230                 Intersection(box, Ma, box, Mb, depth, normal)
231         );
232         // depth is two, but normal can be any
233         // (will probably be the first axis of box a, but any is valid)
234         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
235                 "penetration depth of coincidental 2x2x2 boxes is not 2",
236                 2.0f, depth, delta
237         );
238
239         Ma = glm::translate(glm::vec3(-2, 0, 0)); // 2 to the left
240         Mb = glm::translate(glm::vec3(2, 0, 0)); // 2 to the right
241         CPPUNIT_ASSERT_MESSAGE(
242                 "distant OBBs intersect (2 apart, no rotation)",
243                 !Intersection(box, Ma, box, Mb, depth, normal)
244         );
245         // depth and normal undefined for non-intersecting objects
246
247         Ma = glm::rotate(PI_0p25, glm::vec3(0, 0, 1)); // rotated 45° around Z
248         Mb = glm::translate(glm::vec3(2.4, 0, 0)); // 2.4 to the right
249         // they should barely touch. intersect by about sqrt(2) - 1.4 if my head works
250         CPPUNIT_ASSERT_MESSAGE(
251                 "OBBs don't intersect (one rotated by 45°)",
252                 Intersection(box, Ma, box, Mb, depth, normal)
253         );
254         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
255                 "bad penetration depth (with rotation)",
256                 0.01421356237309504880f, depth, delta
257         );
258         CPPUNIT_ASSERT_EQUAL_MESSAGE(
259                 "bad intersection normal (with rotation)",
260                 glm::vec3(1, 0, 0), glm::abs(normal) // normal can be in + or - x, therefore abs()
261         );
262
263         Mb = glm::translate(glm::vec3(3, 0, 0)); // 3 to the right
264         CPPUNIT_ASSERT_MESSAGE(
265                 "OBBs intersect (one rotated by 45°)",
266                 !Intersection(box, Ma, box, Mb, depth, normal)
267         );
268 }
269
270 }
271 }
272 }