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         : mDirty( false ),
191           mIsInverted( false ) {}
192
193   public:
194
195      /// @name Accessors
196      /// @{
197
198      /// Return the number of planes that a frustum has.
199      static U32 getNumPlanes() { return PlaneCount; }
200
201      /// Return the planes that make up the polyhedron.
202      /// @note The normals of these planes are facing *inwards*.
203      const PlaneF* getPlanes() const { _update(); return mPlanes.address(); }
204
205      /// Return the number of corner points that a frustum has.
206      static U32 getNumPoints() { return CornerPointCount; }
207
208      ///
209      const Point3F* getPoints() const { _update(); return mPoints.address(); }
210
211      /// Return the number of edges that a frustum has.
212      static U32 getNumEdges() { return EdgeCount; }
213
214      /// Return the edge definitions for a frustum.
215      static const Edge* getEdges() { return smEdges.address(); }
216
217      /// @}
218
219      operator AnyPolyhedron() const
220      {
221         return AnyPolyhedron(
222            AnyPolyhedron::PlaneListType( const_cast< PlaneF* >( getPlanes() ), getNumPlanes() ),
223            AnyPolyhedron::PointListType( const_cast< Point3F* >( getPoints() ), getNumPoints() ),
224            AnyPolyhedron::EdgeListType( const_cast< Edge* >( getEdges() ), getNumEdges() )
225         );
226      }
227};
228
229
230/// This class implements a view frustum for use in culling scene objects and
231/// rendering the scene.
232///
233/// @warn Frustums are always non-inverted by default which means that even if
234///   the frustum transform applies a negative scale, the frustum will still be
235///   non-inverted.
236class Frustum : public PolyhedronImpl< FrustumData >
237{
238   public:
239
240      typedef PolyhedronImpl< FrustumData> Parent;
241
242   protected:
243
244      /// @name Tiling
245      /// @{
246
247      /// Number of subdivisions.
248      U32 mNumTiles;
249
250      /// Current rendering tile.
251      Point2I mCurrTile;
252
253      /// Tile overlap percentage.
254      Point2F mTileOverlap;
255
256      /// @}
257
258      /// Offset used for projection matrix calculations
259      Point2F mProjectionOffset;
260
261      /// The calculated projection offset matrix
262      MatrixF mProjectionOffsetMatrix;
263
264   public:
265
266      /// @name Constructors
267      /// @{
268
269      /// Construct a non-inverted frustum.
270      ///
271      /// @note If the given transform has a negative scale, the plane
272      ///   normals will automatically be inverted so that the frustum
273      ///   will still be non-inverted.  Use invert() to actually cause
274      ///   the frustum to be inverted.
275      Frustum( bool orthographic = false,
276               F32 nearLeft = -1.0f, 
277               F32 nearRight = 1.0f, 
278               F32 nearTop = 1.0f, 
279               F32 nearBottom = -1.0f, 
280               F32 nearDist = 0.1f, 
281               F32 farDist = 1.0f,
282               const MatrixF &transform = MatrixF( true ) );
283
284      /// @}
285
286
287      /// @name Operators
288      /// @{
289
290      bool operator==( const Frustum& frustum ) const
291      {
292         return ( ( mNearLeft == frustum.mNearLeft ) &&
293            ( mNearTop == frustum.mNearTop ) &&
294            ( mNearBottom == frustum.mNearBottom ) &&
295            ( mNearDist == frustum.mNearDist ) &&
296            ( mFarDist == frustum.mFarDist ) &&
297            ( mProjectionOffset.x == frustum.mProjectionOffset.x ) &&
298            ( mProjectionOffset.y == frustum.mProjectionOffset.y ) );
299
300      }
301      bool operator!=( const Frustum& frustum ) const { return !( *this == frustum ); }
302
303      /// @}
304
305
306      /// @name Initialization
307      ///
308      /// Functions used to initialize the frustum.
309      ///
310      /// @{
311      
312      /// Sets the frustum from the field of view, screen aspect
313      /// ratio, and the near and far distances.  You can pass an
314      /// matrix to transform the frustum.
315      void set(   bool isOrtho,
316                  F32 fovYInRadians, 
317                  F32 aspectRatio, 
318                  F32 nearDist, 
319                  F32 farDist,
320                  const MatrixF &mat = MatrixF( true ) );
321
322      /// Sets the frustum from the near plane dimensions and
323      /// near and far distances.
324      void set(   bool isOrtho,
325                  F32 nearLeft, 
326                  F32 nearRight, 
327                  F32 nearTop, 
328                  F32 nearBottom, 
329                  F32 nearDist, 
330                  F32 farDist,
331                  const MatrixF &transform = MatrixF( true ) );
332
333      /// Sets the frustum by extracting the planes from a projection,
334      /// view-projection, or world-view-projection matrix.
335      //void set( const MatrixF& projMatrix, bool normalize );
336
337      /// Changes the near distance of the frustum.
338      void setNearDist( F32 nearDist );
339
340      /// Changes the far distance of the frustum.
341      void setFarDist( F32 farDist );
342
343      /// Changes the near and far distance of the frustum.
344      void setNearFarDist( F32 nearDist, F32 farDist );
345
346      ///
347      void cropNearFar(F32 newNearDist, F32 newFarDist);
348
349      /// Returns the far clip distance used to create 
350      /// the frustum planes.
351      F32 getFarDist() const { return mFarDist; }
352
353      /// Returns the far clip distance used to create 
354      /// the frustum planes.
355      F32 getNearDist() const { return mNearDist; }
356
357      /// Return the camera-space minimum X coordinate on the near plane.
358      F32 getNearLeft() const { return mNearLeft; }
359
360      /// Return the camera-space maximum X coordinate on the near plane.
361      F32 getNearRight() const { return mNearRight; }
362
363      /// Return the camera-space maximum Z coordinate on the near plane.
364      F32 getNearTop() const { return mNearTop; }
365
366      /// Return the camera-space minimum Z coordinate on the near plane.
367      F32 getNearBottom() const { return mNearBottom; }
368
369      /// Return the camera-space width of the frustum.
370      F32 getWidth() const { return mFabs( mNearRight - mNearLeft ); }
371
372      /// Return the camera-space height of the frustum.
373      F32 getHeight() const { return mFabs( mNearTop - mNearBottom ); }
374
375      ///
376      F32 getFov() const
377      {
378         F32 nonTiledHeight = getHeight()*mNumTiles;
379         return mAtan2( nonTiledHeight/2.0f, mNearDist ) * 2.0f;
380      }
381
382      ///
383      F32 getAspectRatio() const { return (mNearRight - mNearLeft)/(mNearTop - mNearBottom); }
384
385      /// @}
386
387
388      /// @name Transformation
389      ///
390      /// These functions for transforming the frustum from
391      /// one space to another.
392      ///
393      /// @{
394
395      /// Sets a new transform for the frustum.
396      void setTransform( const MatrixF &transform );
397
398      /// Returns the current transform matrix for the frustum.
399      const MatrixF& getTransform() const { return mTransform; }
400
401      /// Scales up the frustum from its center point.
402      void scaleFromCenter( F32 scale );
403
404      /// Transforms the frustum by F = F * mat.
405      void mul( const MatrixF &mat );
406
407      /// Transforms the frustum by F = mat * F.
408      void mulL( const MatrixF &mat );
409
410      /// Flip the plane normals which has the result
411      /// of reversing the culling results.
412      void invert();
413
414      /// Returns true if the frustum planes point outwards.
415      bool isInverted() const { return mIsInverted; }
416
417      /// Returns the origin point of the frustum.
418      const Point3F& getPosition() const { return mPosition; }
419
420      /// Returns the axis aligned bounding box of the frustum
421      /// points typically used for early rejection.
422      const Box3F& getBounds() const { _update(); return mBounds; }
423
424      // Does the frustum have a projection offset?
425      bool hasProjectionOffset() const { return !mProjectionOffset.isZero(); }
426
427      /// Get the offset used when calculating the projection matrix
428      const Point2F& getProjectionOffset() const { return mProjectionOffset; }
429
430      /// Get the offset matrix used when calculating the projection matrix
431      const MatrixF& getProjectionOffsetMatrix() const { return mProjectionOffsetMatrix; }
432
433      /// Set the offset used when calculating the projection matrix
434      void setProjectionOffset(const Point2F& offsetMat);
435
436      /// Clear any offset used when calculating the projection matrix
437      void clearProjectionOffset() { mProjectionOffset.zero(); mProjectionOffsetMatrix.identity(); }
438
439      /// Enlarges the frustum to contain the planes generated by a project offset, if any.
440      /// Used by scene culling to ensure that all object are contained within the asymetrical frustum.
441      bool bakeProjectionOffset();
442
443      /// Generates a projection matrix from the frustum.
444      void getProjectionMatrix( MatrixF *proj, bool gfxRotate=true ) const;
445
446      /// Will update the frustum if it is dirty
447      void update() { _update(); }
448      /// @}
449
450      /// @name Culling
451      /// @{
452
453      /// Return true if the contents of the given AABB can be culled.
454      bool isCulled( const Box3F& aabb ) const { return ( testPotentialIntersection( aabb ) == GeometryOutside ); }
455
456      /// Return true if the contents of the given OBB can be culled.
457      bool isCulled( const OrientedBox3F& obb ) const { return ( testPotentialIntersection( obb ) == GeometryOutside ); }
458
459      /// Return true if the contents of the given sphere can be culled.
460      bool isCulled( const SphereF& sphere ) const { return ( testPotentialIntersection( sphere ) == GeometryOutside ); }
461
462      /// @}
463
464      /// @name Projection Type
465      /// @{
466
467      bool isOrtho() const { return mIsOrtho; }
468      
469      /// @}
470
471      /// @name Tile settings
472      /// @{
473
474      U32 getNumTiles() const { return mNumTiles; }
475      const Point2I& getCurTile() const { return mCurrTile; }
476      void tileFrustum(U32 numTiles, const Point2I& curTile, Point2F overlap);
477      static void tile( F32 *left, F32 *right, F32 *top, F32 *bottom, U32 numTiles, const Point2I& curTile, Point2F overlap );
478
479      /// @}
480};
481
482#endif // _MATHUTIL_FRUSTUM_H_
483