mBox.cpp

Engine/source/math/mBox.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "math/mMatrix.h"
 25#include "math/mSphere.h"
 26
 27
 28const Box3F Box3F::Invalid( F32_MAX, F32_MAX, F32_MAX, -F32_MAX, -F32_MAX, -F32_MAX );
 29const Box3F Box3F::Max( -F32_MAX, -F32_MAX, -F32_MAX, F32_MAX, F32_MAX, F32_MAX );
 30const Box3F Box3F::Zero( 0, 0, 0, 0, 0, 0 );
 31
 32
 33//-----------------------------------------------------------------------------
 34
 35bool Box3F::isOverlapped( const SphereF& sphere ) const
 36{
 37   // Algorithm: Real-Time Rendering, Ed. 1, p323, 10.10.1 Sphere/Box Intersection
 38
 39   F32 d = 0;
 40   for( U32 i = 0; i < 3; ++ i )
 41      if( sphere.center[ i ] < minExtents[ i ] )
 42         d = d + mSquared( sphere.center[ i ] - minExtents[ i ] );
 43      else if( sphere.center[ i ] > maxExtents[ i ] )
 44         d = d + mSquared( sphere.center[ i ] - maxExtents[ i ] );
 45
 46   return !( d > mSquared( sphere.radius ) );
 47}
 48
 49//-----------------------------------------------------------------------------
 50
 51bool Box3F::collideLine(const Point3F& start, const Point3F& end, F32* t, Point3F* n) const
 52{
 53   // Collide against bounding box. Need at least this for the editor.
 54   F32 st,et;
 55   F32 fst = 0;
 56   F32 fet = 1;
 57   const F32* bmin = &minExtents.x;
 58   const F32* bmax = &maxExtents.x;
 59   const F32* si   = &start.x;
 60   const F32* ei   = &end.x;
 61
 62   static const Point3F na[3] = { Point3F(1.0f, 0.0f, 0.0f), Point3F(0.0f, 1.0f, 0.0f), Point3F(0.0f, 0.0f, 1.0f) };
 63   Point3F finalNormal(0.0f, 0.0f, 0.0f);
 64
 65   for (S32 i = 0; i < 3; i++) {
 66     bool   n_neg = false;
 67      if (si[i] < ei[i]) {
 68         if (si[i] > bmax[i] || ei[i] < bmin[i])
 69            return false;
 70         F32 di = ei[i] - si[i];
 71         st = (si[i] < bmin[i]) ? (bmin[i] - si[i]) / di : 0.0f;
 72         et = (ei[i] > bmax[i]) ? (bmax[i] - si[i]) / di : 1.0f;
 73       n_neg = true;
 74      }
 75      else {
 76         if (ei[i] > bmax[i] || si[i] < bmin[i])
 77            return false;
 78         F32 di = ei[i] - si[i];
 79         st = (si[i] > bmax[i]) ? (bmax[i] - si[i]) / di : 0.0f;
 80         et = (ei[i] < bmin[i]) ? (bmin[i] - si[i]) / di : 1.0f;
 81      }
 82      if (st > fst) {
 83         fst = st;
 84       finalNormal = na[i];
 85       if ( n_neg )
 86         finalNormal.neg();
 87      }
 88      if (et < fet)
 89         fet = et;
 90
 91      if (fet < fst)
 92         return false;
 93   }
 94
 95   *t = fst;
 96   *n = finalNormal;
 97   return true;
 98}
 99
