frustum.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  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. : mIsOrtho(false),
  154. mNearLeft(-1.0f),
  155. mNearRight(1.0f),
  156. mNearTop(1.0f),
  157. mNearBottom(-1.0f),
  158. mNearDist(0.1f),
  159. mFarDist(1.0f),
  160. mTransform(MatrixF(true)),
  161. mDirty( false ),
  162. mIsInverted( false ) {}
  163. public:
  164. /// @name Accessors
  165. /// @{
  166. /// Return the number of planes that a frustum has.
  167. static U32 getNumPlanes() { return PlaneCount; }
  168. /// Return the planes that make up the polyhedron.
  169. /// @note The normals of these planes are facing *inwards*.
  170. const PlaneF* getPlanes() const { _update(); return mPlanes.address(); }
  171. /// Return the number of corner points that a frustum has.
  172. static U32 getNumPoints() { return CornerPointCount; }
  173. ///
  174. const Point3F* getPoints() const { _update(); return mPoints.address(); }
  175. /// Return the number of edges that a frustum has.
  176. static U32 getNumEdges() { return EdgeCount; }
  177. /// Return the edge definitions for a frustum.
  178. static const Edge* getEdges() { return smEdges.address(); }
  179. /// @}
  180. operator AnyPolyhedron() const
  181. {
  182. return AnyPolyhedron(
  183. AnyPolyhedron::PlaneListType( const_cast< PlaneF* >( getPlanes() ), getNumPlanes() ),
  184. AnyPolyhedron::PointListType( const_cast< Point3F* >( getPoints() ), getNumPoints() ),
  185. AnyPolyhedron::EdgeListType( const_cast< Edge* >( getEdges() ), getNumEdges() )
  186. );
  187. }
  188. };
  189. /// This class implements a view frustum for use in culling scene objects and
  190. /// rendering the scene.
  191. ///
  192. /// @warn Frustums are always non-inverted by default which means that even if
  193. /// the frustum transform applies a negative scale, the frustum will still be
  194. /// non-inverted.
  195. class Frustum : public PolyhedronImpl< FrustumData >
  196. {
  197. public:
  198. typedef PolyhedronImpl< FrustumData > Parent;
  199. protected:
  200. /// @name Tiling
  201. /// @{
  202. /// Number of subdivisions.
  203. U32 mNumTiles;
  204. /// Current rendering tile.
  205. Point2I mCurrTile;
  206. /// Tile overlap percentage.
  207. Point2F mTileOverlap;
  208. /// @}
  209. /// Offset used for projection matrix calculations
  210. Point2F mProjectionOffset;
  211. /// The calculated projection offset matrix
  212. MatrixF mProjectionOffsetMatrix;
  213. public:
  214. /// @name Constructors
  215. /// @{
  216. /// Construct a non-inverted frustum.
  217. ///
  218. /// @note If the given transform has a negative scale, the plane
  219. /// normals will automatically be inverted so that the frustum
  220. /// will still be non-inverted. Use invert() to actually cause
  221. /// the frustum to be inverted.
  222. Frustum( bool orthographic = false,
  223. F32 nearLeft = -1.0f,
  224. F32 nearRight = 1.0f,
  225. F32 nearTop = 1.0f,
  226. F32 nearBottom = -1.0f,
  227. F32 nearDist = 0.1f,
  228. F32 farDist = 1.0f,
  229. const MatrixF &transform = MatrixF( true ) );
  230. /// @}
  231. /// @name Operators
  232. /// @{
  233. bool operator==( const Frustum& frustum ) const
  234. {
  235. return ( ( mNearLeft == frustum.mNearLeft ) &&
  236. ( mNearTop == frustum.mNearTop ) &&
  237. ( mNearBottom == frustum.mNearBottom ) &&
  238. ( mNearDist == frustum.mNearDist ) &&
  239. ( mFarDist == frustum.mFarDist ) &&
  240. ( mProjectionOffset.x == frustum.mProjectionOffset.x ) &&
  241. ( mProjectionOffset.y == frustum.mProjectionOffset.y ) );
  242. }
  243. bool operator!=( const Frustum& frustum ) const { return !( *this == frustum ); }
  244. /// @}
  245. /// @name Initialization
  246. ///
  247. /// Functions used to initialize the frustum.
  248. ///
  249. /// @{
  250. /// Sets the frustum from the field of view, screen aspect
  251. /// ratio, and the near and far distances. You can pass an
  252. /// matrix to transform the frustum.
  253. void set( bool isOrtho,
  254. F32 fovYInRadians,
  255. F32 aspectRatio,
  256. F32 nearDist,
  257. F32 farDist,
  258. const MatrixF &mat = MatrixF( true ) );
  259. /// Sets the frustum from the near plane dimensions and
  260. /// near and far distances.
  261. void set( bool isOrtho,
  262. F32 nearLeft,
  263. F32 nearRight,
  264. F32 nearTop,
  265. F32 nearBottom,
  266. F32 nearDist,
  267. F32 farDist,
  268. const MatrixF &transform = MatrixF( true ) );
  269. /// Sets the frustum by extracting the planes from a projection,
  270. /// view-projection, or world-view-projection matrix.
  271. //void set( const MatrixF& projMatrix, bool normalize );
  272. /// Changes the near distance of the frustum.
  273. void setNearDist( F32 nearDist );
  274. /// Changes the far distance of the frustum.
  275. void setFarDist( F32 farDist );
  276. /// Changes the near and far distance of the frustum.
  277. void setNearFarDist( F32 nearDist, F32 farDist );
  278. ///
  279. void cropNearFar(F32 newNearDist, F32 newFarDist);
  280. /// Returns the far clip distance used to create
  281. /// the frustum planes.
  282. F32 getFarDist() const { return mFarDist; }
  283. /// Returns the far clip distance used to create
  284. /// the frustum planes.
  285. F32 getNearDist() const { return mNearDist; }
  286. /// Return the camera-space minimum X coordinate on the near plane.
  287. F32 getNearLeft() const { return mNearLeft; }
  288. /// Return the camera-space maximum X coordinate on the near plane.
  289. F32 getNearRight() const { return mNearRight; }
  290. /// Return the camera-space maximum Z coordinate on the near plane.
  291. F32 getNearTop() const { return mNearTop; }
  292. /// Return the camera-space minimum Z coordinate on the near plane.
  293. F32 getNearBottom() const { return mNearBottom; }
  294. /// Return the camera-space width of the frustum.
  295. F32 getWidth() const { return mFabs( mNearRight - mNearLeft ); }
  296. /// Return the camera-space height of the frustum.
  297. F32 getHeight() const { return mFabs( mNearTop - mNearBottom ); }
  298. ///
  299. F32 getFov() const
  300. {
  301. F32 nonTiledHeight = getHeight()*mNumTiles;
  302. return mAtan2( nonTiledHeight/2.0f, mNearDist ) * 2.0f;
  303. }
  304. ///
  305. F32 getAspectRatio() const { return (mNearRight - mNearLeft)/(mNearTop - mNearBottom); }
  306. /// @}
  307. /// @name Transformation
  308. ///
  309. /// These functions for transforming the frustum from
  310. /// one space to another.
  311. ///
  312. /// @{
  313. /// Sets a new transform for the frustum.
  314. void setTransform( const MatrixF &transform );
  315. /// Returns the current transform matrix for the frustum.
  316. const MatrixF& getTransform() const { return mTransform; }
  317. /// Scales up the frustum from its center point.
  318. void scaleFromCenter( F32 scale );
  319. /// Transforms the frustum by F = F * mat.
  320. void mul( const MatrixF &mat );
  321. /// Transforms the frustum by F = mat * F.
  322. void mulL( const MatrixF &mat );
  323. /// Flip the plane normals which has the result
  324. /// of reversing the culling results.
  325. void invert();
  326. /// Returns true if the frustum planes point outwards.
  327. bool isInverted() const { return mIsInverted; }
  328. /// Returns the origin point of the frustum.
  329. const Point3F& getPosition() const { return mPosition; }
  330. /// Returns the axis aligned bounding box of the frustum
  331. /// points typically used for early rejection.
  332. const Box3F& getBounds() const { _update(); return mBounds; }
  333. // Does the frustum have a projection offset?
  334. bool hasProjectionOffset() const { return !mProjectionOffset.isZero(); }
  335. /// Get the offset used when calculating the projection matrix
  336. const Point2F& getProjectionOffset() const { return mProjectionOffset; }
  337. /// Get the offset matrix used when calculating the projection matrix
  338. const MatrixF& getProjectionOffsetMatrix() const { return mProjectionOffsetMatrix; }
  339. /// Set the offset used when calculating the projection matrix
  340. void setProjectionOffset(const Point2F& offsetMat);
  341. /// Clear any offset used when calculating the projection matrix
  342. void clearProjectionOffset() { mProjectionOffset.zero(); mProjectionOffsetMatrix.identity(); }
  343. /// Enlarges the frustum to contain the planes generated by a project offset, if any.
  344. /// Used by scene culling to ensure that all object are contained within the asymetrical frustum.
  345. bool bakeProjectionOffset();
  346. /// Generates a projection matrix from the frustum.
  347. void getProjectionMatrix( MatrixF *proj, bool gfxRotate=true ) const;
  348. /// Will update the frustum if it is dirty
  349. void update() { _update(); }
  350. /// @}
  351. /// @name Culling
  352. /// @{
  353. /// Return true if the contents of the given AABB can be culled.
  354. bool isCulled( const Box3F& aabb ) const { return ( testPotentialIntersection( aabb ) == GeometryOutside ); }
  355. /// Return true if the contents of the given OBB can be culled.
  356. bool isCulled( const OrientedBox3F& obb ) const { return ( testPotentialIntersection( obb ) == GeometryOutside ); }
  357. /// Return true if the contents of the given sphere can be culled.
  358. bool isCulled( const SphereF& sphere ) const { return ( testPotentialIntersection( sphere ) == GeometryOutside ); }
  359. /// @}
  360. /// @name Projection Type
  361. /// @{
  362. bool isOrtho() const { return mIsOrtho; }
  363. /// @}
  364. /// @name Tile settings
  365. /// @{
  366. U32 getNumTiles() const { return mNumTiles; }
  367. const Point2I& getCurTile() const { return mCurrTile; }
  368. void tileFrustum(U32 numTiles, const Point2I& curTile, Point2F overlap);
  369. static void tile( F32 *left, F32 *right, F32 *top, F32 *bottom, U32 numTiles, const Point2I& curTile, Point2F overlap );
  370. /// @}
  371. };
  372. #endif // _MATHUTIL_FRUSTUM_H_