1 #include "IntersectTest.hpp"
3 #include "../assert.hpp"
5 #include "math/const.hpp"
6 #include "math/geometry.hpp"
9 #include <glm/gtx/transform.hpp>
11 CPPUNIT_TEST_SUITE_REGISTRATION(blobs::math::test::IntersectTest);
13 using blobs::test::AssertEqual;
20 void IntersectTest::setUp() {
23 void IntersectTest::tearDown() {
27 void IntersectTest::testRayBoxIntersection() {
28 Ray ray{ { 0, 0, 0 }, { 1, 0, 0 } }; // at origin, pointing right
29 AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin
30 glm::dmat4 M(1); // no transformation
32 const double delta = 1.0e-15;
37 CPPUNIT_ASSERT_MESSAGE(
38 "ray at origin not intersecting box at origin",
39 Intersect(ray, box, M, normal, distance)
41 // normal undefined, so can't test
43 // move ray outside the box, but have it still point at it
44 // should be 4 units to the left now
45 ray.Origin({ -5, 0, 0 });
46 CPPUNIT_ASSERT_MESSAGE(
47 "ray pointing at box to the right doesn't intersect",
48 Intersect(ray, box, M, normal, distance)
50 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
51 "intersection distance way off",
55 "wrong surface normal at intersection point",
56 glm::dvec3(-1, 0, 0), normal
59 // move ray to the other side, so it's pointing away now
60 ray.Origin({ 5, 0, 0 });
61 CPPUNIT_ASSERT_MESSAGE(
62 "ray pointing away from box to the left still intersects",
63 !Intersect(ray, box, M, normal, distance)
67 ray.Direction({ -1, 0, 0 });
68 CPPUNIT_ASSERT_MESSAGE(
69 "ray pointing at box to the left does not intersect",
70 Intersect(ray, box, M, normal, distance)
72 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
73 "intersection distance way off",
77 "wrong surface normal at intersection point",
78 glm::dvec3(1, 0, 0), normal
82 ray.Origin({ 0, -5, 0 });
83 ray.Direction({ 0, 1, 0 });
84 CPPUNIT_ASSERT_MESSAGE(
85 "ray pointing at box above does not intersect",
86 Intersect(ray, box, M, normal, distance)
88 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
89 "intersection distance way off",
93 "wrong surface normal at intersection point",
94 glm::dvec3(0, -1, 0), normal
98 ray.Direction({ 0, -1, 0 });
99 CPPUNIT_ASSERT_MESSAGE(
100 "ray pointing away from box above still intersects",
101 !Intersect(ray, box, M, normal, distance)
105 ray.Origin({ 0, 5, 0 });
106 CPPUNIT_ASSERT_MESSAGE(
107 "ray pointing at box below does not intersect",
108 Intersect(ray, box, M, normal, distance)
110 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
111 "intersection distance way off",
115 "wrong surface normal at intersection point",
116 glm::dvec3(0, 1, 0), normal
120 ray.Origin({ 0, 0, -5 });
121 ray.Direction({ 0, 0, 1 });
122 CPPUNIT_ASSERT_MESSAGE(
123 "ray pointing at box in front does not intersect",
124 Intersect(ray, box, M, normal, distance)
126 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
127 "intersection distance way off",
131 "wrong surface normal at intersection point",
132 glm::dvec3(0, 0, -1), normal
136 ray.Direction({ 0, 0, -1 });
137 CPPUNIT_ASSERT_MESSAGE(
138 "ray pointing away from box in front still intersects",
139 !Intersect(ray, box, M, normal, distance)
143 ray.Origin({ 0, 0, 5 });
144 CPPUNIT_ASSERT_MESSAGE(
145 "ray pointing at box behind does not intersect",
146 Intersect(ray, box, M, normal, distance)
148 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
149 "intersection distance way off",
153 "wrong surface normal at intersection point",
154 glm::dvec3(0, 0, 1), normal
157 // 45 deg down from 4 units away, so should be about 4 * sqrt(2)
158 ray.Origin({ -5, 4.5, 0 });
159 ray.Direction({ 0.70710678118654752440, -0.70710678118654752440, 0 });
160 CPPUNIT_ASSERT_MESSAGE(
161 "ray pointing at box doesn't intersect",
162 Intersect(ray, box, M, normal, distance)
164 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
165 "intersection distance way off",
166 5.65685424949238019520, distance, delta
169 "wrong surface normal at intersection point",
170 glm::dvec3(-1, 0, 0), normal
174 void IntersectTest::testBoxBoxIntersection() {
175 const double delta = std::numeric_limits<double>::epsilon();
177 glm::dvec3 normal(0);
179 AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin
180 glm::dmat4 Ma(1); // identity
181 glm::dmat4 Mb(1); // identity
182 // they're identical, so should probably intersect ^^
184 CPPUNIT_ASSERT_MESSAGE(
185 "identical OBBs don't intersect",
186 Intersect(box, Ma, box, Mb, normal, depth)
188 // depth is two, but normal can be any
189 // (will probably be the first axis of box a, but any is valid)
190 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
191 "penetration depth of coincidental 2x2x2 boxes is not 2",
195 Ma = glm::translate(glm::dvec3(-2, 0, 0)); // 2 to the left
196 Mb = glm::translate(glm::dvec3(2, 0, 0)); // 2 to the right
197 CPPUNIT_ASSERT_MESSAGE(
198 "distant OBBs intersect (2 apart, no rotation)",
199 !Intersect(box, Ma, box, Mb, normal, depth)
201 // depth and normal undefined for non-intersecting objects
203 Ma = glm::rotate(PI * 0.25, glm::dvec3(0, 0, 1)); // rotated 45° around Z
204 Mb = glm::translate(glm::dvec3(2.4, 0, 0)); // 2.4 to the right
205 // they should barely touch. intersect by about sqrt(2) - 1.4 if my head works
206 CPPUNIT_ASSERT_MESSAGE(
207 "OBBs don't intersect (one rotated by 45°)",
208 Intersect(box, Ma, box, Mb, normal, depth)
210 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
211 "bad penetration depth (with rotation)",
212 0.014213562373095, depth, delta
215 "bad intersection normal (with rotation)",
216 glm::dvec3(1, 0, 0), glm::abs(normal) // normal can be in + or - x, therefore abs()
219 Mb = glm::translate(glm::dvec3(3, 0, 0)); // 3 to the right
220 CPPUNIT_ASSERT_MESSAGE(
221 "OBBs intersect (one rotated by 45°)",
222 !Intersect(box, Ma, box, Mb, normal, depth)
226 void IntersectTest::testRaySphereIntersection() {
227 const double epsilon = std::numeric_limits<double>::epsilon();
228 Ray ray{ { 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 } }; // at origin, pointing right
229 Sphere sphere{ { 0.0, 0.0, 0.0 }, 1.0 }; // unit sphere at origin
231 glm::dvec3 normal(0.0);
233 CPPUNIT_ASSERT_MESSAGE(
234 "ray at origin does not intersect sphere at origin",
235 Intersect(ray, sphere, normal, dist)
237 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
238 "distance along ray to unit sphere, both at origin, is not 1",
242 "bad intersection normal",
243 glm::dvec3(1.0, 0.0, 0.0), normal
246 ray.Origin({ 0.5, 0.0, 0.0 }); // a tad to the right
247 CPPUNIT_ASSERT_MESSAGE(
248 "ray does not intersect sphere at origin",
249 Intersect(ray, sphere, normal, dist)
251 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
252 "distance along ray to unit sphere at origin is not 0.5",
256 "bad intersection normal",
257 glm::dvec3(1.0, 0.0, 0.0), normal
260 // corner case: ray origin exactly on sphere (should "intersect")
261 ray.Origin({ 1.0, 0.0, 0.0 });
262 CPPUNIT_ASSERT_MESSAGE(
263 "ray touching sphere does not intersect it",
264 Intersect(ray, sphere, normal, dist)
266 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
267 "distance along ray touching unit sphere is not 0.0",
271 "bad intersection normal",
272 glm::dvec3(1.0, 0.0, 0.0), normal
275 ray.Origin({ 2.0, 0.0, 0.0 }); // move outside
276 CPPUNIT_ASSERT_MESSAGE(
277 "ray pointing away from sphere intersects it for some reason",
278 !Intersect(ray, sphere, normal, dist)
281 ray.Direction({ -1.0, 0.0, 0.0 }); // flip it around
282 CPPUNIT_ASSERT_MESSAGE(
283 "negative X ray does not intersect sphere",
284 Intersect(ray, sphere, normal, dist)
286 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
287 "distance along ray to unit sphere at origin is not 1",
291 "bad intersection normal",
292 glm::dvec3(1.0, 0.0, 0.0), normal
295 // sphere at 3,0,0; ray at 0,4,0 pointing directly at it
296 // should be 5 units apart, minus one for the radius
297 ray.Origin({ 0.0, 4.0, 0.0 });
298 ray.Direction(glm::normalize(glm::dvec3(3.0, -4.0, 0.0)));
299 sphere.origin = { 3.0, 0.0, 0.0 };
300 CPPUNIT_ASSERT_MESSAGE(
301 "diagonal ray does not intersect sphere",
302 Intersect(ray, sphere, normal, dist)
304 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
305 "distance along ray to unit sphere is not 4",
309 "bad intersection normal",
310 glm::normalize(glm::dvec3(-3.0, 4.0, 0.0)), normal
313 // point the ray straight down, so it misses
314 ray.Direction({ 0.0, -1.0, 0.0});
315 CPPUNIT_ASSERT_MESSAGE(
316 "vertical ray should not intersect sphere",
317 !Intersect(ray, sphere, normal, dist)