frustum.h

Engine/source/math/util/frustum.h

More...

Classes:

class

Advanced fov specification for oculus.

class

This class implements a view frustum for use in culling scene objects and rendering the scene.

class

Polyhedron data for use by frustums.

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#ifndef _MATHUTIL_FRUSTUM_H_
 25#define _MATHUTIL_FRUSTUM_H_
 26
 27#ifndef _MPOLYHEDRON_H_
 28#include "math/mPolyhedron.h"
 29#endif
 30
 31#ifndef _MBOX_H_
 32#include "math/mBox.h"
 33#endif
 34
 35#ifndef _MPLANE_H_
 36#include "math/mPlane.h"
 37#endif
 38
 39#ifndef _MMATRIX_H_
 40#include "math/mMatrix.h"
 41#endif
 42
 43#ifndef _MQUAT_H_
 44#include "math/mQuat.h"
 45#endif
 46
 47#ifndef _MSPHERE_H_
 48#include "math/mSphere.h"
 49#endif
 50
 51
 52//TODO: Specialize intersection tests for frustums using octant tests
 53
 54
 55class OrientedBox3F;
 56
 57/// Advanced fov specification for oculus
 58struct FovPort
 59{
 60   float upTan;
 61   float downTan;
 62   float leftTan;
 63   float rightTan;
 64};
 65
 66/// Polyhedron data for use by frustums.  Uses fixed-size vectors
 67/// and a static vector for the edge list as that never changes
 68/// between frustums.
 69struct FrustumData : public PolyhedronData
 70{
 71      enum
 72      {
 73         EdgeCount = 12
 74      };
 75
 76      /// Indices for the planes in a frustum.
 77      ///
 78      /// Note the planes are ordered left, right, near, 
 79      /// far, top, bottom for getting early rejections
 80      /// from the typical horizontal scene.
 81      enum
 82      {
 83         PlaneLeft,
 84         PlaneRight,
 85         PlaneNear,
 86         PlaneFar,
 87         PlaneTop,
 88         PlaneBottom,
 89
 90         /// The total number of frustum planes.
 91         PlaneCount
 92      };
 93
 94      /// Indices for the corner points of the frustum.
 95      enum CornerPoints
 96      {
 97         NearTopLeft,
 98         NearTopRight,
 99         NearBottomLeft,
100         NearBottomRight,
101         FarTopLeft,
102         FarTopRight,
103         FarBottomLeft,
104         FarBottomRight,
105
106         /// Total number of corner points.
107         CornerPointCount
108      };
109
110      /// Indices for the center points of the frustum planes.
111      enum PlaneCenters 
112      {
113         PlaneLeftCenter,
114         PlaneRightCenter,
115         PlaneTopCenter,
116         PlaneBottomCenter,
117         PlaneNearCenter,
118         PlaneFarCenter,
119      };
120
121      /// Used to mask out planes for testing.
122      enum : <a href="/coding/file/types_8h/#types_8h_1ac3df7cf3c8cb172a588adec881447d68">U32</a>
123      {
124         PlaneMaskLeft     = ( 1 << PlaneLeft ),
125         PlaneMaskRight    = ( 1 << PlaneRight ),
126         PlaneMaskTop      = ( 1 << PlaneTop ),
127         PlaneMaskBottom   = ( 1 << PlaneBottom ),
128         PlaneMaskNear     = ( 1 << PlaneNear ),
129         PlaneMaskFar      = ( 1 << PlaneFar ),
130
131         PlaneMaskAll      = 0xFFFFFFFF,
132      };
133
134      typedef FixedSizeVector< PlaneF, PlaneCount> PlaneListType;
135      typedef FixedSizeVector< Point3F, CornerPointCount> PointListType;
136      typedef FixedSizeVector< Edge, EdgeCount> EdgeListType;
137
138   protected:
139
140      /// @name Lazily Updated Data
141      /// @{
142
143      /// When true, points, planes and bounds must be re-calculated before use.
144      mutable bool mDirty;
145
146      mutable PlaneListType mPlanes;
147      mutable PointListType mPoints;
148
149      /// The center points of the individual faces of the frustum.
150      mutable Point3F mPlaneCenters[ PlaneCount ];
151
152      /// The clipping-space axis-aligned bounding box which contains
153      /// the extents of the frustum.
154      mutable Box3F mBounds;
155
156      /// @}
157
158      /// Static edge list.  Shared by all frustum polyhedrons
159      /// since they are always constructed the same way.
160      static EdgeListType smEdges;
161
162      /// Determines whether this Frustum
163      /// is orthographic or perspective.
164      bool mIsOrtho;
165
166      /// Whether the frustum is inverted, i.e. whether the planes are
167      /// facing outwards rather than inwards.
168      bool mIsInverted;
169
170      /// Used to transform the frustum points from camera
171      /// space into the desired clipping space.
172      MatrixF mTransform;
173
174      /// Camera position extracted from tarnsform.
175      Point3F mPosition;
176
177      /// The size of the near plane used to generate
178      /// the frustum points and planes.
179      F32 mNearLeft;
180      F32 mNearRight;
181      F32 mNearTop;
182      F32 mNearBottom;
183      F32 mNearDist;
184      F32 mFarDist;
185
186      /// Update the point and plane data from the current frustum settings.
187      void _update() const;
188
189      FrustumData()
190         : mIsOrtho(false),
191         mNearLeft(-1.0f),
192         mNearRight(1.0f),
193         mNearTop(1.0f),
194         mNearBottom(-1.0f),
195         mNearDist(0.1f),
196         mFarDist(1.0f),
197         mTransform(MatrixF(true)),
198         mDirty( false ),
199         mIsInverted( false ) {}
200
201   public:
202
203      /// @name Accessors
204      /// @{
205
206      /// Return the number of planes that a frustum has.
207      static U32 getNumPlanes() { return PlaneCount; }
208
209      /// Return the planes that make up the polyhedron.
210      /// @note The normals of these planes are facing *inwards*.
211      const PlaneF* getPlanes() const { _update(); return mPlanes.address(); }
212
213      /// Return the number of corner points that a frustum has.
214      static U32 getNumPoints() { return CornerPointCount; }
215
216      ///
217      const Point3F* getPoints() const { _update(); return mPoints.address(); }
218
219      /// Return the number of edges that a frustum has.
220      static U32 getNumEdges() { return EdgeCount; }
221
222      /// Return the edge definitions for a frustum.
223      static const Edge* getEdges() { return smEdges.address(); }
224
225      /// @}
226
227      operator AnyPolyhedron() const
228      {
229         return AnyPolyhedron(
230            AnyPolyhedron::PlaneListType( const_cast< PlaneF* >( getPlanes() ), getNumPlanes() ),
231            AnyPolyhedron::PointListType( const_cast< Point3F* >( getPoints() ), getNumPoints() ),
232            AnyPolyhedron::EdgeListType( const_cast< Edge* >( getEdges() ), getNumEdges() )
233         );
234      }
235};
236
237
238/// This class implements a view frustum for use in culling scene objects and
239/// rendering the scene.
240///
241/// @warn Frustums are always non-inverted by default which means that even if
242///   the frustum transform applies a negative scale, the frustum will still be
243///   non-inverted.
244class Frustum : public PolyhedronImpl< FrustumData >
245{
246   public:
247
248      typedef PolyhedronImpl< FrustumData> Parent;
249
250   protected:
251
252      /// @name Tiling
253      /// @{
254
255      /// Number of subdivisions.
256      U32 mNumTiles;
257
258      /// Current rendering tile.
259      Point2I mCurrTile;
260
261      /// Tile overlap percentage.
262      Point2F mTileOverlap;
263
264      /// @}
265
266      /// Offset used for projection matrix calculations
267      Point2F mProjectionOffset;
268
269      /// The calculated projection offset matrix
270      MatrixF mProjectionOffsetMatrix;
271
272   public:
273
274      /// @name Constructors
275      /// @{
276
277      /// Construct a non-inverted frustum.
278      ///
279      /// @note If the given transform has a negative scale, the plane
280      ///   normals will automatically be inverted so that the frustum
281      ///   will still be non-inverted.  Use invert() to actually cause
282      ///   the frustum to be inverted.
283      Frustum( bool orthographic = false,
284               F32 nearLeft = -1.0f, 
285               F32 nearRight = 1.0f, 
286               F32 nearTop = 1.0f, 
287               F32 nearBottom = -1.0f, 
288               F32 nearDist = 0.1f, 
289               F32 farDist = 1.0f,
290               const MatrixF &transform = MatrixF( true ) );
291
292      /// @}
293
294
295      /// @name Operators
296      /// @{
297
298      bool operator==( const Frustum& frustum ) const
299      {
300         return ( ( mNearLeft == frustum.mNearLeft ) &&
301            ( mNearTop == frustum.mNearTop ) &&
302            ( mNearBottom == frustum.mNearBottom ) &&
303            ( mNearDist == frustum.mNearDist ) &&
304            ( mFarDist == frustum.mFarDist ) &&
305            ( mProjectionOffset.x == frustum.mProjectionOffset.x ) &&
306            ( mProjectionOffset.y == frustum.mProjectionOffset.y ) );
307
308      }
309      bool operator!=( const Frustum& frustum ) const { return !( *this == frustum ); }
310
311      /// @}
312
313
314      /// @name Initialization
315      ///
316      /// Functions used to initialize the frustum.
317      ///
318      /// @{
319      
320      /// Sets the frustum from the field of view, screen aspect
321      /// ratio, and the near and far distances.  You can pass an
322      /// matrix to transform the frustum.
323      void set(   bool isOrtho,
324                  F32 fovYInRadians, 
325                  F32 aspectRatio, 
326                  F32 nearDist, 
327                  F32 farDist,
328                  const MatrixF &mat = MatrixF( true ) );
329
330      /// Sets the frustum from the near plane dimensions and
331      /// near and far distances.
332      void set(   bool isOrtho,
333                  F32 nearLeft, 
334                  F32 nearRight, 
335                  F32 nearTop, 
336                  F32 nearBottom, 
337                  F32 nearDist, 
338                  F32 farDist,
339                  const MatrixF &transform = MatrixF( true ) );
340
341      /// Sets the frustum by extracting the planes from a projection,
342      /// view-projection, or world-view-projection matrix.
343      //void set( const MatrixF& projMatrix, bool normalize );
344
345      /// Changes the near distance of the frustum.
346      void setNearDist( F32 nearDist );
347
348      /// Changes the far distance of the frustum.
349      void setFarDist( F32 farDist );
350
351      /// Changes the near and far distance of the frustum.
352      void setNearFarDist( F32 nearDist, F32 farDist );
353
354      ///
355      void cropNearFar(F32 newNearDist, F32 newFarDist);
356
357      /// Returns the far clip distance used to create 
358      /// the frustum planes.
359      F32 getFarDist() const { return mFarDist; }
360
361      /// Returns the far clip distance used to create 
362      /// the frustum planes.
363      F32 getNearDist() const { return mNearDist; }
364
365      /// Return the camera-space minimum X coordinate on the near plane.
366      F32 getNearLeft() const { return mNearLeft; }
367
368      /// Return the camera-space maximum X coordinate on the near plane.
369      F32 getNearRight() const { return mNearRight; }
370
371      /// Return the camera-space maximum Z coordinate on the near plane.
372      F32 getNearTop() const { return mNearTop; }
373
374      /// Return the camera-space minimum Z coordinate on the near plane.
375      F32 getNearBottom() const { return mNearBottom; }
376
377      /// Return the camera-space width of the frustum.
378      F32 getWidth() const { return mFabs( mNearRight - mNearLeft ); }
379
380      /// Return the camera-space height of the frustum.
381      F32 getHeight() const { return mFabs( mNearTop - mNearBottom ); }
382
383      ///
384      F32 getFov() const
385      {
386         F32 nonTiledHeight = getHeight()*mNumTiles;
387         return mAtan2( nonTiledHeight/2.0f, mNearDist ) * 2.0f;
388      }
389
390      ///
391      F32 getAspectRatio() const { return (mNearRight - mNearLeft)/(mNearTop - mNearBottom); }
392
393      /// @}
394
395
396      /// @name Transformation
397      ///
398      /// These functions for transforming the frustum from
399      /// one space to another.
400      ///
401      /// @{
402
403      /// Sets a new transform for the frustum.
404      void setTransform( const MatrixF &transform );
405
406      /// Returns the current transform matrix for the frustum.
407      const MatrixF& getTransform() const { return mTransform; }
408
409      /// Scales up the frustum from its center point.
410      void scaleFromCenter( F32 scale );
411
412      /// Transforms the frustum by F = F * mat.
413      void mul( const MatrixF &mat );
414
415      /// Transforms the frustum by F = mat * F.
416      void mulL( const MatrixF &mat );
417
418      /// Flip the plane normals which has the result
419      /// of reversing the culling results.
420      void invert();
421
422      /// Returns true if the frustum planes point outwards.
423      bool isInverted() const { return mIsInverted; }
424
425      /// Returns the origin point of the frustum.
426      const Point3F& getPosition() const { return mPosition; }
427
428      /// Returns the axis aligned bounding box of the frustum
429      /// points typically used for early rejection.
430      const Box3F& getBounds() const { _update(); return mBounds; }
431
432      // Does the frustum have a projection offset?
433      bool hasProjectionOffset() const { return !mProjectionOffset.isZero(); }
434
435      /// Get the offset used when calculating the projection matrix
436      const Point2F& getProjectionOffset() const { return mProjectionOffset; }
437
438      /// Get the offset matrix used when calculating the projection matrix
439      const MatrixF& getProjectionOffsetMatrix() const { return mProjectionOffsetMatrix; }
440
441      /// Set the offset used when calculating the projection matrix
442      void setProjectionOffset(const Point2F& offsetMat);
443
444      /// Clear any offset used when calculating the projection matrix
445      void clearProjectionOffset() { mProjectionOffset.zero(); mProjectionOffsetMatrix.identity(); }
446
447      /// Enlarges the frustum to contain the planes generated by a project offset, if any.
448      /// Used by scene culling to ensure that all object are contained within the asymetrical frustum.
449      bool bakeProjectionOffset();
450
451      /// Generates a projection matrix from the frustum.
452      void getProjectionMatrix( MatrixF *proj, bool gfxRotate=true ) const;
453
454      /// Will update the frustum if it is dirty
455      void update() { _update(); }
456      /// @}
457
458      /// @name Culling
459      /// @{
460
461      /// Return true if the contents of the given AABB can be culled.
462      bool isCulled( const Box3F& aabb ) const { return ( testPotentialIntersection( aabb ) == GeometryOutside ); }
463
464      /// Return true if the contents of the given OBB can be culled.
465      bool isCulled( const OrientedBox3F& obb ) const { return ( testPotentialIntersection( obb ) == GeometryOutside ); }
466
467      /// Return true if the contents of the given sphere can be culled.
468      bool isCulled( const SphereF& sphere ) const { return ( testPotentialIntersection( sphere ) == GeometryOutside ); }
469
470      /// @}
471
472      /// @name Projection Type
473      /// @{
474
475      bool isOrtho() const { return mIsOrtho; }
476      
477      /// @}
478
479      /// @name Tile settings
480      /// @{
481
482      U32 getNumTiles() const { return mNumTiles; }
483      const Point2I& getCurTile() const { return mCurrTile; }
484      void tileFrustum(U32 numTiles, const Point2I& curTile, Point2F overlap);
485      static void tile( F32 *left, F32 *right, F32 *top, F32 *bottom, U32 numTiles, const Point2I& curTile, Point2F overlap );
486
487      /// @}
488};
489
490#endif // _MATHUTIL_FRUSTUM_H_
491