frustum.h 15 KB

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