/src/ogre/OgreMain/src/OgreMath.cpp
Line | Count | Source |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #include "OgreStableHeaders.h" |
29 | | |
30 | | namespace Ogre |
31 | | { |
32 | | |
33 | | constexpr Real Math::POS_INFINITY; |
34 | | constexpr Real Math::NEG_INFINITY; |
35 | | constexpr Real Math::PI; |
36 | | constexpr Real Math::TWO_PI; |
37 | | constexpr Real Math::HALF_PI; |
38 | | constexpr float Math::fDeg2Rad; |
39 | | constexpr float Math::fRad2Deg; |
40 | | constexpr Real Math::LOG2; |
41 | | |
42 | | int Math::mTrigTableSize; |
43 | | Math::AngleUnit Math::msAngleUnit; |
44 | | |
45 | | float Math::mTrigTableFactor; |
46 | | float *Math::mSinTable = NULL; |
47 | | float *Math::mTanTable = NULL; |
48 | | |
49 | | Math::RandomValueProvider* Math::mRandProvider = NULL; |
50 | | |
51 | | //----------------------------------------------------------------------- |
52 | | Math::Math( unsigned int trigTableSize ) |
53 | 0 | { |
54 | 0 | msAngleUnit = AU_DEGREE; |
55 | 0 | mTrigTableSize = trigTableSize; |
56 | 0 | mTrigTableFactor = mTrigTableSize / Math::TWO_PI; |
57 | |
|
58 | 0 | mSinTable = OGRE_ALLOC_T(float, mTrigTableSize, MEMCATEGORY_GENERAL); |
59 | 0 | mTanTable = OGRE_ALLOC_T(float, mTrigTableSize, MEMCATEGORY_GENERAL); |
60 | |
|
61 | 0 | buildTrigTables(); |
62 | 0 | } |
63 | | |
64 | | //----------------------------------------------------------------------- |
65 | | Math::~Math() |
66 | 0 | { |
67 | 0 | OGRE_FREE(mSinTable, MEMCATEGORY_GENERAL); |
68 | 0 | OGRE_FREE(mTanTable, MEMCATEGORY_GENERAL); |
69 | 0 | } |
70 | | |
71 | | //----------------------------------------------------------------------- |
72 | | void Math::buildTrigTables(void) |
73 | 0 | { |
74 | | // Build trig lookup tables |
75 | | // Could get away with building only PI sized Sin table but simpler this |
76 | | // way. Who cares, it'll ony use an extra 8k of memory anyway and I like |
77 | | // simplicity. |
78 | 0 | float angle; |
79 | 0 | for (int i = 0; i < mTrigTableSize; ++i) |
80 | 0 | { |
81 | 0 | angle = Math::TWO_PI * i / Real(mTrigTableSize); |
82 | 0 | mSinTable[i] = std::sin(angle); |
83 | 0 | mTanTable[i] = std::tan(angle); |
84 | 0 | } |
85 | 0 | } |
86 | | //----------------------------------------------------------------------- |
87 | | float Math::SinTable (float fValue) |
88 | 0 | { |
89 | | // Convert range to index values, wrap if required |
90 | 0 | int idx; |
91 | 0 | if (fValue >= 0) |
92 | 0 | { |
93 | 0 | idx = int(fValue * mTrigTableFactor) % mTrigTableSize; |
94 | 0 | } |
95 | 0 | else |
96 | 0 | { |
97 | 0 | idx = mTrigTableSize - (int(-fValue * mTrigTableFactor) % mTrigTableSize) - 1; |
98 | 0 | } |
99 | |
|
100 | 0 | return mSinTable[idx]; |
101 | 0 | } |
102 | | //----------------------------------------------------------------------- |
103 | | float Math::TanTable (float fValue) |
104 | 0 | { |
105 | | // Convert range to index values, wrap if required |
106 | 0 | int idx = int(fValue * mTrigTableFactor) % mTrigTableSize; |
107 | 0 | return mTanTable[idx]; |
108 | 0 | } |
109 | | //----------------------------------------------------------------------- |
110 | | Radian Math::ACos (Real fValue) |
111 | 0 | { |
112 | 0 | if ( -1.0 < fValue ) |
113 | 0 | { |
114 | 0 | if ( fValue < 1.0 ) |
115 | 0 | return Radian(std::acos(fValue)); |
116 | 0 | else |
117 | 0 | return Radian(0.0); |
118 | 0 | } |
119 | 0 | else |
120 | 0 | { |
121 | 0 | return Radian(PI); |
122 | 0 | } |
123 | 0 | } |
124 | | //----------------------------------------------------------------------- |
125 | | Radian Math::ASin (Real fValue) |
126 | 0 | { |
127 | 0 | if ( -1.0 < fValue ) |
128 | 0 | { |
129 | 0 | if ( fValue < 1.0 ) |
130 | 0 | return Radian(std::asin(fValue)); |
131 | 0 | else |
132 | 0 | return Radian(HALF_PI); |
133 | 0 | } |
134 | 0 | else |
135 | 0 | { |
136 | 0 | return Radian(-HALF_PI); |
137 | 0 | } |
138 | 0 | } |
139 | | |
140 | | //----------------------------------------------------------------------- |
141 | | void Math::SetRandomValueProvider(RandomValueProvider* provider) |
142 | 0 | { |
143 | 0 | mRandProvider = provider; |
144 | 0 | } |
145 | | |
146 | | //----------------------------------------------------------------------- |
147 | | void Math::setAngleUnit(Math::AngleUnit unit) |
148 | 0 | { |
149 | 0 | msAngleUnit = unit; |
150 | 0 | } |
151 | | //----------------------------------------------------------------------- |
152 | | Math::AngleUnit Math::getAngleUnit(void) |
153 | 0 | { |
154 | 0 | return msAngleUnit; |
155 | 0 | } |
156 | | //----------------------------------------------------------------------- |
157 | | float Math::AngleUnitsToRadians(float angleunits) |
158 | 0 | { |
159 | 0 | if (msAngleUnit == AU_DEGREE) |
160 | 0 | return angleunits * fDeg2Rad; |
161 | 0 | else |
162 | 0 | return angleunits; |
163 | 0 | } |
164 | | |
165 | | //----------------------------------------------------------------------- |
166 | | float Math::RadiansToAngleUnits(float radians) |
167 | 0 | { |
168 | 0 | if (msAngleUnit == AU_DEGREE) |
169 | 0 | return radians * fRad2Deg; |
170 | 0 | else |
171 | 0 | return radians; |
172 | 0 | } |
173 | | |
174 | | //----------------------------------------------------------------------- |
175 | | float Math::AngleUnitsToDegrees(float angleunits) |
176 | 0 | { |
177 | 0 | if (msAngleUnit == AU_RADIAN) |
178 | 0 | return angleunits * fRad2Deg; |
179 | 0 | else |
180 | 0 | return angleunits; |
181 | 0 | } |
182 | | |
183 | | //----------------------------------------------------------------------- |
184 | | float Math::DegreesToAngleUnits(float degrees) |
185 | 0 | { |
186 | 0 | if (msAngleUnit == AU_RADIAN) |
187 | 0 | return degrees * fDeg2Rad; |
188 | 0 | else |
189 | 0 | return degrees; |
190 | 0 | } |
191 | | |
192 | | //----------------------------------------------------------------------- |
193 | | bool Math::pointInTri2D(const Vector2& p, const Vector2& a, |
194 | | const Vector2& b, const Vector2& c) |
195 | 0 | { |
196 | | // Winding must be consistent from all edges for point to be inside |
197 | 0 | Vector2 v1, v2; |
198 | 0 | Real dot[3]; |
199 | 0 | bool zeroDot[3]; |
200 | |
|
201 | 0 | v1 = b - a; |
202 | 0 | v2 = p - a; |
203 | | |
204 | | // Note we don't care about normalisation here since sign is all we need |
205 | | // It means we don't have to worry about magnitude of cross products either |
206 | 0 | dot[0] = v1.crossProduct(v2); |
207 | 0 | zeroDot[0] = Math::RealEqual(dot[0], 0.0f, 1e-3); |
208 | | |
209 | |
|
210 | 0 | v1 = c - b; |
211 | 0 | v2 = p - b; |
212 | |
|
213 | 0 | dot[1] = v1.crossProduct(v2); |
214 | 0 | zeroDot[1] = Math::RealEqual(dot[1], 0.0f, 1e-3); |
215 | | |
216 | | // Compare signs (ignore colinear / coincident points) |
217 | 0 | if(!zeroDot[0] && !zeroDot[1] |
218 | 0 | && Math::Sign(dot[0]) != Math::Sign(dot[1])) |
219 | 0 | { |
220 | 0 | return false; |
221 | 0 | } |
222 | | |
223 | 0 | v1 = a - c; |
224 | 0 | v2 = p - c; |
225 | |
|
226 | 0 | dot[2] = v1.crossProduct(v2); |
227 | 0 | zeroDot[2] = Math::RealEqual(dot[2], 0.0f, 1e-3); |
228 | | // Compare signs (ignore colinear / coincident points) |
229 | 0 | if((!zeroDot[0] && !zeroDot[2] |
230 | 0 | && Math::Sign(dot[0]) != Math::Sign(dot[2])) || |
231 | 0 | (!zeroDot[1] && !zeroDot[2] |
232 | 0 | && Math::Sign(dot[1]) != Math::Sign(dot[2]))) |
233 | 0 | { |
234 | 0 | return false; |
235 | 0 | } |
236 | | |
237 | | |
238 | 0 | return true; |
239 | 0 | } |
240 | | //----------------------------------------------------------------------- |
241 | | bool Math::pointInTri3D(const Vector3& p, const Vector3& a, |
242 | | const Vector3& b, const Vector3& c, const Vector3& normal) |
243 | 0 | { |
244 | | // Winding must be consistent from all edges for point to be inside |
245 | 0 | Vector3 v1, v2; |
246 | 0 | Real dot[3]; |
247 | 0 | bool zeroDot[3]; |
248 | |
|
249 | 0 | v1 = b - a; |
250 | 0 | v2 = p - a; |
251 | | |
252 | | // Note we don't care about normalisation here since sign is all we need |
253 | | // It means we don't have to worry about magnitude of cross products either |
254 | 0 | dot[0] = v1.crossProduct(v2).dotProduct(normal); |
255 | 0 | zeroDot[0] = Math::RealEqual(dot[0], 0.0f, 1e-3); |
256 | | |
257 | |
|
258 | 0 | v1 = c - b; |
259 | 0 | v2 = p - b; |
260 | |
|
261 | 0 | dot[1] = v1.crossProduct(v2).dotProduct(normal); |
262 | 0 | zeroDot[1] = Math::RealEqual(dot[1], 0.0f, 1e-3); |
263 | | |
264 | | // Compare signs (ignore colinear / coincident points) |
265 | 0 | if(!zeroDot[0] && !zeroDot[1] |
266 | 0 | && Math::Sign(dot[0]) != Math::Sign(dot[1])) |
267 | 0 | { |
268 | 0 | return false; |
269 | 0 | } |
270 | | |
271 | 0 | v1 = a - c; |
272 | 0 | v2 = p - c; |
273 | |
|
274 | 0 | dot[2] = v1.crossProduct(v2).dotProduct(normal); |
275 | 0 | zeroDot[2] = Math::RealEqual(dot[2], 0.0f, 1e-3); |
276 | | // Compare signs (ignore colinear / coincident points) |
277 | 0 | if((!zeroDot[0] && !zeroDot[2] |
278 | 0 | && Math::Sign(dot[0]) != Math::Sign(dot[2])) || |
279 | 0 | (!zeroDot[1] && !zeroDot[2] |
280 | 0 | && Math::Sign(dot[1]) != Math::Sign(dot[2]))) |
281 | 0 | { |
282 | 0 | return false; |
283 | 0 | } |
284 | | |
285 | | |
286 | 0 | return true; |
287 | 0 | } |
288 | | //----------------------------------------------------------------------- |
289 | | std::pair<bool, Real> Math::intersects(const Ray& ray, |
290 | | const std::vector<Plane>& planes, bool normalIsOutside) |
291 | 0 | { |
292 | 0 | bool allInside = true; |
293 | 0 | std::pair<bool, Real> ret; |
294 | 0 | std::pair<bool, Real> end; |
295 | 0 | ret.first = false; |
296 | 0 | ret.second = 0.0f; |
297 | 0 | end.first = false; |
298 | 0 | end.second = 0; |
299 | | |
300 | | // derive side |
301 | | // NB we don't pass directly since that would require Plane::Side in |
302 | | // interface, which results in recursive includes since Math is so fundamental |
303 | 0 | Plane::Side outside = normalIsOutside ? Plane::POSITIVE_SIDE : Plane::NEGATIVE_SIDE; |
304 | 0 | for (auto& plane : planes) |
305 | 0 | { |
306 | | // is origin outside? |
307 | 0 | if (plane.getSide(ray.getOrigin()) == outside) |
308 | 0 | { |
309 | 0 | allInside = false; |
310 | | // Test single plane |
311 | 0 | std::pair<bool, Real> planeRes = |
312 | 0 | ray.intersects(plane); |
313 | 0 | if (planeRes.first) |
314 | 0 | { |
315 | | // Ok, we intersected |
316 | 0 | ret.first = true; |
317 | | // Use the most distant result since convex volume |
318 | 0 | ret.second = std::max(ret.second, planeRes.second); |
319 | 0 | } |
320 | 0 | else |
321 | 0 | { |
322 | 0 | ret.first =false; |
323 | 0 | ret.second=0.0f; |
324 | 0 | return ret; |
325 | 0 | } |
326 | 0 | } |
327 | 0 | else |
328 | 0 | { |
329 | 0 | std::pair<bool, Real> planeRes = |
330 | 0 | ray.intersects(plane); |
331 | 0 | if (planeRes.first) |
332 | 0 | { |
333 | 0 | if( !end.first ) |
334 | 0 | { |
335 | 0 | end.first = true; |
336 | 0 | end.second = planeRes.second; |
337 | 0 | } |
338 | 0 | else |
339 | 0 | { |
340 | 0 | end.second = std::min( planeRes.second, end.second ); |
341 | 0 | } |
342 | |
|
343 | 0 | } |
344 | |
|
345 | 0 | } |
346 | 0 | } |
347 | | |
348 | 0 | if (allInside) |
349 | 0 | { |
350 | | // Intersecting at 0 distance since inside the volume! |
351 | 0 | ret.first = true; |
352 | 0 | ret.second = 0.0f; |
353 | 0 | return ret; |
354 | 0 | } |
355 | | |
356 | 0 | if( end.first ) |
357 | 0 | { |
358 | 0 | if( end.second < ret.second ) |
359 | 0 | { |
360 | 0 | ret.first = false; |
361 | 0 | return ret; |
362 | 0 | } |
363 | 0 | } |
364 | 0 | return ret; |
365 | 0 | } |
366 | | //----------------------------------------------------------------------- |
367 | | std::pair<bool, Real> Math::intersects(const Ray& ray, const AxisAlignedBox& box) |
368 | 0 | { |
369 | 0 | if (box.isNull()) return std::pair<bool, Real>(false, (Real)0); |
370 | 0 | if (box.isInfinite()) return std::pair<bool, Real>(true, (Real)0); |
371 | | |
372 | 0 | Real lowt = 0.0f; |
373 | 0 | Real t; |
374 | 0 | bool hit = false; |
375 | 0 | Vector3 hitpoint; |
376 | 0 | const Vector3& min = box.getMinimum(); |
377 | 0 | const Vector3& max = box.getMaximum(); |
378 | 0 | const Vector3& rayorig = ray.getOrigin(); |
379 | 0 | const Vector3& raydir = ray.getDirection(); |
380 | | |
381 | | // Check origin inside first |
382 | 0 | if ( rayorig > min && rayorig < max ) |
383 | 0 | { |
384 | 0 | return std::pair<bool, Real>(true, (Real)0); |
385 | 0 | } |
386 | | |
387 | | // Check each face in turn, only check closest 3 |
388 | | // Min x |
389 | 0 | if (rayorig.x <= min.x && raydir.x > 0) |
390 | 0 | { |
391 | 0 | t = (min.x - rayorig.x) / raydir.x; |
392 | | |
393 | | // Substitute t back into ray and check bounds and dist |
394 | 0 | hitpoint = rayorig + raydir * t; |
395 | 0 | if (hitpoint.y >= min.y && hitpoint.y <= max.y && |
396 | 0 | hitpoint.z >= min.z && hitpoint.z <= max.z && |
397 | 0 | (!hit || t < lowt)) |
398 | 0 | { |
399 | 0 | hit = true; |
400 | 0 | lowt = t; |
401 | 0 | } |
402 | 0 | } |
403 | | // Max x |
404 | 0 | if (rayorig.x >= max.x && raydir.x < 0) |
405 | 0 | { |
406 | 0 | t = (max.x - rayorig.x) / raydir.x; |
407 | | |
408 | | // Substitute t back into ray and check bounds and dist |
409 | 0 | hitpoint = rayorig + raydir * t; |
410 | 0 | if (hitpoint.y >= min.y && hitpoint.y <= max.y && |
411 | 0 | hitpoint.z >= min.z && hitpoint.z <= max.z && |
412 | 0 | (!hit || t < lowt)) |
413 | 0 | { |
414 | 0 | hit = true; |
415 | 0 | lowt = t; |
416 | 0 | } |
417 | 0 | } |
418 | | // Min y |
419 | 0 | if (rayorig.y <= min.y && raydir.y > 0) |
420 | 0 | { |
421 | 0 | t = (min.y - rayorig.y) / raydir.y; |
422 | | |
423 | | // Substitute t back into ray and check bounds and dist |
424 | 0 | hitpoint = rayorig + raydir * t; |
425 | 0 | if (hitpoint.x >= min.x && hitpoint.x <= max.x && |
426 | 0 | hitpoint.z >= min.z && hitpoint.z <= max.z && |
427 | 0 | (!hit || t < lowt)) |
428 | 0 | { |
429 | 0 | hit = true; |
430 | 0 | lowt = t; |
431 | 0 | } |
432 | 0 | } |
433 | | // Max y |
434 | 0 | if (rayorig.y >= max.y && raydir.y < 0) |
435 | 0 | { |
436 | 0 | t = (max.y - rayorig.y) / raydir.y; |
437 | | |
438 | | // Substitute t back into ray and check bounds and dist |
439 | 0 | hitpoint = rayorig + raydir * t; |
440 | 0 | if (hitpoint.x >= min.x && hitpoint.x <= max.x && |
441 | 0 | hitpoint.z >= min.z && hitpoint.z <= max.z && |
442 | 0 | (!hit || t < lowt)) |
443 | 0 | { |
444 | 0 | hit = true; |
445 | 0 | lowt = t; |
446 | 0 | } |
447 | 0 | } |
448 | | // Min z |
449 | 0 | if (rayorig.z <= min.z && raydir.z > 0) |
450 | 0 | { |
451 | 0 | t = (min.z - rayorig.z) / raydir.z; |
452 | | |
453 | | // Substitute t back into ray and check bounds and dist |
454 | 0 | hitpoint = rayorig + raydir * t; |
455 | 0 | if (hitpoint.x >= min.x && hitpoint.x <= max.x && |
456 | 0 | hitpoint.y >= min.y && hitpoint.y <= max.y && |
457 | 0 | (!hit || t < lowt)) |
458 | 0 | { |
459 | 0 | hit = true; |
460 | 0 | lowt = t; |
461 | 0 | } |
462 | 0 | } |
463 | | // Max z |
464 | 0 | if (rayorig.z >= max.z && raydir.z < 0) |
465 | 0 | { |
466 | 0 | t = (max.z - rayorig.z) / raydir.z; |
467 | | |
468 | | // Substitute t back into ray and check bounds and dist |
469 | 0 | hitpoint = rayorig + raydir * t; |
470 | 0 | if (hitpoint.x >= min.x && hitpoint.x <= max.x && |
471 | 0 | hitpoint.y >= min.y && hitpoint.y <= max.y && |
472 | 0 | (!hit || t < lowt)) |
473 | 0 | { |
474 | 0 | hit = true; |
475 | 0 | lowt = t; |
476 | 0 | } |
477 | 0 | } |
478 | |
|
479 | 0 | return std::pair<bool, Real>(hit, (Real)lowt); |
480 | |
|
481 | 0 | } |
482 | | //----------------------------------------------------------------------- |
483 | | bool Math::intersects(const Ray& ray, const AxisAlignedBox& box, |
484 | | Real* d1, Real* d2) |
485 | 0 | { |
486 | 0 | if (box.isNull()) |
487 | 0 | return false; |
488 | | |
489 | 0 | if (box.isInfinite()) |
490 | 0 | { |
491 | 0 | if (d1) *d1 = 0; |
492 | 0 | if (d2) *d2 = Math::POS_INFINITY; |
493 | 0 | return true; |
494 | 0 | } |
495 | | |
496 | 0 | const Vector3& min = box.getMinimum(); |
497 | 0 | const Vector3& max = box.getMaximum(); |
498 | 0 | const Vector3& rayorig = ray.getOrigin(); |
499 | 0 | const Vector3& raydir = ray.getDirection(); |
500 | |
|
501 | 0 | Vector3 absDir; |
502 | 0 | absDir[0] = Math::Abs(raydir[0]); |
503 | 0 | absDir[1] = Math::Abs(raydir[1]); |
504 | 0 | absDir[2] = Math::Abs(raydir[2]); |
505 | | |
506 | | // Sort the axis, ensure check minimise floating error axis first |
507 | 0 | int imax = 0, imid = 1, imin = 2; |
508 | 0 | if (absDir[0] < absDir[2]) |
509 | 0 | { |
510 | 0 | imax = 2; |
511 | 0 | imin = 0; |
512 | 0 | } |
513 | 0 | if (absDir[1] < absDir[imin]) |
514 | 0 | { |
515 | 0 | imid = imin; |
516 | 0 | imin = 1; |
517 | 0 | } |
518 | 0 | else if (absDir[1] > absDir[imax]) |
519 | 0 | { |
520 | 0 | imid = imax; |
521 | 0 | imax = 1; |
522 | 0 | } |
523 | |
|
524 | 0 | Real start = 0, end = Math::POS_INFINITY; |
525 | |
|
526 | 0 | #define _CALC_AXIS(i) \ |
527 | 0 | do { \ |
528 | 0 | Real denom = 1 / raydir[i]; \ |
529 | 0 | Real newstart = (min[i] - rayorig[i]) * denom; \ |
530 | 0 | Real newend = (max[i] - rayorig[i]) * denom; \ |
531 | 0 | if (newstart > newend) std::swap(newstart, newend); \ |
532 | 0 | if (newstart > end || newend < start) return false; \ |
533 | 0 | if (newstart > start) start = newstart; \ |
534 | 0 | if (newend < end) end = newend; \ |
535 | 0 | } while(0) |
536 | | |
537 | | // Check each axis in turn |
538 | |
|
539 | 0 | _CALC_AXIS(imax); |
540 | | |
541 | 0 | if (absDir[imid] < std::numeric_limits<Real>::epsilon()) |
542 | 0 | { |
543 | | // Parallel with middle and minimise axis, check bounds only |
544 | 0 | if (rayorig[imid] < min[imid] || rayorig[imid] > max[imid] || |
545 | 0 | rayorig[imin] < min[imin] || rayorig[imin] > max[imin]) |
546 | 0 | return false; |
547 | 0 | } |
548 | 0 | else |
549 | 0 | { |
550 | 0 | _CALC_AXIS(imid); |
551 | | |
552 | 0 | if (absDir[imin] < std::numeric_limits<Real>::epsilon()) |
553 | 0 | { |
554 | | // Parallel with minimise axis, check bounds only |
555 | 0 | if (rayorig[imin] < min[imin] || rayorig[imin] > max[imin]) |
556 | 0 | return false; |
557 | 0 | } |
558 | 0 | else |
559 | 0 | { |
560 | 0 | _CALC_AXIS(imin); |
561 | 0 | } |
562 | 0 | } |
563 | 0 | #undef _CALC_AXIS |
564 | | |
565 | 0 | if (d1) *d1 = start; |
566 | 0 | if (d2) *d2 = end; |
567 | |
|
568 | 0 | return true; |
569 | 0 | } |
570 | | //----------------------------------------------------------------------- |
571 | | std::pair<bool, Real> Math::intersects(const Ray& ray, const Vector3& a, const Vector3& b, |
572 | | const Vector3& c, bool positiveSide, bool negativeSide) |
573 | 0 | { |
574 | 0 | const Real EPSILON = 1e-6f; |
575 | 0 | Vector3 E1 = b - a; |
576 | 0 | Vector3 E2 = c - a; |
577 | 0 | Vector3 P = ray.getDirection().crossProduct(E2); |
578 | 0 | Real det = E1.dotProduct(P); |
579 | | |
580 | | // if determinant is near zero, ray lies in plane of triangle |
581 | 0 | if((!positiveSide || det <= EPSILON) && (!negativeSide || det >= -EPSILON)) |
582 | 0 | return {false, (Real)0}; |
583 | 0 | Real inv_det = 1.0f / det; |
584 | | |
585 | | // calculate u parameter and test bounds |
586 | 0 | Vector3 T = ray.getOrigin() - a; |
587 | 0 | Real u = T.dotProduct(P) * inv_det; |
588 | 0 | if(u < 0.0f || u > 1.0f) |
589 | 0 | return {false, (Real)0}; |
590 | | |
591 | | // calculate v parameter and test bounds |
592 | 0 | Vector3 Q = T.crossProduct(E1); |
593 | 0 | Real v = ray.getDirection().dotProduct(Q) * inv_det; |
594 | 0 | if (v < 0.0f || u + v > 1.0f) |
595 | 0 | return {false, (Real)0}; |
596 | | |
597 | | // calculate t, ray intersects triangle |
598 | 0 | Real t = E2.dotProduct(Q) * inv_det; |
599 | 0 | if (t < 0.0f) |
600 | 0 | return {false, (Real)0}; |
601 | | |
602 | 0 | return {true, t}; |
603 | 0 | } |
604 | | //----------------------------------------------------------------------- |
605 | | bool Math::intersects(const Sphere& sphere, const AxisAlignedBox& box) |
606 | 0 | { |
607 | 0 | if (box.isNull()) return false; |
608 | 0 | if (box.isInfinite()) return true; |
609 | | |
610 | | // Use splitting planes |
611 | 0 | const Vector3& center = sphere.getCenter(); |
612 | 0 | Real radius = sphere.getRadius(); |
613 | 0 | const Vector3& min = box.getMinimum(); |
614 | 0 | const Vector3& max = box.getMaximum(); |
615 | | |
616 | | // Arvo's algorithm |
617 | 0 | Real s, d = 0; |
618 | 0 | for (int i = 0; i < 3; ++i) |
619 | 0 | { |
620 | 0 | if (center.ptr()[i] < min.ptr()[i]) |
621 | 0 | { |
622 | 0 | s = center.ptr()[i] - min.ptr()[i]; |
623 | 0 | d += s * s; |
624 | 0 | } |
625 | 0 | else if(center.ptr()[i] > max.ptr()[i]) |
626 | 0 | { |
627 | 0 | s = center.ptr()[i] - max.ptr()[i]; |
628 | 0 | d += s * s; |
629 | 0 | } |
630 | 0 | } |
631 | 0 | return d <= radius * radius; |
632 | |
|
633 | 0 | } |
634 | | //----------------------------------------------------------------------- |
635 | | Vector3 Math::calculateTangentSpaceVector( |
636 | | const Vector3& position1, const Vector3& position2, const Vector3& position3, |
637 | | Real u1, Real v1, Real u2, Real v2, Real u3, Real v3) |
638 | 0 | { |
639 | | //side0 is the vector along one side of the triangle of vertices passed in, |
640 | | //and side1 is the vector along another side. Taking the cross product of these returns the normal. |
641 | 0 | Vector3 side0 = position1 - position2; |
642 | 0 | Vector3 side1 = position3 - position1; |
643 | | //Calculate face normal |
644 | 0 | Vector3 normal = side1.crossProduct(side0); |
645 | 0 | normal.normalise(); |
646 | | //Now we use a formula to calculate the tangent. |
647 | 0 | Real deltaV0 = v1 - v2; |
648 | 0 | Real deltaV1 = v3 - v1; |
649 | 0 | Vector3 tangent = deltaV1 * side0 - deltaV0 * side1; |
650 | 0 | tangent.normalise(); |
651 | | //Calculate binormal |
652 | 0 | Real deltaU0 = u1 - u2; |
653 | 0 | Real deltaU1 = u3 - u1; |
654 | 0 | Vector3 binormal = deltaU1 * side0 - deltaU0 * side1; |
655 | 0 | binormal.normalise(); |
656 | | //Now, we take the cross product of the tangents to get a vector which |
657 | | //should point in the same direction as our normal calculated above. |
658 | | //If it points in the opposite direction (the dot product between the normals is less than zero), |
659 | | //then we need to reverse the s and t tangents. |
660 | | //This is because the triangle has been mirrored when going from tangent space to object space. |
661 | | //reverse tangents if necessary |
662 | 0 | Vector3 tangentCross = tangent.crossProduct(binormal); |
663 | 0 | if (tangentCross.dotProduct(normal) < 0.0f) |
664 | 0 | { |
665 | 0 | tangent = -tangent; |
666 | 0 | binormal = -binormal; |
667 | 0 | } |
668 | |
|
669 | 0 | return tangent; |
670 | |
|
671 | 0 | } |
672 | | //----------------------------------------------------------------------- |
673 | | Affine3 Math::buildReflectionMatrix(const Plane& p) |
674 | 0 | { |
675 | 0 | return Affine3( |
676 | 0 | -2 * p.normal.x * p.normal.x + 1, -2 * p.normal.x * p.normal.y, -2 * p.normal.x * p.normal.z, -2 * p.normal.x * p.d, |
677 | 0 | -2 * p.normal.y * p.normal.x, -2 * p.normal.y * p.normal.y + 1, -2 * p.normal.y * p.normal.z, -2 * p.normal.y * p.d, |
678 | 0 | -2 * p.normal.z * p.normal.x, -2 * p.normal.z * p.normal.y, -2 * p.normal.z * p.normal.z + 1, -2 * p.normal.z * p.d); |
679 | 0 | } |
680 | | //----------------------------------------------------------------------- |
681 | | Real Math::gaussianDistribution(Real x, Real offset, Real scale) |
682 | 0 | { |
683 | 0 | Real nom = Math::Exp( |
684 | 0 | -Math::Sqr(x - offset) / (2 * Math::Sqr(scale))); |
685 | 0 | Real denom = scale * Math::Sqrt(2 * Math::PI); |
686 | |
|
687 | 0 | return nom / denom; |
688 | |
|
689 | 0 | } |
690 | | //--------------------------------------------------------------------- |
691 | | Affine3 Math::makeViewMatrix(const Vector3& position, const Quaternion& orientation, |
692 | | const Affine3* reflectMatrix) |
693 | 0 | { |
694 | | // This is most efficiently done using 3x3 Matrices |
695 | 0 | Matrix3 rot; |
696 | 0 | orientation.ToRotationMatrix(rot); |
697 | | |
698 | | // Make the translation relative to new axes |
699 | 0 | Matrix3 rotT = rot.Transpose(); |
700 | 0 | Vector3 trans = -rotT * position; |
701 | | |
702 | | // Make final matrix |
703 | 0 | Affine3 viewMatrix = Affine3::IDENTITY; |
704 | 0 | viewMatrix = rotT; // fills upper 3x3 |
705 | 0 | viewMatrix[0][3] = trans.x; |
706 | 0 | viewMatrix[1][3] = trans.y; |
707 | 0 | viewMatrix[2][3] = trans.z; |
708 | | |
709 | | // Deal with reflections |
710 | 0 | if (reflectMatrix) |
711 | 0 | { |
712 | 0 | viewMatrix = viewMatrix * (*reflectMatrix); |
713 | 0 | } |
714 | |
|
715 | 0 | return viewMatrix; |
716 | |
|
717 | 0 | } |
718 | | |
719 | | Matrix4 Math::makePerspectiveMatrix(Real left, Real right, Real bottom, Real top, Real zNear, Real zFar) |
720 | 0 | { |
721 | | // The code below will dealing with general projection |
722 | | // parameters, similar glFrustum. |
723 | | // Doesn't optimise manually except division operator, so the |
724 | | // code more self-explaining. |
725 | |
|
726 | 0 | Real inv_w = 1 / (right - left); |
727 | 0 | Real inv_h = 1 / (top - bottom); |
728 | 0 | Real inv_d = 1 / (zFar - zNear); |
729 | | |
730 | | // Calc matrix elements |
731 | 0 | Real A = 2 * zNear * inv_w; |
732 | 0 | Real B = 2 * zNear * inv_h; |
733 | 0 | Real C = (right + left) * inv_w; |
734 | 0 | Real D = (top + bottom) * inv_h; |
735 | 0 | Real q, qn; |
736 | |
|
737 | 0 | if (zFar == 0) |
738 | 0 | { |
739 | | // Infinite far plane |
740 | 0 | q = Frustum::INFINITE_FAR_PLANE_ADJUST - 1; |
741 | 0 | qn = zNear * (Frustum::INFINITE_FAR_PLANE_ADJUST - 2); |
742 | 0 | } |
743 | 0 | else |
744 | 0 | { |
745 | 0 | q = - (zFar + zNear) * inv_d; |
746 | 0 | qn = -2 * (zFar * zNear) * inv_d; |
747 | 0 | } |
748 | |
|
749 | 0 | Matrix4 ret = Matrix4::ZERO; |
750 | 0 | ret[0][0] = A; |
751 | 0 | ret[0][2] = C; |
752 | 0 | ret[1][1] = B; |
753 | 0 | ret[1][2] = D; |
754 | 0 | ret[2][2] = q; |
755 | 0 | ret[2][3] = qn; |
756 | 0 | ret[3][2] = -1; |
757 | |
|
758 | 0 | return ret; |
759 | 0 | } |
760 | | //--------------------------------------------------------------------- |
761 | | Real Math::boundingRadiusFromAABB(const AxisAlignedBox& aabb) |
762 | 3.26k | { |
763 | 3.26k | const Vector3& max = aabb.getMaximum(); |
764 | 3.26k | const Vector3& min = aabb.getMinimum(); |
765 | | |
766 | 3.26k | Vector3 magnitude = max; |
767 | 3.26k | magnitude.makeCeil(-max); |
768 | 3.26k | magnitude.makeCeil(min); |
769 | 3.26k | magnitude.makeCeil(-min); |
770 | | |
771 | 3.26k | return magnitude.length(); |
772 | 3.26k | } |
773 | | |
774 | | Real Math::boundingRadiusFromAABBCentered(const AxisAlignedBox& aabb) |
775 | 0 | { |
776 | 0 | const Vector3& max = aabb.getMaximum(); |
777 | 0 | const Vector3& min = aabb.getMinimum(); |
778 | |
|
779 | 0 | return ((min - max) * 0.5f).length(); |
780 | 0 | } |
781 | | |
782 | 0 | std::ostream& operator<<(std::ostream& o, const Radian& v) { return o << "Radian(" << v.valueRadians() << ")"; } |
783 | 0 | std::ostream& operator<<(std::ostream& o, const Degree& v) { return o << "Degree(" << v.valueDegrees() << ")"; } |
784 | | } |