1 //-----------------------------------------------------------------------------
2 // Copyright (c) 2012 GarageGames, LLC
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to
6 // deal in the Software without restriction, including without limitation the
7 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 // sell copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 //-----------------------------------------------------------------------------
23 #ifndef _MATHUTIL_FRUSTUM_H_
24 #define _MATHUTIL_FRUSTUM_H_
26 #ifndef _MPOLYHEDRON_H_
27 #include "math/mPolyhedron.h"
31 #include "math/mBox.h"
35 #include "math/mPlane.h"
39 #include "math/mMatrix.h"
43 #include "math/mQuat.h"
47 #include "math/mSphere.h"
51 //TODO: Specialize intersection tests for frustums using octant tests
56 /// Advanced fov specification for oculus
65 /// Polyhedron data for use by frustums. Uses fixed-size vectors
66 /// and a static vector for the edge list as that never changes
68 struct FrustumData
: public PolyhedronData
75 /// Indices for the planes in a frustum.
77 /// Note the planes are ordered left, right, near,
78 /// far, top, bottom for getting early rejections
79 /// from the typical horizontal scene.
89 /// The total number of frustum planes.
93 /// Indices for the corner points of the frustum.
105 /// Total number of corner points.
109 /// Indices for the center points of the frustum planes.
120 /// Used to mask out planes for testing.
123 PlaneMaskLeft
= ( 1 << PlaneLeft
),
124 PlaneMaskRight
= ( 1 << PlaneRight
),
125 PlaneMaskTop
= ( 1 << PlaneTop
),
126 PlaneMaskBottom
= ( 1 << PlaneBottom
),
127 PlaneMaskNear
= ( 1 << PlaneNear
),
128 PlaneMaskFar
= ( 1 << PlaneFar
),
130 PlaneMaskAll
= 0xFFFFFFFF,
133 typedef FixedSizeVector
< PlaneF
, PlaneCount
> PlaneListType
;
134 typedef FixedSizeVector
< Point3F
, CornerPointCount
> PointListType
;
135 typedef FixedSizeVector
< Edge
, EdgeCount
> EdgeListType
;
139 /// @name Lazily Updated Data
142 /// When true, points, planes and bounds must be re-calculated before use.
145 mutable PlaneListType mPlanes
;
146 mutable PointListType mPoints
;
148 /// The center points of the individual faces of the frustum.
149 mutable Point3F mPlaneCenters
[ PlaneCount
];
151 /// The clipping-space axis-aligned bounding box which contains
152 /// the extents of the frustum.
153 mutable Box3F mBounds
;
157 /// Static edge list. Shared by all frustum polyhedrons
158 /// since they are always constructed the same way.
159 static EdgeListType smEdges
;
161 /// Determines whether this Frustum
162 /// is orthographic or perspective.
165 /// Whether the frustum is inverted, i.e. whether the planes are
166 /// facing outwards rather than inwards.
169 /// Used to transform the frustum points from camera
170 /// space into the desired clipping space.
173 /// Camera position extracted from tarnsform.
176 /// The size of the near plane used to generate
177 /// the frustum points and planes.
185 /// Update the point and plane data from the current frustum settings.
186 void _update() const;
190 mIsInverted( false ) {}
197 /// Return the number of planes that a frustum has.
198 static U32
getNumPlanes() { return PlaneCount
; }
200 /// Return the planes that make up the polyhedron.
201 /// @note The normals of these planes are facing *inwards*.
202 const PlaneF
* getPlanes() const { _update(); return mPlanes
.address(); }
204 /// Return the number of corner points that a frustum has.
205 static U32
getNumPoints() { return CornerPointCount
; }
208 const Point3F
* getPoints() const { _update(); return mPoints
.address(); }
210 /// Return the number of edges that a frustum has.
211 static U32
getNumEdges() { return EdgeCount
; }
213 /// Return the edge definitions for a frustum.
214 static const Edge
* getEdges() { return smEdges
.address(); }
218 operator AnyPolyhedron() const
220 return AnyPolyhedron(
221 AnyPolyhedron::PlaneListType( const_cast< PlaneF
* >( getPlanes() ), getNumPlanes() ),
222 AnyPolyhedron::PointListType( const_cast< Point3F
* >( getPoints() ), getNumPoints() ),
223 AnyPolyhedron::EdgeListType( const_cast< Edge
* >( getEdges() ), getNumEdges() )
229 /// This class implements a view frustum for use in culling scene objects and
230 /// rendering the scene.
232 /// @warn Frustums are always non-inverted by default which means that even if
233 /// the frustum transform applies a negative scale, the frustum will still be
235 class Frustum
: public PolyhedronImpl
< FrustumData
>
239 typedef PolyhedronImpl
< FrustumData
> Parent
;
246 /// Number of subdivisions.
249 /// Current rendering tile.
252 /// Tile overlap percentage.
253 Point2F mTileOverlap
;
257 /// Offset used for projection matrix calculations
258 Point2F mProjectionOffset
;
260 /// The calculated projection offset matrix
261 MatrixF mProjectionOffsetMatrix
;
265 /// @name Constructors
268 /// Construct a non-inverted frustum.
270 /// @note If the given transform has a negative scale, the plane
271 /// normals will automatically be inverted so that the frustum
272 /// will still be non-inverted. Use invert() to actually cause
273 /// the frustum to be inverted.
274 Frustum( bool orthographic
= false,
275 F32 nearLeft
= -1.0f
,
276 F32 nearRight
= 1.0f
,
278 F32 nearBottom
= -1.0f
,
281 const MatrixF
&transform
= MatrixF( true ) );
289 bool operator==( const Frustum
& frustum
) const
291 return ( ( mNearLeft
== frustum
.mNearLeft
) &&
292 ( mNearTop
== frustum
.mNearTop
) &&
293 ( mNearBottom
== frustum
.mNearBottom
) &&
294 ( mNearDist
== frustum
.mNearDist
) &&
295 ( mFarDist
== frustum
.mFarDist
) &&
296 ( mProjectionOffset
.x
== frustum
.mProjectionOffset
.x
) &&
297 ( mProjectionOffset
.y
== frustum
.mProjectionOffset
.y
) );
300 bool operator!=( const Frustum
& frustum
) const { return !( *this == frustum
); }
305 /// @name Initialization
307 /// Functions used to initialize the frustum.
311 /// Sets the frustum from the field of view, screen aspect
312 /// ratio, and the near and far distances. You can pass an
313 /// matrix to transform the frustum.
314 void set( bool isOrtho
,
319 const MatrixF
&mat
= MatrixF( true ) );
321 /// Sets the frustum from the near plane dimensions and
322 /// near and far distances.
323 void set( bool isOrtho
,
330 const MatrixF
&transform
= MatrixF( true ) );
332 /// Sets the frustum by extracting the planes from a projection,
333 /// view-projection, or world-view-projection matrix.
334 //void set( const MatrixF& projMatrix, bool normalize );
336 /// Changes the near distance of the frustum.
337 void setNearDist( F32 nearDist
);
339 /// Changes the far distance of the frustum.
340 void setFarDist( F32 farDist
);
342 /// Changes the near and far distance of the frustum.
343 void setNearFarDist( F32 nearDist
, F32 farDist
);
346 void cropNearFar(F32 newNearDist
, F32 newFarDist
);
348 /// Returns the far clip distance used to create
349 /// the frustum planes.
350 F32
getFarDist() const { return mFarDist
; }
352 /// Returns the far clip distance used to create
353 /// the frustum planes.
354 F32
getNearDist() const { return mNearDist
; }
356 /// Return the camera-space minimum X coordinate on the near plane.
357 F32
getNearLeft() const { return mNearLeft
; }
359 /// Return the camera-space maximum X coordinate on the near plane.
360 F32
getNearRight() const { return mNearRight
; }
362 /// Return the camera-space maximum Z coordinate on the near plane.
363 F32
getNearTop() const { return mNearTop
; }
365 /// Return the camera-space minimum Z coordinate on the near plane.
366 F32
getNearBottom() const { return mNearBottom
; }
368 /// Return the camera-space width of the frustum.
369 F32
getWidth() const { return mFabs( mNearRight
- mNearLeft
); }
371 /// Return the camera-space height of the frustum.
372 F32
getHeight() const { return mFabs( mNearTop
- mNearBottom
); }
377 F32 nonTiledHeight
= getHeight()*mNumTiles
;
378 return mAtan2( nonTiledHeight
/2.0f
, mNearDist
) * 2.0f
;
382 F32
getAspectRatio() const { return (mNearRight
- mNearLeft
)/(mNearTop
- mNearBottom
); }
387 /// @name Transformation
389 /// These functions for transforming the frustum from
390 /// one space to another.
394 /// Sets a new transform for the frustum.
395 void setTransform( const MatrixF
&transform
);
397 /// Returns the current transform matrix for the frustum.
398 const MatrixF
& getTransform() const { return mTransform
; }
400 /// Scales up the frustum from its center point.
401 void scaleFromCenter( F32 scale
);
403 /// Transforms the frustum by F = F * mat.
404 void mul( const MatrixF
&mat
);
406 /// Transforms the frustum by F = mat * F.
407 void mulL( const MatrixF
&mat
);
409 /// Flip the plane normals which has the result
410 /// of reversing the culling results.
413 /// Returns true if the frustum planes point outwards.
414 bool isInverted() const { return mIsInverted
; }
416 /// Returns the origin point of the frustum.
417 const Point3F
& getPosition() const { return mPosition
; }
419 /// Returns the axis aligned bounding box of the frustum
420 /// points typically used for early rejection.
421 const Box3F
& getBounds() const { _update(); return mBounds
; }
423 // Does the frustum have a projection offset?
424 bool hasProjectionOffset() const { return !mProjectionOffset
.isZero(); }
426 /// Get the offset used when calculating the projection matrix
427 const Point2F
& getProjectionOffset() const { return mProjectionOffset
; }
429 /// Get the offset matrix used when calculating the projection matrix
430 const MatrixF
& getProjectionOffsetMatrix() const { return mProjectionOffsetMatrix
; }
432 /// Set the offset used when calculating the projection matrix
433 void setProjectionOffset(const Point2F
& offsetMat
);
435 /// Clear any offset used when calculating the projection matrix
436 void clearProjectionOffset() { mProjectionOffset
.zero(); mProjectionOffsetMatrix
.identity(); }
438 /// Enlarges the frustum to contain the planes generated by a project offset, if any.
439 /// Used by scene culling to ensure that all object are contained within the asymetrical frustum.
440 bool bakeProjectionOffset();
442 /// Generates a projection matrix from the frustum.
443 void getProjectionMatrix( MatrixF
*proj
, bool gfxRotate
=true ) const;
445 /// Will update the frustum if it is dirty
446 void update() { _update(); }
452 /// Return true if the contents of the given AABB can be culled.
453 bool isCulled( const Box3F
& aabb
) const { return ( testPotentialIntersection( aabb
) == GeometryOutside
); }
455 /// Return true if the contents of the given OBB can be culled.
456 bool isCulled( const OrientedBox3F
& obb
) const { return ( testPotentialIntersection( obb
) == GeometryOutside
); }
458 /// Return true if the contents of the given sphere can be culled.
459 bool isCulled( const SphereF
& sphere
) const { return ( testPotentialIntersection( sphere
) == GeometryOutside
); }
463 /// @name Projection Type
466 bool isOrtho() const { return mIsOrtho
; }
470 /// @name Tile settings
473 U32
getNumTiles() const { return mNumTiles
; }
474 const Point2I
& getCurTile() const { return mCurrTile
; }
475 void tileFrustum(U32 numTiles
, const Point2I
& curTile
, Point2F overlap
);
476 static void tile( F32
*left
, F32
*right
, F32
*top
, F32
*bottom
, U32 numTiles
, const Point2I
& curTile
, Point2F overlap
);
481 #endif // _MATHUTIL_FRUSTUM_H_