frustum.h
Engine/source/math/util/frustum.h
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
