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