source: OGRE/trunk/ogrenew/OgreMain/src/OgreMath.cpp @ 692

Revision 692, 31.6 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26
27#include "OgreMath.h"
28#include "asm_math.h"
29#include "OgreVector2.h"
30#include "OgreVector3.h"
31#include "OgreVector4.h"
32#include "OgreRay.h"
33#include "OgreSphere.h"
34#include "OgreAxisAlignedBox.h"
35#include "OgrePlane.h"
36
37
38namespace Ogre
39{
40
41    const Real Math::POS_INFINITY = std::numeric_limits<Real>::infinity();
42    const Real Math::NEG_INFINITY = -std::numeric_limits<Real>::infinity();
43    const Real Math::PI = Real( 4.0 * atan( 1.0 ) );
44    const Real Math::TWO_PI = Real( 2.0 * PI );
45    const Real Math::HALF_PI = Real( 0.5 * PI );
46        const Real Math::fDeg2Rad = PI / Real(180.0);
47        const Real Math::fRad2Deg = Real(180.0) / PI;
48
49    int Math::mTrigTableSize;
50   Math::AngleUnit Math::msAngleUnit;
51
52    Real  Math::mTrigTableFactor;
53    Real *Math::mSinTable = NULL;
54    Real *Math::mTanTable = NULL;
55
56    //-----------------------------------------------------------------------
57    Math::Math( unsigned int trigTableSize )
58    {
59        msAngleUnit = AU_DEGREE;
60
61        mTrigTableSize = trigTableSize;
62        mTrigTableFactor = mTrigTableSize / Math::TWO_PI;
63
64        mSinTable = new Real[mTrigTableSize];
65        mTanTable = new Real[mTrigTableSize];
66
67        buildTrigTables();
68    }
69
70    //-----------------------------------------------------------------------
71    Math::~Math()
72    {
73        delete [] mSinTable;
74        delete [] mTanTable;
75    }
76
77    //-----------------------------------------------------------------------
78    void Math::buildTrigTables(void)
79    {
80        // Build trig lookup tables
81        // Could get away with building only PI sized Sin table but simpler this
82        // way. Who cares, it'll ony use an extra 8k of memory anyway and I like
83        // simplicity.
84        Real angle;
85        for (int i = 0; i < mTrigTableSize; ++i)
86        {
87            angle = Math::TWO_PI * i / mTrigTableSize;
88            mSinTable[i] = sin(angle);
89            mTanTable[i] = tan(angle);
90        }
91    }
92        //-----------------------------------------------------------------------       
93        Real Math::SinTable (Real fValue)
94    {
95        // Convert range to index values, wrap if required
96        int idx;
97        if (fValue >= 0)
98        {
99            idx = int(fValue * mTrigTableFactor) % mTrigTableSize;
100        }
101        else
102        {
103            idx = mTrigTableSize - (int(-fValue * mTrigTableFactor) % mTrigTableSize) - 1;
104        }
105
106        return mSinTable[idx];
107    }
108        //-----------------------------------------------------------------------
109        Real Math::TanTable (Real fValue)
110    {
111        // Convert range to index values, wrap if required
112                int idx = int(fValue *= mTrigTableFactor) % mTrigTableSize;
113                return mTanTable[idx];
114    }
115    //-----------------------------------------------------------------------
116    int Math::ISign (int iValue)
117    {
118        return ( iValue > 0 ? +1 : ( iValue < 0 ? -1 : 0 ) );
119    }
120    //-----------------------------------------------------------------------
121    Radian Math::ACos (Real fValue)
122    {
123        if ( -1.0 < fValue )
124        {
125            if ( fValue < 1.0 )
126                return Radian(acos(fValue));
127            else
128                return Radian(0.0);
129        }
130        else
131        {
132            return Radian(PI);
133        }
134    }
135    //-----------------------------------------------------------------------
136    Radian Math::ASin (Real fValue)
137    {
138        if ( -1.0 < fValue )
139        {
140            if ( fValue < 1.0 )
141                return Radian(asin(fValue));
142            else
143                return Radian(HALF_PI);
144        }
145        else
146        {
147            return Radian(-HALF_PI);
148        }
149    }
150    //-----------------------------------------------------------------------
151    Real Math::Sign (Real fValue)
152    {
153        if ( fValue > 0.0 )
154            return 1.0;
155
156        if ( fValue < 0.0 )
157            return -1.0;
158
159        return 0.0;
160    }
161        //-----------------------------------------------------------------------
162        Real Math::InvSqrt(Real fValue)
163        {
164                return Real(asm_rsq(fValue));
165        }
166    //-----------------------------------------------------------------------
167    Real Math::UnitRandom ()
168    {
169        return asm_rand() / asm_rand_max();
170    }
171   
172    //-----------------------------------------------------------------------
173    Real Math::RangeRandom (Real fLow, Real fHigh)
174    {
175        return (fHigh-fLow)*UnitRandom() + fLow;
176    }
177
178    //-----------------------------------------------------------------------
179    Real Math::SymmetricRandom ()
180    {
181                return 2.0f * UnitRandom() - 1.0f;
182    }
183
184   //-----------------------------------------------------------------------
185    void Math::setAngleUnit(Math::AngleUnit unit)
186   {
187       msAngleUnit = unit;
188   }
189   //-----------------------------------------------------------------------
190   Math::AngleUnit Math::getAngleUnit(void)
191   {
192       return msAngleUnit;
193   }
194    //-----------------------------------------------------------------------
195    Real Math::AngleUnitsToRadians(Real angleunits)
196    {
197       if (msAngleUnit == AU_DEGREE)
198           return angleunits * fDeg2Rad;
199       else
200           return angleunits;
201    }
202
203    //-----------------------------------------------------------------------
204    Real Math::RadiansToAngleUnits(Real radians)
205    {
206       if (msAngleUnit == AU_DEGREE)
207           return radians * fRad2Deg;
208       else
209           return radians;
210    }
211
212    //-----------------------------------------------------------------------
213    Real Math::AngleUnitsToDegrees(Real angleunits)
214    {
215       if (msAngleUnit == AU_RADIAN)
216           return angleunits * fRad2Deg;
217       else
218           return angleunits;
219    }
220
221    //-----------------------------------------------------------------------
222    Real Math::DegreesToAngleUnits(Real degrees)
223    {
224       if (msAngleUnit == AU_RADIAN)
225           return degrees * fDeg2Rad;
226       else
227           return degrees;
228    }
229
230    //-----------------------------------------------------------------------
231        bool Math::pointInTri2D(const Vector2& p, const Vector2& a,
232                const Vector2& b, const Vector2& c)
233    {
234                // Winding must be consistent from all edges for point to be inside
235                Vector2 v1, v2;
236                Real dot[3];
237                bool zeroDot[3];
238
239                v1 = b - a;
240                v2 = p - a;
241
242                // Note we don't care about normalisation here since sign is all we need
243                // It means we don't have to worry about magnitude of cross products either
244                dot[0] = v1.crossProduct(v2);
245                zeroDot[0] = Math::RealEqual(dot[0], 0.0f, 1e-3);
246
247
248                v1 = c - b;
249                v2 = p - b;
250
251                dot[1] = v1.crossProduct(v2);
252                zeroDot[1] = Math::RealEqual(dot[1], 0.0f, 1e-3);
253
254                // Compare signs (ignore colinear / coincident points)
255                if(!zeroDot[0] && !zeroDot[1]
256                && Math::Sign(dot[0]) != Math::Sign(dot[1]))
257                {
258                        return false;
259                }
260
261                v1 = a - c;
262                v2 = p - c;
263
264                dot[2] = v1.crossProduct(v2);
265                zeroDot[2] = Math::RealEqual(dot[2], 0.0f, 1e-3);
266                // Compare signs (ignore colinear / coincident points)
267                if((!zeroDot[0] && !zeroDot[2]
268                        && Math::Sign(dot[0]) != Math::Sign(dot[2])) ||
269                        (!zeroDot[1] && !zeroDot[2]
270                        && Math::Sign(dot[1]) != Math::Sign(dot[2])))
271                {
272                        return false;
273                }
274
275
276                return true;
277    }
278        //-----------------------------------------------------------------------
279        bool Math::pointInTri3D(const Vector3& p, const Vector3& a,
280                const Vector3& b, const Vector3& c, const Vector3& normal)
281        {
282        // Winding must be consistent from all edges for point to be inside
283                Vector3 v1, v2;
284                Real dot[3];
285                bool zeroDot[3];
286
287        v1 = b - a;
288        v2 = p - a;
289
290                // Note we don't care about normalisation here since sign is all we need
291                // It means we don't have to worry about magnitude of cross products either
292        dot[0] = v1.crossProduct(v2).dotProduct(normal);
293                zeroDot[0] = Math::RealEqual(dot[0], 0.0f, 1e-3);
294
295
296        v1 = c - b;
297        v2 = p - b;
298
299                dot[1] = v1.crossProduct(v2).dotProduct(normal);
300                zeroDot[1] = Math::RealEqual(dot[1], 0.0f, 1e-3);
301
302                // Compare signs (ignore colinear / coincident points)
303                if(!zeroDot[0] && !zeroDot[1]
304                        && Math::Sign(dot[0]) != Math::Sign(dot[1]))
305                {
306            return false;
307                }
308
309        v1 = a - c;
310        v2 = p - c;
311
312                dot[2] = v1.crossProduct(v2).dotProduct(normal);
313                zeroDot[2] = Math::RealEqual(dot[2], 0.0f, 1e-3);
314                // Compare signs (ignore colinear / coincident points)
315                if((!zeroDot[0] && !zeroDot[2]
316                        && Math::Sign(dot[0]) != Math::Sign(dot[2])) ||
317                        (!zeroDot[1] && !zeroDot[2]
318                        && Math::Sign(dot[1]) != Math::Sign(dot[2])))
319                {
320                        return false;
321                }
322
323
324        return true;
325        }
326    //-----------------------------------------------------------------------
327    bool Math::RealEqual( Real a, Real b, Real tolerance )
328    {
329        if (fabs(b-a) <= tolerance)
330            return true;
331        else
332            return false;
333    }
334
335    //-----------------------------------------------------------------------
336    std::pair<bool, Real> Math::intersects(const Ray& ray, const Plane& plane)
337    {
338
339        Real denom = plane.normal.dotProduct(ray.getDirection());
340        if (Math::Abs(denom) < std::numeric_limits<Real>::epsilon())
341        {
342            // Parallel
343            return std::pair<bool, Real>(false, 0);
344        }
345        else
346        {
347            Real nom = plane.normal.dotProduct(ray.getOrigin()) + plane.d;
348            Real t = -(nom/denom);
349            return std::pair<bool, Real>(t >= 0, t);
350        }
351       
352    }
353    //-----------------------------------------------------------------------
354    std::pair<bool, Real> Math::intersects(const Ray& ray,
355        const std::vector<Plane>& planes, bool normalIsOutside)
356    {
357        std::vector<Plane>::const_iterator planeit, planeitend;
358        planeitend = planes.end();
359        bool allInside = true;
360        std::pair<bool, Real> ret;
361        ret.first = false;
362        ret.second = 0.0f;
363
364        // derive side
365        // NB we don't pass directly since that would require Plane::Side in
366        // interface, which results in recursive includes since Math is so fundamental
367        Plane::Side outside = normalIsOutside ? Plane::POSITIVE_SIDE : Plane::NEGATIVE_SIDE;
368
369        for (planeit = planes.begin(); planeit != planeitend; ++planeit)
370        {
371            const Plane& plane = *planeit;
372            // is origin outside?
373            if (plane.getSide(ray.getOrigin()) == outside)
374            {
375                allInside = false;
376                // Test single plane
377                std::pair<bool, Real> planeRes =
378                    ray.intersects(plane);
379                if (planeRes.first)
380                {
381                    // Ok, we intersected
382                    ret.first = true;
383                    // Use the most distant result since convex volume
384                    ret.second = std::max(ret.second, planeRes.second);
385                }
386            }
387        }
388
389        if (allInside)
390        {
391            // Intersecting at 0 distance since inside the volume!
392            ret.first = true;
393            ret.second = 0.0f;
394        }
395
396        return ret;
397    }
398    //-----------------------------------------------------------------------
399    std::pair<bool, Real> Math::intersects(const Ray& ray,
400        const std::list<Plane>& planes, bool normalIsOutside)
401    {
402        std::list<Plane>::const_iterator planeit, planeitend;
403        planeitend = planes.end();
404        bool allInside = true;
405        std::pair<bool, Real> ret;
406        ret.first = false;
407        ret.second = 0.0f;
408
409        // derive side
410        // NB we don't pass directly since that would require Plane::Side in
411        // interface, which results in recursive includes since Math is so fundamental
412        Plane::Side outside = normalIsOutside ? Plane::POSITIVE_SIDE : Plane::NEGATIVE_SIDE;
413
414        for (planeit = planes.begin(); planeit != planeitend; ++planeit)
415        {
416            const Plane& plane = *planeit;
417            // is origin outside?
418            if (plane.getSide(ray.getOrigin()) == outside)
419            {
420                allInside = false;
421                // Test single plane
422                std::pair<bool, Real> planeRes =
423                    ray.intersects(plane);
424                if (planeRes.first)
425                {
426                    // Ok, we intersected
427                    ret.first = true;
428                    // Use the most distant result since convex volume
429                    ret.second = std::max(ret.second, planeRes.second);
430                }
431            }
432        }
433
434        if (allInside)
435        {
436            // Intersecting at 0 distance since inside the volume!
437            ret.first = true;
438            ret.second = 0.0f;
439        }
440
441        return ret;
442    }
443    //-----------------------------------------------------------------------
444    std::pair<bool, Real> Math::intersects(const Ray& ray, const Sphere& sphere,
445        bool discardInside)
446    {
447        const Vector3& raydir = ray.getDirection();
448        // Adjust ray origin relative to sphere center
449        const Vector3& rayorig = ray.getOrigin() - sphere.getCenter();
450        Real radius = sphere.getRadius();
451
452        // Check origin inside first
453        if (rayorig.squaredLength() <= radius*radius && discardInside)
454        {
455            return std::pair<bool, Real>(true, 0);
456        }
457
458        // Mmm, quadratics
459        // Build coeffs which can be used with std quadratic solver
460        // ie t = (-b +/- sqrt(b*b + 4ac)) / 2a
461        Real a = raydir.dotProduct(raydir);
462        Real b = 2 * rayorig.dotProduct(raydir);
463        Real c = rayorig.dotProduct(rayorig) - radius*radius;
464
465        // Calc determinant
466        Real d = (b*b) - (4 * a * c);
467        if (d < 0)
468        {
469            // No intersection
470            return std::pair<bool, Real>(false, 0);
471        }
472        else
473        {
474            // BTW, if d=0 there is one intersection, if d > 0 there are 2
475            // But we only want the closest one, so that's ok, just use the
476            // '-' version of the solver
477            Real t = ( -b - Math::Sqrt(d) ) / (2 * a);
478            if (t < 0)
479                t = ( -b + Math::Sqrt(d) ) / (2 * a);
480            return std::pair<bool, Real>(true, t);
481        }
482
483
484    }
485    //-----------------------------------------------------------------------
486    std::pair<bool, Real> Math::intersects(const Ray& ray, const AxisAlignedBox& box)
487    {
488        if (box.isNull()) return std::pair<bool, Real>(false, 0);
489
490        Real lowt = 0.0f;
491        Real t;
492        bool hit = false;
493        Vector3 hitpoint;
494        const Vector3& min = box.getMinimum();
495        const Vector3& max = box.getMaximum();
496        const Vector3& rayorig = ray.getOrigin();
497        const Vector3& raydir = ray.getDirection();
498
499        // Check origin inside first
500        if ( rayorig > min && rayorig < max )
501        {
502            return std::pair<bool, Real>(true, 0);
503        }
504
505        // Check each face in turn, only check closest 3
506        // Min x
507        if (rayorig.x < min.x && raydir.x > 0)
508        {
509            t = (min.x - rayorig.x) / raydir.x;
510            if (t > 0)
511            {
512                // Substitute t back into ray and check bounds and dist
513                hitpoint = rayorig + raydir * t;
514                if (hitpoint.y >= min.y && hitpoint.y <= max.y &&
515                    hitpoint.z >= min.z && hitpoint.z <= max.z &&
516                    (!hit || t < lowt))
517                {
518                    hit = true;
519                    lowt = t;
520                }
521            }
522        }
523        // Max x
524        if (rayorig.x > max.x && raydir.x < 0)
525        {
526            t = (max.x - rayorig.x) / raydir.x;
527            if (t > 0)
528            {
529                // Substitute t back into ray and check bounds and dist
530                hitpoint = rayorig + raydir * t;
531                if (hitpoint.y >= min.y && hitpoint.y <= max.y &&
532                    hitpoint.z >= min.z && hitpoint.z <= max.z &&
533                    (!hit || t < lowt))
534                {
535                    hit = true;
536                    lowt = t;
537                }
538            }
539        }
540        // Min y
541        if (rayorig.y < min.y && raydir.y > 0)
542        {
543            t = (min.y - rayorig.y) / raydir.y;
544            if (t > 0)
545            {
546                // Substitute t back into ray and check bounds and dist
547                hitpoint = rayorig + raydir * t;
548                if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
549                    hitpoint.z >= min.z && hitpoint.z <= max.z &&
550                    (!hit || t < lowt))
551                {
552                    hit = true;
553                    lowt = t;
554                }
555            }
556        }
557        // Max y
558        if (rayorig.y > max.y && raydir.y < 0)
559        {
560            t = (max.y - rayorig.y) / raydir.y;
561            if (t > 0)
562            {
563                // Substitute t back into ray and check bounds and dist
564                hitpoint = rayorig + raydir * t;
565                if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
566                    hitpoint.z >= min.z && hitpoint.z <= max.z &&
567                    (!hit || t < lowt))
568                {
569                    hit = true;
570                    lowt = t;
571                }
572            }
573        }
574        // Min z
575        if (rayorig.z < min.z && raydir.z > 0)
576        {
577            t = (min.z - rayorig.z) / raydir.z;
578            if (t > 0)
579            {
580                // Substitute t back into ray and check bounds and dist
581                hitpoint = rayorig + raydir * t;
582                if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
583                    hitpoint.y >= min.y && hitpoint.y <= max.y &&
584                    (!hit || t < lowt))
585                {
586                    hit = true;
587                    lowt = t;
588                }
589            }
590        }
591        // Max z
592        if (rayorig.z > max.z && raydir.z < 0)
593        {
594            t = (max.z - rayorig.z) / raydir.z;
595            if (t > 0)
596            {
597                // Substitute t back into ray and check bounds and dist
598                hitpoint = rayorig + raydir * t;
599                if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
600                    hitpoint.y >= min.y && hitpoint.y <= max.y &&
601                    (!hit || t < lowt))
602                {
603                    hit = true;
604                    lowt = t;
605                }
606            }
607        }
608
609        return std::pair<bool, Real>(hit, lowt);
610
611    }
612    //-----------------------------------------------------------------------
613    bool Math::intersects(const Ray& ray, const AxisAlignedBox& box,
614        Real* d1, Real* d2)
615    {
616        if (box.isNull())
617            return false;
618
619        const Vector3& min = box.getMinimum();
620        const Vector3& max = box.getMaximum();
621        const Vector3& rayorig = ray.getOrigin();
622        const Vector3& raydir = ray.getDirection();
623
624        Vector3 absDir;
625        absDir[0] = Math::Abs(raydir[0]);
626        absDir[1] = Math::Abs(raydir[1]);
627        absDir[2] = Math::Abs(raydir[2]);
628
629        // Sort the axis, ensure check minimise floating error axis first
630        int imax = 0, imid = 1, imin = 2;
631        if (absDir[0] < absDir[2])
632        {
633            imax = 2;
634            imin = 0;
635        }
636        if (absDir[1] < absDir[imin])
637        {
638            imid = imin;
639            imin = 1;
640        }
641        else if (absDir[1] > absDir[imax])
642        {
643            imid = imax;
644            imax = 1;
645        }
646
647        Real start = 0, end = Math::POS_INFINITY;
648
649#define _CALC_AXIS(i)                                       \
650    do {                                                    \
651        Real denom = 1 / raydir[i];                         \
652        Real newstart = (min[i] - rayorig[i]) * denom;      \
653        Real newend = (max[i] - rayorig[i]) * denom;        \
654        if (newstart > newend) std::swap(newstart, newend); \
655        if (newstart > end || newend < start) return false; \
656        if (newstart > start) start = newstart;             \
657        if (newend < end) end = newend;                     \
658    } while(0)
659
660        // Check each axis in turn
661
662        _CALC_AXIS(imax);
663
664        if (absDir[imid] < std::numeric_limits<Real>::epsilon())
665        {
666            // Parallel with middle and minimise axis, check bounds only
667            if (rayorig[imid] < min[imid] || rayorig[imid] > max[imid] ||
668                rayorig[imin] < min[imin] || rayorig[imin] > max[imin])
669                return false;
670        }
671        else
672        {
673            _CALC_AXIS(imid);
674
675            if (absDir[imin] < std::numeric_limits<Real>::epsilon())
676            {
677                // Parallel with minimise axis, check bounds only
678                if (rayorig[imin] < min[imin] || rayorig[imin] > max[imin])
679                    return false;
680            }
681            else
682            {
683                _CALC_AXIS(imin);
684            }
685        }
686#undef _CALC_AXIS
687
688        if (d1) *d1 = start;
689        if (d2) *d2 = end;
690
691        return true;
692    }
693    //-----------------------------------------------------------------------
694    std::pair<bool, Real> Math::intersects(const Ray& ray, const Vector3& a,
695        const Vector3& b, const Vector3& c, const Vector3& normal,
696        bool positiveSide, bool negativeSide)
697    {
698        //
699        // Calculate intersection with plane.
700        //
701        Real t;
702        {
703            Real denom = normal.dotProduct(ray.getDirection());
704
705            // Check intersect side
706            if (denom > + std::numeric_limits<Real>::epsilon())
707            {
708                if (!negativeSide)
709                    return std::pair<bool, Real>(false, 0);
710            }
711            else if (denom < - std::numeric_limits<Real>::epsilon())
712            {
713                if (!positiveSide)
714                    return std::pair<bool, Real>(false, 0);
715            }
716            else
717            {
718                // Parallel or triangle area is close to zero when
719                // the plane normal not normalised.
720                return std::pair<bool, Real>(false, 0);
721            }
722
723            t = normal.dotProduct(a - ray.getOrigin()) / denom;
724
725            if (t < 0)
726            {
727                // Intersection is behind origin
728                return std::pair<bool, Real>(false, 0);
729            }
730        }
731
732        //
733        // Calculate the largest area projection plane in X, Y or Z.
734        //
735        size_t i0, i1;
736        {
737            Real n0 = Math::Abs(normal[0]);
738            Real n1 = Math::Abs(normal[1]);
739            Real n2 = Math::Abs(normal[2]);
740
741            i0 = 1; i1 = 2;
742            if (n1 > n2)
743            {
744                if (n1 > n0) i0 = 0;
745            }
746            else
747            {
748                if (n2 > n0) i1 = 0;
749            }
750        }
751
752        //
753        // Check the intersection point is inside the triangle.
754        //
755        {
756            Real u1 = b[i0] - a[i0];
757            Real v1 = b[i1] - a[i1];
758            Real u2 = c[i0] - a[i0];
759            Real v2 = c[i1] - a[i1];
760            Real u0 = t * ray.getDirection()[i0] + ray.getOrigin()[i0] - a[i0];
761            Real v0 = t * ray.getDirection()[i1] + ray.getOrigin()[i1] - a[i1];
762
763            Real alpha = u0 * v2 - u2 * v0;
764            Real beta  = u1 * v0 - u0 * v1;
765            Real area  = u1 * v2 - u2 * v1;
766
767            // epsilon to avoid float precision error
768            const Real EPSILON = 1e-3f;
769
770            Real tolerance = - EPSILON * area;
771
772            if (area > 0)
773            {
774                if (alpha < tolerance || beta < tolerance || alpha+beta > area-tolerance)
775                    return std::pair<bool, Real>(false, 0);
776            }
777            else
778            {
779                if (alpha > tolerance || beta > tolerance || alpha+beta < area-tolerance)
780                    return std::pair<bool, Real>(false, 0);
781            }
782        }
783
784        return std::pair<bool, Real>(true, t);
785    }
786    //-----------------------------------------------------------------------
787    std::pair<bool, Real> Math::intersects(const Ray& ray, const Vector3& a,
788        const Vector3& b, const Vector3& c,
789        bool positiveSide, bool negativeSide)
790    {
791        Vector3 normal = calculateBasicFaceNormalWithoutNormalize(a, b, c);
792        return intersects(ray, a, b, c, normal, positiveSide, negativeSide);
793    }
794    //-----------------------------------------------------------------------
795    bool Math::intersects(const Sphere& sphere, const AxisAlignedBox& box)
796    {
797        if (box.isNull()) return false;
798
799        // Use splitting planes
800        const Vector3& center = sphere.getCenter();
801        Real radius = sphere.getRadius();
802        const Vector3& min = box.getMinimum();
803        const Vector3& max = box.getMaximum();
804
805        // just test facing planes, early fail if sphere is totally outside
806        if (center.x < min.x &&
807            min.x - center.x > radius)
808        {
809            return false;
810        }
811        if (center.x > max.x &&
812            center.x  - max.x > radius)
813        {
814            return false;
815        }
816
817        if (center.y < min.y &&
818            min.y - center.y > radius)
819        {
820            return false;
821        }
822        if (center.y > max.y &&
823            center.y  - max.y > radius)
824        {
825            return false;
826        }
827
828        if (center.z < min.z &&
829            min.z - center.z > radius)
830        {
831            return false;
832        }
833        if (center.z > max.z &&
834            center.z  - max.z > radius)
835        {
836            return false;
837        }
838
839        // Must intersect
840        return true;
841
842    }
843    //-----------------------------------------------------------------------
844    bool Math::intersects(const Plane& plane, const AxisAlignedBox& box)
845    {
846        if (box.isNull()) return false;
847
848        // Get corners of the box
849        const Vector3* pCorners = box.getAllCorners();
850
851
852        // Test which side of the plane the corners are
853        // Intersection occurs when at least one corner is on the
854        // opposite side to another
855        Plane::Side lastSide = plane.getSide(pCorners[0]);
856        for (int corner = 1; corner < 8; ++corner)
857        {
858            if (plane.getSide(pCorners[corner]) != lastSide)
859            {
860                return true;
861            }
862        }
863
864        return false;
865    }
866    //-----------------------------------------------------------------------
867    bool Math::intersects(const Sphere& sphere, const Plane& plane)
868    {
869        return (
870            Math::Abs(plane.normal.dotProduct(sphere.getCenter()))
871            <= sphere.getRadius() );
872    }
873    //-----------------------------------------------------------------------
874    Vector3 Math::calculateTangentSpaceVector(
875        const Vector3& position1, const Vector3& position2, const Vector3& position3,
876        Real u1, Real v1, Real u2, Real v2, Real u3, Real v3)
877    {
878            //side0 is the vector along one side of the triangle of vertices passed in,
879            //and side1 is the vector along another side. Taking the cross product of these returns the normal.
880            Vector3 side0 = position1 - position2;
881            Vector3 side1 = position3 - position1;
882            //Calculate face normal
883            Vector3 normal = side1.crossProduct(side0);
884            normal.normalise();
885            //Now we use a formula to calculate the tangent.
886            Real deltaV0 = v1 - v2;
887            Real deltaV1 = v3 - v1;
888            Vector3 tangent = deltaV1 * side0 - deltaV0 * side1;
889            tangent.normalise();
890            //Calculate binormal
891            Real deltaU0 = u1 - u2;
892            Real deltaU1 = u3 - u1;
893            Vector3 binormal = deltaU1 * side0 - deltaU0 * side1;
894            binormal.normalise();
895            //Now, we take the cross product of the tangents to get a vector which
896            //should point in the same direction as our normal calculated above.
897            //If it points in the opposite direction (the dot product between the normals is less than zero),
898            //then we need to reverse the s and t tangents.
899            //This is because the triangle has been mirrored when going from tangent space to object space.
900            //reverse tangents if necessary
901            Vector3 tangentCross = tangent.crossProduct(binormal);
902            if (tangentCross.dotProduct(normal) < 0.0f)
903            {
904                    tangent = -tangent;
905                    binormal = -binormal;
906            }
907
908        return tangent;
909
910    }
911    //-----------------------------------------------------------------------
912    Matrix4 Math::buildReflectionMatrix(const Plane& p)
913    {
914        return Matrix4(
915            -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,
916            -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,
917            -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,
918            0,                                  0,                                  0,                                  1);
919    }
920    //-----------------------------------------------------------------------
921    Vector4 Math::calculateFaceNormal(const Vector3& v1, const Vector3& v2, const Vector3& v3)
922    {
923        Vector3 normal = calculateBasicFaceNormal(v1, v2, v3);
924        // Now set up the w (distance of tri from origin
925        return Vector4(normal.x, normal.y, normal.z, -(normal.dotProduct(v1)));
926    }
927    //-----------------------------------------------------------------------
928    Vector3 Math::calculateBasicFaceNormal(const Vector3& v1, const Vector3& v2, const Vector3& v3)
929    {
930        Vector3 normal = (v2 - v1).crossProduct(v3 - v1);
931        normal.normalise();
932        return normal;
933    }
934    //-----------------------------------------------------------------------
935    Vector4 Math::calculateFaceNormalWithoutNormalize(const Vector3& v1, const Vector3& v2, const Vector3& v3)
936    {
937        Vector3 normal = calculateBasicFaceNormalWithoutNormalize(v1, v2, v3);
938        // Now set up the w (distance of tri from origin)
939        return Vector4(normal.x, normal.y, normal.z, -(normal.dotProduct(v1)));
940    }
941    //-----------------------------------------------------------------------
942    Vector3 Math::calculateBasicFaceNormalWithoutNormalize(const Vector3& v1, const Vector3& v2, const Vector3& v3)
943    {
944        Vector3 normal = (v2 - v1).crossProduct(v3 - v1);
945        return normal;
946    }
947}
Note: See TracBrowser for help on using the repository browser.