frustum.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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. #include "platform/platform.h"
  23. #include "math/util/frustum.h"
  24. #include "math/mMathFn.h"
  25. #include "math/mathUtils.h"
  26. #include "math/mSphere.h"
  27. #include "platform/profiler.h"
  28. static const MatrixF sGFXProjRotMatrix( EulerF( (M_PI_F / 2.0f), 0.0f, 0.0f ) );
  29. //TODO: For OBB/frustum intersections and ortho frustums, we can resort to a much quicker AABB/OBB test
  30. // Must be CW ordered for face[0] of each edge! Keep in mind that normals
  31. // are pointing *inwards* and thus what appears CCW outside is CW inside.
  32. FrustumData::EdgeListType FrustumData::smEdges
  33. (
  34. PolyhedronData::Edge( PlaneNear, PlaneTop, NearTopRight, NearTopLeft ),
  35. PolyhedronData::Edge( PlaneNear, PlaneBottom, NearBottomLeft, NearBottomRight ),
  36. PolyhedronData::Edge( PlaneNear, PlaneLeft, NearTopLeft, NearBottomLeft ),
  37. PolyhedronData::Edge( PlaneNear, PlaneRight, NearTopRight, NearBottomRight ),
  38. PolyhedronData::Edge( PlaneFar, PlaneTop, FarTopLeft, FarTopRight ),
  39. PolyhedronData::Edge( PlaneFar, PlaneBottom, FarBottomRight, FarBottomLeft ),
  40. PolyhedronData::Edge( PlaneFar, PlaneLeft, FarBottomLeft, FarTopLeft ),
  41. PolyhedronData::Edge( PlaneFar, PlaneRight, FarTopRight, FarBottomRight ),
  42. PolyhedronData::Edge( PlaneTop, PlaneLeft, FarTopLeft, NearTopLeft ),
  43. PolyhedronData::Edge( PlaneTop, PlaneRight, NearTopRight, FarTopRight ),
  44. PolyhedronData::Edge( PlaneBottom, PlaneLeft, NearBottomLeft, FarBottomLeft ),
  45. PolyhedronData::Edge( PlaneBottom, PlaneRight, FarBottomRight, NearBottomRight )
  46. );
  47. //-----------------------------------------------------------------------------
  48. Frustum::Frustum( bool isOrtho,
  49. F32 nearLeft,
  50. F32 nearRight,
  51. F32 nearTop,
  52. F32 nearBottom,
  53. F32 nearDist,
  54. F32 farDist,
  55. const MatrixF &transform )
  56. {
  57. mTransform = transform;
  58. mPosition = transform.getPosition();
  59. mNearLeft = nearLeft;
  60. mNearRight = nearRight;
  61. mNearTop = nearTop;
  62. mNearBottom = nearBottom;
  63. mNearDist = nearDist;
  64. mFarDist = farDist;
  65. mIsOrtho = isOrtho;
  66. mNumTiles = 1;
  67. mCurrTile.set(0,0);
  68. mTileOverlap.set(0.0f, 0.0f);
  69. mProjectionOffset.zero();
  70. mProjectionOffsetMatrix.identity();
  71. mDirty = true;
  72. }
  73. //-----------------------------------------------------------------------------
  74. void Frustum::set( bool isOrtho,
  75. F32 fovYInRadians,
  76. F32 aspectRatio,
  77. F32 nearDist,
  78. F32 farDist,
  79. const MatrixF &transform )
  80. {
  81. F32 left, right, top, bottom;
  82. MathUtils::makeFrustum( &left, &right, &top, &bottom, fovYInRadians, aspectRatio, nearDist );
  83. tile( &left, &right, &top, &bottom, mNumTiles, mCurrTile, mTileOverlap );
  84. set( isOrtho, left, right, top, bottom, nearDist, farDist, transform );
  85. }
  86. //-----------------------------------------------------------------------------
  87. void Frustum::set( bool isOrtho,
  88. F32 nearLeft,
  89. F32 nearRight,
  90. F32 nearTop,
  91. F32 nearBottom,
  92. F32 nearDist,
  93. F32 farDist,
  94. const MatrixF &transform )
  95. {
  96. mTransform = transform;
  97. mPosition = mTransform.getPosition();
  98. mNearLeft = nearLeft;
  99. mNearRight = nearRight;
  100. mNearTop = nearTop;
  101. mNearBottom = nearBottom;
  102. mNearDist = nearDist;
  103. mFarDist = farDist;
  104. mIsOrtho = isOrtho;
  105. mDirty = true;
  106. }
  107. //-----------------------------------------------------------------------------
  108. #if 0
  109. void Frustum::set( const MatrixF &projMat, bool normalize )
  110. {
  111. // From "Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix"
  112. // by Gil Gribb and Klaus Hartmann.
  113. //
  114. // http://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf
  115. // Right clipping plane.
  116. mPlanes[ PlaneRight ].set( projMat[3] - projMat[0],
  117. projMat[7] - projMat[4],
  118. projMat[11] - projMat[8],
  119. projMat[15] - projMat[12] );
  120. // Left clipping plane.
  121. mPlanes[ PlaneLeft ].set( projMat[3] + projMat[0],
  122. projMat[7] + projMat[4],
  123. projMat[11] + projMat[8],
  124. projMat[15] + projMat[12] );
  125. // Bottom clipping plane.
  126. mPlanes[ PlaneBottom ].set( projMat[3] + projMat[1],
  127. projMat[7] + projMat[5],
  128. projMat[11] + projMat[9],
  129. projMat[15] + projMat[13] );
  130. // Top clipping plane.
  131. mPlanes[ PlaneTop ].set( projMat[3] - projMat[1],
  132. projMat[7] - projMat[5],
  133. projMat[11] - projMat[9],
  134. projMat[15] - projMat[13] );
  135. // Near clipping plane
  136. mPlanes[ PlaneNear ].set( projMat[3] + projMat[2],
  137. projMat[7] + projMat[6],
  138. projMat[11] + projMat[10],
  139. projMat[15] + projMat[14] );
  140. // Far clipping plane.
  141. mPlanes[ PlaneFar ].set( projMat[3] - projMat[2],
  142. projMat[7] - projMat[6],
  143. projMat[11] - projMat[10],
  144. projMat[15] - projMat[14] );
  145. if( normalize )
  146. {
  147. for( S32 i = 0; i < PlaneCount; ++ i )
  148. mPlanes[ i ].normalize();
  149. }
  150. /*// Create the corner points via plane intersections.
  151. mPlanes[ PlaneNear ].intersect( mPlanes[ PlaneTop ], mPlanes[ PlaneLeft ], &mPoints[ NearTopLeft ] );
  152. mPlanes[ PlaneNear ].intersect( mPlanes[ PlaneTop ], mPlanes[ PlaneRight ], &mPoints[ NearTopRight ] );
  153. mPlanes[ PlaneNear ].intersect( mPlanes[ PlaneBottom ], mPlanes[ PlaneLeft ], &mPoints[ NearBottomLeft ] );
  154. mPlanes[ PlaneNear ].intersect( mPlanes[ PlaneBottom ], mPlanes[ PlaneRight ], &mPoints[ NearBottomRight ] );
  155. mPlanes[ PlaneFar ].intersect( mPlanes[ PlaneTop ], mPlanes[ PlaneLeft ], &mPoints[ FarTopLeft ] );
  156. mPlanes[ PlaneFar ].intersect( mPlanes[ PlaneTop ], mPlanes[ PlaneRight ], &mPoints[ FarTopRight ] );
  157. mPlanes[ PlaneFar ].intersect( mPlanes[ PlaneBottom ], mPlanes[ PlaneLeft ], &mPoints[ FarBottomLeft ] );
  158. mPlanes[ PlaneFar ].intersect( mPlanes[ PlaneBottom ], mPlanes[ PlaneRight ], &mPoints[ FarBottomRight ] );
  159. */
  160. // Update the axis aligned bounding box.
  161. _updateBounds();
  162. }
  163. #endif
  164. //-----------------------------------------------------------------------------
  165. void Frustum::setNearDist( F32 nearDist )
  166. {
  167. setNearFarDist( nearDist, mFarDist );
  168. }
  169. //-----------------------------------------------------------------------------
  170. void Frustum::setFarDist( F32 farDist )
  171. {
  172. setNearFarDist( mNearDist, farDist );
  173. }
  174. //-----------------------------------------------------------------------------
  175. void Frustum::setNearFarDist( F32 nearDist, F32 farDist )
  176. {
  177. if( mNearDist == nearDist && mFarDist == farDist )
  178. return;
  179. // Recalculate the frustum.
  180. MatrixF xfm( mTransform );
  181. const F32 CENTER_EPSILON = 0.001f;
  182. F32 centerX = mNearLeft + (mNearRight - mNearLeft) * 0.5;
  183. F32 centerY = mNearBottom + (mNearTop - mNearBottom) * 0.5;
  184. if ((centerX > CENTER_EPSILON || centerX < -CENTER_EPSILON) || (centerY > CENTER_EPSILON || centerY < -CENTER_EPSILON) )
  185. {
  186. // Off-center projection, so re-calc use the new distances
  187. FovPort expectedFovPort;
  188. expectedFovPort.leftTan = -(mNearLeft / mNearDist);
  189. expectedFovPort.rightTan = (mNearRight / mNearDist);
  190. expectedFovPort.upTan = (mNearTop / mNearDist);
  191. expectedFovPort.downTan = -(mNearBottom / mNearDist);
  192. MathUtils::makeFovPortFrustum(this, mIsOrtho, nearDist, farDist, expectedFovPort);
  193. }
  194. else
  195. {
  196. // Projection is not off-center, use the normal code
  197. set(mIsOrtho, getFov(), getAspectRatio(), nearDist, farDist, xfm);
  198. }
  199. }
  200. //-----------------------------------------------------------------------------
  201. void Frustum::cropNearFar(F32 newNearDist, F32 newFarDist)
  202. {
  203. const F32 newOverOld = newNearDist / mNearDist;
  204. set( mIsOrtho, mNearLeft * newOverOld, mNearRight * newOverOld, mNearTop * newOverOld, mNearBottom * newOverOld,
  205. newNearDist, newFarDist, mTransform);
  206. }
  207. //-----------------------------------------------------------------------------
  208. bool Frustum::bakeProjectionOffset()
  209. {
  210. // Nothing to bake if ortho
  211. if( mIsOrtho )
  212. return false;
  213. // Nothing to bake if no offset
  214. if( mProjectionOffset.isZero() )
  215. return false;
  216. // Near plane points in camera space
  217. Point3F np[4];
  218. np[0].set( mNearLeft, mNearDist, mNearTop ); // NearTopLeft
  219. np[1].set( mNearRight, mNearDist, mNearTop ); // NearTopRight
  220. np[2].set( mNearLeft, mNearDist, mNearBottom ); // NearBottomLeft
  221. np[3].set( mNearRight, mNearDist, mNearBottom ); // NearBottomRight
  222. // Generate the near plane
  223. PlaneF nearPlane( np[0], np[1], np[3] );
  224. // Far plane points in camera space
  225. const F32 farOverNear = mFarDist / mNearDist;
  226. Point3F fp0( mNearLeft * farOverNear, mFarDist, mNearTop * farOverNear ); // FarTopLeft
  227. Point3F fp1( mNearRight * farOverNear, mFarDist, mNearTop * farOverNear ); // FarTopRight
  228. Point3F fp2( mNearLeft * farOverNear, mFarDist, mNearBottom * farOverNear ); // FarBottomLeft
  229. Point3F fp3( mNearRight * farOverNear, mFarDist, mNearBottom * farOverNear ); // FarBottomRight
  230. // Generate the far plane
  231. PlaneF farPlane( fp0, fp1, fp3 );
  232. // The offset camera point
  233. Point3F offsetCamera( mProjectionOffset.x, 0.0f, mProjectionOffset.y );
  234. // The near plane point we'll be using for our calculations below
  235. U32 nIndex = 0;
  236. if( mProjectionOffset.x < 0.0 )
  237. {
  238. // Offset to the left so we'll need to use the near plane point on the right
  239. nIndex = 1;
  240. }
  241. if( mProjectionOffset.y > 0.0 )
  242. {
  243. // Offset to the top so we'll need to use the near plane point at the bottom
  244. nIndex += 2;
  245. }
  246. // Begin by calculating the offset point on the far plane as it goes
  247. // from the offset camera to the edge of the near plane.
  248. Point3F farPoint;
  249. Point3F fdir = np[nIndex] - offsetCamera;
  250. fdir.normalize();
  251. if( farPlane.intersect(offsetCamera, fdir, &farPoint) )
  252. {
  253. // Calculate the new near plane edge from the non-offset camera position
  254. // to the far plane point from above.
  255. Point3F nearPoint;
  256. Point3F ndir = farPoint;
  257. ndir.normalize();
  258. if( nearPlane.intersect( Point3F::Zero, ndir, &nearPoint) )
  259. {
  260. // Handle a x offset
  261. if( mProjectionOffset.x < 0.0 )
  262. {
  263. // The new near plane right side
  264. mNearRight = nearPoint.x;
  265. }
  266. else if( mProjectionOffset.x > 0.0 )
  267. {
  268. // The new near plane left side
  269. mNearLeft = nearPoint.x;
  270. }
  271. // Handle a y offset
  272. if( mProjectionOffset.y < 0.0 )
  273. {
  274. // The new near plane top side
  275. mNearTop = nearPoint.y;
  276. }
  277. else if( mProjectionOffset.y > 0.0 )
  278. {
  279. // The new near plane bottom side
  280. mNearBottom = nearPoint.y;
  281. }
  282. }
  283. }
  284. mDirty = true;
  285. // Indicate that we've modified the frustum
  286. return true;
  287. }
  288. //-----------------------------------------------------------------------------
  289. void FrustumData::_update() const
  290. {
  291. if( !mDirty )
  292. return;
  293. PROFILE_SCOPE( Frustum_update );
  294. const Point3F& cameraPos = mPosition;
  295. // Build the frustum points in camera space first.
  296. if( mIsOrtho )
  297. {
  298. mPoints[ NearTopLeft ].set( mNearLeft, mNearDist, mNearTop );
  299. mPoints[ NearTopRight ].set( mNearRight, mNearDist, mNearTop );
  300. mPoints[ NearBottomLeft ].set( mNearLeft, mNearDist, mNearBottom );
  301. mPoints[ NearBottomRight ].set( mNearRight, mNearDist, mNearBottom );
  302. mPoints[ FarTopLeft ].set( mNearLeft, mFarDist, mNearTop );
  303. mPoints[ FarTopRight ].set( mNearRight, mFarDist, mNearTop );
  304. mPoints[ FarBottomLeft ].set( mNearLeft, mFarDist, mNearBottom );
  305. mPoints[ FarBottomRight ].set( mNearRight, mFarDist, mNearBottom );
  306. }
  307. else
  308. {
  309. const F32 farOverNear = mFarDist / mNearDist;
  310. mPoints[ NearTopLeft ].set( mNearLeft, mNearDist, mNearTop );
  311. mPoints[ NearTopRight ].set( mNearRight, mNearDist, mNearTop );
  312. mPoints[ NearBottomLeft ].set( mNearLeft, mNearDist, mNearBottom );
  313. mPoints[ NearBottomRight ].set( mNearRight, mNearDist, mNearBottom );
  314. mPoints[ FarTopLeft ].set( mNearLeft * farOverNear, mFarDist, mNearTop * farOverNear );
  315. mPoints[ FarTopRight ].set( mNearRight * farOverNear, mFarDist, mNearTop * farOverNear );
  316. mPoints[ FarBottomLeft ].set( mNearLeft * farOverNear, mFarDist, mNearBottom * farOverNear );
  317. mPoints[ FarBottomRight ].set( mNearRight * farOverNear, mFarDist, mNearBottom * farOverNear );
  318. }
  319. // Transform the points into the desired culling space.
  320. for( U32 i = 0; i < mPoints.size(); ++ i )
  321. mTransform.mulP( mPoints[ i ] );
  322. // Update the axis aligned bounding box from
  323. // the newly transformed points.
  324. mBounds = Box3F::aroundPoints( mPoints.address(), mPoints.size() );
  325. // Finally build the planes.
  326. if( mIsOrtho )
  327. {
  328. mPlanes[ PlaneLeft ].set( mPoints[ NearBottomLeft ],
  329. mPoints[ FarTopLeft ],
  330. mPoints[ FarBottomLeft ] );
  331. mPlanes[ PlaneRight ].set( mPoints[ NearTopRight ],
  332. mPoints[ FarBottomRight ],
  333. mPoints[ FarTopRight ] );
  334. mPlanes[ PlaneTop ].set( mPoints[ FarTopRight ],
  335. mPoints[ NearTopLeft ],
  336. mPoints[ NearTopRight ] );
  337. mPlanes[ PlaneBottom ].set( mPoints[ NearBottomRight ],
  338. mPoints[ FarBottomLeft ],
  339. mPoints[ FarBottomRight ] );
  340. mPlanes[ PlaneNear ].set( mPoints[ NearTopLeft ],
  341. mPoints[ NearBottomLeft ],
  342. mPoints[ NearTopRight ] );
  343. mPlanes[ PlaneFar ].set( mPoints[ FarTopLeft ],
  344. mPoints[ FarTopRight ],
  345. mPoints[ FarBottomLeft ] );
  346. }
  347. else
  348. {
  349. mPlanes[ PlaneLeft ].set( cameraPos,
  350. mPoints[ NearTopLeft ],
  351. mPoints[ NearBottomLeft ] );
  352. mPlanes[ PlaneRight ].set( cameraPos,
  353. mPoints[ NearBottomRight ],
  354. mPoints[ NearTopRight ] );
  355. mPlanes[ PlaneTop ].set( cameraPos,
  356. mPoints[ NearTopRight ],
  357. mPoints[ NearTopLeft ] );
  358. mPlanes[ PlaneBottom ].set( cameraPos,
  359. mPoints[ NearBottomLeft ],
  360. mPoints[ NearBottomRight ] );
  361. mPlanes[ PlaneNear ].set( mPoints[ NearTopLeft ],
  362. mPoints[ NearBottomLeft ],
  363. mPoints[ NearTopRight ] );
  364. mPlanes[ PlaneFar ].set( mPoints[ FarTopLeft ],
  365. mPoints[ FarTopRight ],
  366. mPoints[ FarBottomLeft ] );
  367. }
  368. // If the frustum plane orientation doesn't match mIsInverted
  369. // now, invert all the plane normals.
  370. //
  371. // Note that if we have a transform matrix with a negative scale,
  372. // then the initial planes we have computed will always be inverted.
  373. const bool inverted = mPlanes[ PlaneNear ].whichSide( cameraPos ) == PlaneF::Front;
  374. if( inverted != mIsInverted )
  375. {
  376. for( U32 i = 0; i < mPlanes.size(); ++ i )
  377. mPlanes[ i ].invert();
  378. }
  379. AssertFatal( mPlanes[ PlaneNear ].whichSide( cameraPos ) != PlaneF::Front,
  380. "Frustum::_update - Viewpoint lies on front side of near plane!" );
  381. // And now the center points which are mostly just used in debug rendering.
  382. mPlaneCenters[ PlaneLeftCenter ] = ( mPoints[ NearTopLeft ] +
  383. mPoints[ NearBottomLeft ] +
  384. mPoints[ FarTopLeft ] +
  385. mPoints[ FarBottomLeft ] ) / 4.0f;
  386. mPlaneCenters[ PlaneRightCenter ] = ( mPoints[ NearTopRight ] +
  387. mPoints[ NearBottomRight ] +
  388. mPoints[ FarTopRight ] +
  389. mPoints[ FarBottomRight ] ) / 4.0f;
  390. mPlaneCenters[ PlaneTopCenter ] = ( mPoints[ NearTopLeft ] +
  391. mPoints[ NearTopRight ] +
  392. mPoints[ FarTopLeft ] +
  393. mPoints[ FarTopRight ] ) / 4.0f;
  394. mPlaneCenters[ PlaneBottomCenter ] = ( mPoints[ NearBottomLeft ] +
  395. mPoints[ NearBottomRight ] +
  396. mPoints[ FarBottomLeft ] +
  397. mPoints[ FarBottomRight ] ) / 4.0f;
  398. mPlaneCenters[ PlaneNearCenter ] = ( mPoints[ NearTopLeft ] +
  399. mPoints[ NearTopRight ] +
  400. mPoints[ NearBottomLeft ] +
  401. mPoints[ NearBottomRight ] ) / 4.0f;
  402. mPlaneCenters[ PlaneFarCenter ] = ( mPoints[ FarTopLeft ] +
  403. mPoints[ FarTopRight ] +
  404. mPoints[ FarBottomLeft ] +
  405. mPoints[ FarBottomRight ] ) / 4.0f;
  406. // Done.
  407. mDirty = false;
  408. }
  409. //-----------------------------------------------------------------------------
  410. void Frustum::invert()
  411. {
  412. mIsInverted = !mIsInverted;
  413. _update();
  414. }
  415. //-----------------------------------------------------------------------------
  416. void Frustum::setTransform( const MatrixF &mat )
  417. {
  418. mTransform = mat;
  419. mPosition = mTransform.getPosition();
  420. mDirty = true;
  421. }
  422. //-----------------------------------------------------------------------------
  423. void Frustum::scaleFromCenter( F32 scale )
  424. {
  425. // Extract the fov and aspect ratio.
  426. F32 fovInRadians = mAtan2( (mNearTop - mNearBottom)*mNumTiles/2.0f, mNearDist ) * 2.0f;
  427. F32 aspectRatio = (mNearRight - mNearLeft)/(mNearTop - mNearBottom);
  428. // Now move the near and far planes out.
  429. F32 halfDist = ( mFarDist - mNearDist ) / 2.0f;
  430. mNearDist -= halfDist * ( scale - 1.0f );
  431. mFarDist += halfDist * ( scale - 1.0f );
  432. // Setup the new scaled frustum.
  433. set( mIsOrtho, fovInRadians, aspectRatio, mNearDist, mFarDist, mTransform );
  434. }
  435. //-----------------------------------------------------------------------------
  436. void Frustum::mul( const MatrixF& mat )
  437. {
  438. mTransform.mul( mat );
  439. mDirty = true;
  440. }
  441. //-----------------------------------------------------------------------------
  442. void Frustum::mulL( const MatrixF& mat )
  443. {
  444. MatrixF last( mTransform );
  445. mTransform.mul( mat, last );
  446. mDirty = true;
  447. }
  448. //-----------------------------------------------------------------------------
  449. void Frustum::setProjectionOffset(const Point2F& offsetMat)
  450. {
  451. mProjectionOffset = offsetMat;
  452. mProjectionOffsetMatrix.identity();
  453. mProjectionOffsetMatrix.setPosition(Point3F(mProjectionOffset.x, mProjectionOffset.y, 0.0f));
  454. }
  455. //-----------------------------------------------------------------------------
  456. void Frustum::getProjectionMatrix( MatrixF *proj, bool gfxRotate ) const
  457. {
  458. if (mIsOrtho)
  459. {
  460. MathUtils::makeOrthoProjection(proj, mNearLeft, mNearRight, mNearTop, mNearBottom, mNearDist, mFarDist, gfxRotate);
  461. proj->mulL(mProjectionOffsetMatrix);
  462. }
  463. else
  464. {
  465. MathUtils::makeProjection(proj, mNearLeft, mNearRight, mNearTop, mNearBottom, mNearDist, mFarDist, gfxRotate);
  466. proj->mulL(mProjectionOffsetMatrix);
  467. }
  468. }
  469. //-----------------------------------------------------------------------------
  470. void Frustum::tileFrustum(U32 numTiles, const Point2I& curTile, Point2F overlap)
  471. {
  472. //These will be stored to re-tile the frustum if needed
  473. mNumTiles = numTiles;
  474. mCurrTile = curTile;
  475. mTileOverlap = overlap;
  476. tile(&mNearLeft, &mNearRight, &mNearTop, &mNearBottom, mNumTiles, mCurrTile, mTileOverlap);
  477. }
  478. //-----------------------------------------------------------------------------
  479. void Frustum::tile( F32 *left, F32 *right, F32 *top, F32 *bottom, U32 numTiles, const Point2I& curTile, Point2F overlap )
  480. {
  481. if (numTiles == 1)
  482. return;
  483. Point2F tileSize( ( *right - *left ) / (F32)numTiles,
  484. ( *top - *bottom ) / (F32)numTiles );
  485. F32 leftOffset = tileSize.x*overlap.x;
  486. F32 rightOffset = tileSize.x*overlap.x*2;
  487. F32 bottomOffset = tileSize.y*overlap.y;
  488. F32 topOffset = tileSize.y*overlap.y*2;
  489. *left += tileSize.x * curTile.x - leftOffset;
  490. *right = *left + tileSize.x + rightOffset;
  491. *bottom += tileSize.y * curTile.y - bottomOffset;
  492. *top = *bottom + tileSize.y + topOffset;
  493. }