100//-----------------------------------------------------------------------------
101
102bool Box3F::collideLine(const Point3F& start, const Point3F& end) const
103{
104   F32 t;
105   Point3F normal;
106   return collideLine(start, end, &t, &normal);
107}
108
109//-----------------------------------------------------------------------------
110
111bool Box3F::collideOrientedBox(const Point3F & bRadii, const MatrixF & toA) const
112{
113   Point3F p;
114   toA.getColumn(3,&p);
115   Point3F aCenter = minExtents + maxExtents;
116   aCenter *= 0.5f;
117   p -= aCenter; // this essentially puts origin of toA target space on the center of the current box
118   Point3F aRadii = maxExtents - minExtents;
119   aRadii *= 0.5f;
120
121   F32 absXX,absXY,absXZ;
122   F32 absYX,absYY,absYZ;
123   F32 absZX,absZY,absZZ;
124
125   const F32 * f = toA;
126
127   absXX = mFabs(f[0]);
128   absYX = mFabs(f[1]);
129   absZX = mFabs(f[2]);
130
131   if (aRadii.x + bRadii.x * absXX + bRadii.y * absYX + bRadii.z * absZX - mFabs(p.x)<0.0f)
132      return false;
133
134   absXY = mFabs(f[4]);
135   absYY = mFabs(f[5]);
136   absZY = mFabs(f[6]);
137   if (aRadii.y + bRadii.x * absXY +   bRadii.y * absYY +   bRadii.z * absZY - mFabs(p.y)<0.0f)
138      return false;
139   
140   absXZ = mFabs(f[8]);
141   absYZ = mFabs(f[9]);
142   absZZ = mFabs(f[10]);
143   if (aRadii.z + bRadii.x * absXZ + bRadii.y * absYZ +  bRadii.z * absZZ - mFabs(p.z)<0.0f)
144      return false;
145
146   if (aRadii.x*absXX + aRadii.y*absXY + aRadii.z*absXZ + bRadii.x - mFabs(p.x*f[0] + p.y*f[4] + p.z*f[8])<0.0f)
147      return false;
148
149   if (aRadii.x*absYX + aRadii.y*absYY + aRadii.z*absYZ + bRadii.y - mFabs(p.x*f[1] + p.y*f[5] + p.z*f[9])<0.0f)
150      return false;     
151   
152   if (aRadii.x*absZX + aRadii.y*absZY + aRadii.z*absZZ + bRadii.z - mFabs(p.x*f[2] + p.y*f[6] + p.z*f[10])<0.0f)
153      return false;     
154   
155   if (mFabs(p.z*f[4] - p.y*f[8]) >
156            aRadii.y * absXZ + aRadii.z * absXY +
157            bRadii.y * absZX + bRadii.z * absYX)
158      return false;
159   
160   if (mFabs(p.z*f[5] - p.y*f[9]) >
161            aRadii.y * absYZ + aRadii.z * absYY +
162            bRadii.x * absZX + bRadii.z * absXX)
163      return false;
164   
165   if (mFabs(p.z*f[6] - p.y*f[10]) >
166            aRadii.y * absZZ + aRadii.z * absZY +
167            bRadii.x * absYX + bRadii.y * absXX)
168      return false;
169   
170   if (mFabs(p.x*f[8] - p.z*f[0]) >
171            aRadii.x * absXZ + aRadii.z * absXX +
172            bRadii.y * absZY + bRadii.z * absYY)
173      return false;
174   
175   if (mFabs(p.x*f[9] - p.z*f[1]) >
176            aRadii.x * absYZ + aRadii.z * absYX +
177            bRadii.x * absZY + bRadii.z * absXY)
178      return false;
179   
180   if (mFabs(p.x*f[10] - p.z*f[2]) >
181            aRadii.x * absZZ + aRadii.z * absZX +
182            bRadii.x * absYY + bRadii.y * absXY)
183      return false;
184   
185   if (mFabs(p.y*f[0] - p.x*f[4]) >
186            aRadii.x * absXY + aRadii.y * absXX +
187            bRadii.y * absZZ + bRadii.z * absYZ)
188      return false;
189   
190   if (mFabs(p.y*f[1] - p.x*f[5]) >
191            aRadii.x * absYY + aRadii.y * absYX +
192            bRadii.x * absZZ + bRadii.z * absXZ)
193      return false;
194   
195   if (mFabs(p.y*f[2] - p.x*f[6]) >
196            aRadii.x * absZY + aRadii.y * absZX +
197            bRadii.x * absYZ + bRadii.y * absXZ)
198      return false;
199   
200   return true;
201}
202
203//-----------------------------------------------------------------------------
204
205Box3F Box3F::aroundPoints( const Point3F* points, U32 numPoints )
206{
207   AssertFatal( points != NULL, "Box3F::aroundPoints - Receive a NULL pointer" );
208   AssertFatal( numPoints >= 1, "Box3F::aroundPoints - Must have at least one point" );
209
210   Box3F box;
211   
212   Point3F minPoint = points[ 0 ];
213   Point3F maxPoint = points[ 0 ];
214
215   for( U32 i = 1; i < numPoints; ++ i )
216      for( U32 n = 0; n < 3; ++ n )
217      {
218         minPoint[ n ] = getMin( minPoint[ n ], points[ i ][ n ] );
219         maxPoint[ n ] = getMax( maxPoint[ n ], points[ i ][ n ] );
220      }
221
222   return Box3F( minPoint, maxPoint );
223}
224
225//-----------------------------------------------------------------------------
226
227Point3F Box3F::computeVertex( U32 corner ) const
228{
229   AssertFatal( corner < NUM_POINTS, "Box3F::computeVertex - Index out of range" );
230   
231   switch( corner )
232   {
233      case NearBottomLeft:    return Point3F( minExtents.x, minExtents.y, minExtents.z );
234      case NearTopLeft:       return Point3F( minExtents.x, minExtents.y, maxExtents.z );
235      case NearTopRight:      return Point3F( maxExtents.x, minExtents.y, maxExtents.z );
236      case NearBottomRight:   return Point3F( maxExtents.x, minExtents.y, minExtents.z );
237
238      case FarBottomLeft:     return Point3F( minExtents.x, maxExtents.y, minExtents.z );
239      case FarTopLeft:        return Point3F( minExtents.x, maxExtents.y, maxExtents.z );
240      case FarTopRight:       return Point3F( maxExtents.x, maxExtents.y, maxExtents.z );
241      case FarBottomRight:    return Point3F( maxExtents.x, maxExtents.y, minExtents.z );
242   }
243
244   // Not reached.
245   return Point3F( 0.f, 0.f, 0.f );
246}
247
248//-----------------------------------------------------------------------------
249
250F32 Box3F::getGreatestDiagonalLength() const
251{
252   F32 maxDiagonalsLen = ( computeVertex( FarTopRight ) - computeVertex( NearBottomLeft ) ).len();
253
254   maxDiagonalsLen = getMax( maxDiagonalsLen, ( computeVertex( FarTopLeft ) - computeVertex( NearBottomRight ) ).len() );
255   maxDiagonalsLen = getMax( maxDiagonalsLen, ( computeVertex( FarBottomLeft ) - computeVertex( NearTopRight ) ).len() );
256   maxDiagonalsLen = getMax( maxDiagonalsLen, ( computeVertex( FarBottomRight ) - computeVertex( NearTopLeft ) ).len() );
257
258   return maxDiagonalsLen;
259}
260
261//-----------------------------------------------------------------------------
262
263SphereF Box3F::getBoundingSphere() const
264{
265   return SphereF( getCenter(), getGreatestDiagonalLength() / 2.f );
266}
267