frustum.h 15 KB

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