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 : 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