1 #include "IntersectionTest.hpp"
3 #include "geometry/const.hpp"
4 #include "geometry/primitive.hpp"
7 #include <glm/gtx/io.hpp>
8 #include <glm/gtx/transform.hpp>
10 CPPUNIT_TEST_SUITE_REGISTRATION(gong::geometry::test::IntersectionTest);
17 void IntersectionTest::setUp() {
20 void IntersectionTest::tearDown() {
24 void IntersectionTest::testAABB() {
25 AABB a{ { -1, -1, -1 }, { 1, 1, 1 } };
28 CPPUNIT_ASSERT_MESSAGE(
29 "coincidental AABBs should intersect",
34 CPPUNIT_ASSERT_MESSAGE(
35 "AABBs should intersect",
40 CPPUNIT_ASSERT_MESSAGE(
41 "AABBs should not intersect",
46 CPPUNIT_ASSERT_MESSAGE(
47 "AABBs should intersect",
52 CPPUNIT_ASSERT_MESSAGE(
53 "AABBs should not intersect",
58 CPPUNIT_ASSERT_MESSAGE(
59 "AABBs should intersect",
64 CPPUNIT_ASSERT_MESSAGE(
65 "AABBs should not intersect",
70 CPPUNIT_ASSERT_MESSAGE(
71 "AABBs should not intersect",
76 CPPUNIT_ASSERT_MESSAGE(
77 "AABBs should not intersect",
82 void IntersectionTest::testSimpleRayBox() {
83 Ray ray{ { 0, 0, 0 }, { 1, 0, 0 }, { } }; // at origin, pointing right
85 AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin
87 const float delta = std::numeric_limits<float>::epsilon();
91 CPPUNIT_ASSERT_MESSAGE(
92 "ray at origin not intersecting box at origin",
93 Intersection(ray, box, distance)
96 // move ray outside the box, but have it still point at it
97 // should be 4 units to the left now
99 CPPUNIT_ASSERT_MESSAGE(
100 "ray pointing at box doesn't intersect",
101 Intersection(ray, box, distance)
103 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
104 "intersection distance way off",
105 4.0f, distance, delta
108 // move ray to the other side, so it's pointing away now
110 CPPUNIT_ASSERT_MESSAGE(
111 "ray pointing away from box still intersects",
112 !Intersection(ray, box, distance)
115 // 45 deg down from 4 units away, so should be about 4 * sqrt(2)
116 ray.orig = { -5.0f, 4.5f, 0.0f };
117 ray.dir = { 0.70710678118654752440f, -0.70710678118654752440f, 0.0f };
119 CPPUNIT_ASSERT_MESSAGE(
120 "ray pointing at box doesn't intersect",
121 Intersection(ray, box, distance)
123 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
124 "intersection distance way off",
125 5.65685424949238019520f, distance, delta
129 void IntersectionTest::testRayBox() {
130 Ray ray{ { 0, 0, 0 }, { 1, 0, 0 }, { } }; // at origin, pointing right
131 AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin
132 glm::mat4 M(1); // no transformation
134 const float delta = std::numeric_limits<float>::epsilon();
139 CPPUNIT_ASSERT_MESSAGE(
140 "ray at origin not intersecting box at origin",
141 Intersection(ray, box, M, &distance)
143 // normal undefined, so can't test
145 // move ray outside the box, but have it still point at it
146 // should be 4 units to the left now
148 CPPUNIT_ASSERT_MESSAGE(
149 "ray pointing at box to the right doesn't intersect",
150 Intersection(ray, box, M, &distance, &normal)
152 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
153 "intersection distance way off",
154 4.0f, distance, delta
156 CPPUNIT_ASSERT_EQUAL_MESSAGE(
157 "wrong surface normal at intersection point",
158 glm::vec3(-1, 0, 0), normal
161 // move ray to the other side, so it's pointing away now
163 CPPUNIT_ASSERT_MESSAGE(
164 "ray pointing away from box to the left still intersects",
165 !Intersection(ray, box, M)
170 CPPUNIT_ASSERT_MESSAGE(
171 "ray pointing at box to the left does not intersect",
172 Intersection(ray, box, M, &distance, &normal)
174 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
175 "intersection distance way off",
176 4.0f, distance, delta
178 CPPUNIT_ASSERT_EQUAL_MESSAGE(
179 "wrong surface normal at intersection point",
180 glm::vec3(1, 0, 0), normal
184 ray.orig = { 0, -5, 0 };
185 ray.dir = { 0, 1, 0 };
186 CPPUNIT_ASSERT_MESSAGE(
187 "ray pointing at box above does not intersect",
188 Intersection(ray, box, M, &distance, &normal)
190 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
191 "intersection distance way off",
192 4.0f, distance, delta
194 CPPUNIT_ASSERT_EQUAL_MESSAGE(
195 "wrong surface normal at intersection point",
196 glm::vec3(0, -1, 0), normal
201 CPPUNIT_ASSERT_MESSAGE(
202 "ray pointing away from box above still intersects",
203 !Intersection(ray, box, M)
208 CPPUNIT_ASSERT_MESSAGE(
209 "ray pointing at box below does not intersect",
210 Intersection(ray, box, M, &distance, &normal)
212 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
213 "intersection distance way off",
214 4.0f, distance, delta
216 CPPUNIT_ASSERT_EQUAL_MESSAGE(
217 "wrong surface normal at intersection point",
218 glm::vec3(0, 1, 0), normal
222 ray.orig = { 0, 0, -5 };
223 ray.dir = { 0, 0, 1 };
224 CPPUNIT_ASSERT_MESSAGE(
225 "ray pointing at box in front does not intersect",
226 Intersection(ray, box, M, &distance, &normal)
228 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
229 "intersection distance way off",
230 4.0f, distance, delta
232 CPPUNIT_ASSERT_EQUAL_MESSAGE(
233 "wrong surface normal at intersection point",
234 glm::vec3(0, 0, -1), normal
239 CPPUNIT_ASSERT_MESSAGE(
240 "ray pointing away from box in front still intersects",
241 !Intersection(ray, box, M)
246 CPPUNIT_ASSERT_MESSAGE(
247 "ray pointing at box behind does not intersect",
248 Intersection(ray, box, M, &distance, &normal)
250 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
251 "intersection distance way off",
252 4.0f, distance, delta
254 CPPUNIT_ASSERT_EQUAL_MESSAGE(
255 "wrong surface normal at intersection point",
256 glm::vec3(0, 0, 1), normal
259 // 45 deg down from 4 units away, so should be about 4 * sqrt(2)
260 ray.orig = { -5.0f, 4.5f, 0.0f };
261 ray.dir = { 0.70710678118654752440f, -0.70710678118654752440f, 0.0f };
262 CPPUNIT_ASSERT_MESSAGE(
263 "ray pointing at box doesn't intersect",
264 Intersection(ray, box, M, &distance, &normal)
266 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
267 "intersection distance way off",
268 5.65685424949238019520f, distance, delta
270 CPPUNIT_ASSERT_EQUAL_MESSAGE(
271 "wrong surface normal at intersection point",
272 glm::vec3(-1, 0, 0), normal
276 void IntersectionTest::testBoxBox() {
277 const float delta = std::numeric_limits<float>::epsilon();
281 AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin
282 glm::mat4 Ma(1); // identity
283 glm::mat4 Mb(1); // identity
284 // they're identical, so should probably intersect ^^
286 CPPUNIT_ASSERT_MESSAGE(
287 "identical OBBs don't intersect",
288 Intersection(box, Ma, box, Mb, depth, normal)
290 // depth is two, but normal can be any
291 // (will probably be the first axis of box a, but any is valid)
292 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
293 "penetration depth of coincidental 2x2x2 boxes is not 2",
297 Ma = glm::translate(glm::vec3(-2, 0, 0)); // 2 to the left
298 Mb = glm::translate(glm::vec3(2, 0, 0)); // 2 to the right
299 CPPUNIT_ASSERT_MESSAGE(
300 "distant OBBs intersect (2 apart, no rotation)",
301 !Intersection(box, Ma, box, Mb, depth, normal)
303 // depth and normal undefined for non-intersecting objects
305 Ma = glm::rotate(PI_0p25, glm::vec3(0, 0, 1)); // rotated 45° around Z
306 Mb = glm::translate(glm::vec3(2.4, 0, 0)); // 2.4 to the right
307 // they should barely touch. intersect by about sqrt(2) - 1.4 if my head works
308 CPPUNIT_ASSERT_MESSAGE(
309 "OBBs don't intersect (one rotated by 45°)",
310 Intersection(box, Ma, box, Mb, depth, normal)
312 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
313 "bad penetration depth (with rotation)",
314 0.01421356237309504880f, depth, delta
316 CPPUNIT_ASSERT_EQUAL_MESSAGE(
317 "bad intersection normal (with rotation)",
318 glm::vec3(1, 0, 0), glm::abs(normal) // normal can be in + or - x, therefore abs()
321 Mb = glm::translate(glm::vec3(3, 0, 0)); // 3 to the right
322 CPPUNIT_ASSERT_MESSAGE(
323 "OBBs intersect (one rotated by 45°)",
324 !Intersection(box, Ma, box, Mb, depth, normal)
328 void IntersectionTest::testSpherePlane() {
329 const float delta = std::numeric_limits<float>::epsilon();
331 // unit sphere at origin
332 Sphere sphere{{ 0.0f, 0.0f, 0.0f }, 1.0f};
333 // horizontal plane at origin (the XZ plane)
334 Plane plane{{ 0.0f, 1.0f, 0.0f }, 0.0f };
338 CPPUNIT_ASSERT_MESSAGE(
339 "sphere at origin does not intersect plane at origin",
340 Intersection(sphere, plane, depth, normal)
342 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
343 "bad penetration depth of sphere with plane",
346 // normal is actually undefined in this case, but either will work
347 CPPUNIT_ASSERT_MESSAGE(
348 "bad contact normal of sphere intersecting plane",
349 normal == glm::vec3(0.0f, 1.0f, 0.0f) || normal == glm::vec3(0.0f, -1.0f, 0.0f)
352 // center above, but still intersecting
353 sphere.origin.y = 0.5f;
354 CPPUNIT_ASSERT_MESSAGE(
355 "sphere does not intersect plane",
356 Intersection(sphere, plane, depth, normal)
358 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
359 "bad penetration depth of sphere with plane",
362 CPPUNIT_ASSERT_EQUAL_MESSAGE(
363 "bad contact normal of sphere intersecting plane",
364 glm::vec3(0.0f, 1.0f, 0.0f), normal
367 // center below, but still intersecting
368 sphere.origin.y = -0.5f;
369 CPPUNIT_ASSERT_MESSAGE(
370 "sphere does not intersect plane",
371 Intersection(sphere, plane, depth, normal)
373 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
374 "bad penetration depth of sphere with plane",
377 CPPUNIT_ASSERT_EQUAL_MESSAGE(
378 "bad contact normal of sphere intersecting plane",
379 glm::vec3(0.0f, -1.0f, 0.0f), normal
382 // sphere completely above
383 sphere.origin.y = 1.5f;
384 CPPUNIT_ASSERT_MESSAGE(
385 "sphere above plane intersects",
386 !Intersection(sphere, plane, depth, normal)
389 // sphere completely below
390 sphere.origin.y = -1.5f;
391 CPPUNIT_ASSERT_MESSAGE(
392 "sphere below plane intersects",
393 !Intersection(sphere, plane, depth, normal)
397 void IntersectionTest::testSphereHalfSpace() {
398 const float delta = std::numeric_limits<float>::epsilon();
400 // unit sphere at origin
401 Sphere sphere{{ 0.0f, 0.0f, 0.0f }, 1.0f};
402 // horizontal plane at origin (the XZ plane)
403 Plane plane{{ 0.0f, 1.0f, 0.0f }, 0.0f };
406 CPPUNIT_ASSERT_MESSAGE(
407 "sphere at origin does not intersect half space to origin",
408 Intersection(sphere, plane, depth)
410 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
411 "bad penetration depth of sphere with half space",
415 sphere.origin.y = 0.5f;
416 CPPUNIT_ASSERT_MESSAGE(
417 "sphere does not intersect half space",
418 Intersection(sphere, plane, depth)
420 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
421 "bad penetration depth of sphere with half space",
425 sphere.origin.y = -0.5f;
426 CPPUNIT_ASSERT_MESSAGE(
427 "sphere does not intersect half space",
428 Intersection(sphere, plane, depth)
430 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
431 "bad penetration depth of sphere with half space",
435 sphere.origin.y = -1.5f;
436 CPPUNIT_ASSERT_MESSAGE(
437 "sphere inside half space does not intersect",
438 Intersection(sphere, plane, depth)
440 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
441 "bad penetration depth of sphere with half space",
445 sphere.origin.y = 1.5f;
446 CPPUNIT_ASSERT_MESSAGE(
447 "sphere outside half space intersects",
448 !Intersection(sphere, plane, depth)