Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreMath.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

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