OgreFrustum.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. /*
  2. -----------------------------------------------------------------------------
  3. This source file is part of OGRE
  4. (Object-oriented Graphics Rendering Engine)
  5. For the latest info, see http://www.ogre3d.org
  6. Copyright (c) 2000-2011 Torus Knot Software Ltd
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  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 FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22. -----------------------------------------------------------------------------
  23. */
  24. #include "OgreFrustum.h"
  25. #include "OgreMath.h"
  26. #include "OgreMatrix3.h"
  27. #include "OgreSphere.h"
  28. #include "OgreException.h"
  29. #include "OgreHardwareBufferManager.h"
  30. #include "OgreHardwareVertexBuffer.h"
  31. #include "OgreHardwareIndexBuffer.h"
  32. namespace Ogre {
  33. String Frustum::msMovableType = "Frustum";
  34. const Real Frustum::INFINITE_FAR_PLANE_ADJUST = 0.00001;
  35. //-----------------------------------------------------------------------
  36. Frustum::Frustum(const String& name) :
  37. mProjType(PT_PERSPECTIVE),
  38. mFOVy(Radian(Math::PI/4.0f)),
  39. mFarDist(100000.0f),
  40. mNearDist(100.0f),
  41. mAspect(1.33333333333333f),
  42. mOrthoHeight(1000),
  43. mFrustumOffset(Vector2::ZERO),
  44. mFocalLength(1.0f),
  45. mLastParentOrientation(Quaternion::IDENTITY),
  46. mLastParentPosition(Vector3::ZERO),
  47. mRecalcFrustum(true),
  48. mRecalcView(true),
  49. mRecalcFrustumPlanes(true),
  50. mRecalcWorldSpaceCorners(true),
  51. mRecalcVertexData(true),
  52. mCustomViewMatrix(false),
  53. mCustomProjMatrix(false),
  54. mFrustumExtentsManuallySet(false),
  55. mOrientationMode(OR_DEGREE_0),
  56. mReflect(false),
  57. mLinkedReflectPlane(0),
  58. mObliqueDepthProjection(false),
  59. mLinkedObliqueProjPlane(0)
  60. {
  61. mLastLinkedReflectionPlane.normal = Vector3::ZERO;
  62. mLastLinkedObliqueProjPlane.normal = Vector3::ZERO;
  63. updateView();
  64. updateFrustum();
  65. }
  66. //-----------------------------------------------------------------------
  67. Frustum::~Frustum()
  68. {
  69. // Do nothing
  70. }
  71. //-----------------------------------------------------------------------
  72. void Frustum::setFOVy(const Radian& fov)
  73. {
  74. mFOVy = fov;
  75. invalidateFrustum();
  76. }
  77. //-----------------------------------------------------------------------
  78. const Radian& Frustum::getFOVy(void) const
  79. {
  80. return mFOVy;
  81. }
  82. //-----------------------------------------------------------------------
  83. void Frustum::setFarClipDistance(Real farPlane)
  84. {
  85. mFarDist = farPlane;
  86. invalidateFrustum();
  87. }
  88. //-----------------------------------------------------------------------
  89. Real Frustum::getFarClipDistance(void) const
  90. {
  91. return mFarDist;
  92. }
  93. //-----------------------------------------------------------------------
  94. void Frustum::setNearClipDistance(Real nearPlane)
  95. {
  96. if (nearPlane <= 0)
  97. OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Near clip distance must be greater than zero.",
  98. "Frustum::setNearClipDistance");
  99. mNearDist = nearPlane;
  100. invalidateFrustum();
  101. }
  102. //-----------------------------------------------------------------------
  103. Real Frustum::getNearClipDistance(void) const
  104. {
  105. return mNearDist;
  106. }
  107. //---------------------------------------------------------------------
  108. void Frustum::setFrustumOffset(const Vector2& offset)
  109. {
  110. mFrustumOffset = offset;
  111. invalidateFrustum();
  112. }
  113. //---------------------------------------------------------------------
  114. void Frustum::setFrustumOffset(Real horizontal, Real vertical)
  115. {
  116. setFrustumOffset(Vector2(horizontal, vertical));
  117. }
  118. //---------------------------------------------------------------------
  119. const Vector2& Frustum::getFrustumOffset() const
  120. {
  121. return mFrustumOffset;
  122. }
  123. //---------------------------------------------------------------------
  124. void Frustum::setFocalLength(Real focalLength)
  125. {
  126. if (focalLength <= 0)
  127. {
  128. OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
  129. "Focal length must be greater than zero.",
  130. "Frustum::setFocalLength");
  131. }
  132. mFocalLength = focalLength;
  133. invalidateFrustum();
  134. }
  135. //---------------------------------------------------------------------
  136. Real Frustum::getFocalLength() const
  137. {
  138. return mFocalLength;
  139. }
  140. //-----------------------------------------------------------------------
  141. const Matrix4& Frustum::getProjectionMatrix(void) const
  142. {
  143. updateFrustum();
  144. return mProjMatrix;
  145. }
  146. //-----------------------------------------------------------------------
  147. const Matrix4& Frustum::getProjectionMatrixWithRSDepth(void) const
  148. {
  149. updateFrustum();
  150. return mProjMatrixRSDepth;
  151. }
  152. //-----------------------------------------------------------------------
  153. const Matrix4& Frustum::getProjectionMatrixRS(void) const
  154. {
  155. updateFrustum();
  156. return mProjMatrixRS;
  157. }
  158. //-----------------------------------------------------------------------
  159. const Matrix4& Frustum::getViewMatrix(void) const
  160. {
  161. updateView();
  162. return mViewMatrix;
  163. }
  164. //-----------------------------------------------------------------------
  165. const Plane* Frustum::getFrustumPlanes(void) const
  166. {
  167. // Make any pending updates to the calculated frustum planes
  168. updateFrustumPlanes();
  169. return mFrustumPlanes;
  170. }
  171. //-----------------------------------------------------------------------
  172. const Plane& Frustum::getFrustumPlane(unsigned short plane) const
  173. {
  174. // Make any pending updates to the calculated frustum planes
  175. updateFrustumPlanes();
  176. return mFrustumPlanes[plane];
  177. }
  178. //-----------------------------------------------------------------------
  179. bool Frustum::isVisible(const AxisAlignedBox& bound, FrustumPlane* culledBy) const
  180. {
  181. // Null boxes always invisible
  182. if (bound.isNull()) return false;
  183. // Infinite boxes always visible
  184. if (bound.isInfinite()) return true;
  185. // Make any pending updates to the calculated frustum planes
  186. updateFrustumPlanes();
  187. // Get centre of the box
  188. Vector3 centre = bound.getCenter();
  189. // Get the half-size of the box
  190. Vector3 halfSize = bound.getHalfSize();
  191. // For each plane, see if all points are on the negative side
  192. // If so, object is not visible
  193. for (int plane = 0; plane < 6; ++plane)
  194. {
  195. // Skip far plane if infinite view frustum
  196. if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0)
  197. continue;
  198. Plane::Side side = mFrustumPlanes[plane].getSide(centre, halfSize);
  199. if (side == Plane::NEGATIVE_SIDE)
  200. {
  201. // ALL corners on negative side therefore out of view
  202. if (culledBy)
  203. *culledBy = (FrustumPlane)plane;
  204. return false;
  205. }
  206. }
  207. return true;
  208. }
  209. //-----------------------------------------------------------------------
  210. bool Frustum::isVisible(const Vector3& vert, FrustumPlane* culledBy) const
  211. {
  212. // Make any pending updates to the calculated frustum planes
  213. updateFrustumPlanes();
  214. // For each plane, see if all points are on the negative side
  215. // If so, object is not visible
  216. for (int plane = 0; plane < 6; ++plane)
  217. {
  218. // Skip far plane if infinite view frustum
  219. if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0)
  220. continue;
  221. if (mFrustumPlanes[plane].getSide(vert) == Plane::NEGATIVE_SIDE)
  222. {
  223. // ALL corners on negative side therefore out of view
  224. if (culledBy)
  225. *culledBy = (FrustumPlane)plane;
  226. return false;
  227. }
  228. }
  229. return true;
  230. }
  231. //-----------------------------------------------------------------------
  232. bool Frustum::isVisible(const Sphere& sphere, FrustumPlane* culledBy) const
  233. {
  234. // Make any pending updates to the calculated frustum planes
  235. updateFrustumPlanes();
  236. // For each plane, see if sphere is on negative side
  237. // If so, object is not visible
  238. for (int plane = 0; plane < 6; ++plane)
  239. {
  240. // Skip far plane if infinite view frustum
  241. if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0)
  242. continue;
  243. // If the distance from sphere center to plane is negative, and 'more negative'
  244. // than the radius of the sphere, sphere is outside frustum
  245. if (mFrustumPlanes[plane].getDistance(sphere.getCenter()) < -sphere.getRadius())
  246. {
  247. // ALL corners on negative side therefore out of view
  248. if (culledBy)
  249. *culledBy = (FrustumPlane)plane;
  250. return false;
  251. }
  252. }
  253. return true;
  254. }
  255. //-----------------------------------------------------------------------
  256. void Frustum::calcProjectionParameters(Real& left, Real& right, Real& bottom, Real& top) const
  257. {
  258. if (mCustomProjMatrix)
  259. {
  260. // Convert clipspace corners to camera space
  261. Matrix4 invProj = mProjMatrix.inverse();
  262. Vector3 topLeft(-0.5f, 0.5f, 0.0f);
  263. Vector3 bottomRight(0.5f, -0.5f, 0.0f);
  264. topLeft = invProj * topLeft;
  265. bottomRight = invProj * bottomRight;
  266. left = topLeft.x;
  267. top = topLeft.y;
  268. right = bottomRight.x;
  269. bottom = bottomRight.y;
  270. }
  271. else
  272. {
  273. if (mFrustumExtentsManuallySet)
  274. {
  275. left = mLeft;
  276. right = mRight;
  277. top = mTop;
  278. bottom = mBottom;
  279. }
  280. // Calculate general projection parameters
  281. else if (mProjType == PT_PERSPECTIVE)
  282. {
  283. Radian thetaY (mFOVy * 0.5f);
  284. Real tanThetaY = Math::Tan(thetaY);
  285. Real tanThetaX = tanThetaY * mAspect;
  286. Real nearFocal = mNearDist / mFocalLength;
  287. Real nearOffsetX = mFrustumOffset.x * nearFocal;
  288. Real nearOffsetY = mFrustumOffset.y * nearFocal;
  289. Real half_w = tanThetaX * mNearDist;
  290. Real half_h = tanThetaY * mNearDist;
  291. left = - half_w + nearOffsetX;
  292. right = + half_w + nearOffsetX;
  293. bottom = - half_h + nearOffsetY;
  294. top = + half_h + nearOffsetY;
  295. mLeft = left;
  296. mRight = right;
  297. mTop = top;
  298. mBottom = bottom;
  299. }
  300. else
  301. {
  302. // Unknown how to apply frustum offset to orthographic camera, just ignore here
  303. Real half_w = getOrthoWindowWidth() * 0.5f;
  304. Real half_h = getOrthoWindowHeight() * 0.5f;
  305. left = - half_w;
  306. right = + half_w;
  307. bottom = - half_h;
  308. top = + half_h;
  309. mLeft = left;
  310. mRight = right;
  311. mTop = top;
  312. mBottom = bottom;
  313. }
  314. }
  315. }
  316. //-----------------------------------------------------------------------
  317. void Frustum::updateFrustumImpl(void) const
  318. {
  319. // Common calcs
  320. Real left, right, bottom, top;
  321. #if OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0
  322. if (mOrientationMode != OR_PORTRAIT)
  323. calcProjectionParameters(bottom, top, left, right);
  324. else
  325. #endif
  326. calcProjectionParameters(left, right, bottom, top);
  327. if (!mCustomProjMatrix)
  328. {
  329. // The code below will dealing with general projection
  330. // parameters, similar glFrustum and glOrtho.
  331. // Doesn't optimise manually except division operator, so the
  332. // code more self-explaining.
  333. Real inv_w = 1 / (right - left);
  334. Real inv_h = 1 / (top - bottom);
  335. Real inv_d = 1 / (mFarDist - mNearDist);
  336. // Recalc if frustum params changed
  337. if (mProjType == PT_PERSPECTIVE)
  338. {
  339. // Calc matrix elements
  340. Real A = 2 * mNearDist * inv_w;
  341. Real B = 2 * mNearDist * inv_h;
  342. Real C = (right + left) * inv_w;
  343. Real D = (top + bottom) * inv_h;
  344. Real q, qn;
  345. if (mFarDist == 0)
  346. {
  347. // Infinite far plane
  348. q = Frustum::INFINITE_FAR_PLANE_ADJUST - 1;
  349. qn = mNearDist * (Frustum::INFINITE_FAR_PLANE_ADJUST - 2);
  350. }
  351. else
  352. {
  353. q = - (mFarDist + mNearDist) * inv_d;
  354. qn = -2 * (mFarDist * mNearDist) * inv_d;
  355. }
  356. // NB: This creates 'uniform' perspective projection matrix,
  357. // which depth range [-1,1], right-handed rules
  358. //
  359. // [ A 0 C 0 ]
  360. // [ 0 B D 0 ]
  361. // [ 0 0 q qn ]
  362. // [ 0 0 -1 0 ]
  363. //
  364. // A = 2 * near / (right - left)
  365. // B = 2 * near / (top - bottom)
  366. // C = (right + left) / (right - left)
  367. // D = (top + bottom) / (top - bottom)
  368. // q = - (far + near) / (far - near)
  369. // qn = - 2 * (far * near) / (far - near)
  370. mProjMatrix = Matrix4::ZERO;
  371. mProjMatrix[0][0] = A;
  372. mProjMatrix[0][2] = C;
  373. mProjMatrix[1][1] = B;
  374. mProjMatrix[1][2] = D;
  375. mProjMatrix[2][2] = q;
  376. mProjMatrix[2][3] = qn;
  377. mProjMatrix[3][2] = -1;
  378. if (mObliqueDepthProjection)
  379. {
  380. // Translate the plane into view space
  381. // Don't use getViewMatrix here, incase overrided by
  382. // camera and return a cull frustum view matrix
  383. updateView();
  384. Plane plane = mViewMatrix * mObliqueProjPlane;
  385. // Thanks to Eric Lenyel for posting this calculation
  386. // at www.terathon.com
  387. // Calculate the clip-space corner point opposite the
  388. // clipping plane
  389. // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
  390. // transform it into camera space by multiplying it
  391. // by the inverse of the projection matrix
  392. /* generalised version
  393. Vector4 q = matrix.inverse() *
  394. Vector4(Math::Sign(plane.normal.x),
  395. Math::Sign(plane.normal.y), 1.0f, 1.0f);
  396. */
  397. Vector4 qVec;
  398. qVec.x = (Math::Sign(plane.normal.x) + mProjMatrix[0][2]) / mProjMatrix[0][0];
  399. qVec.y = (Math::Sign(plane.normal.y) + mProjMatrix[1][2]) / mProjMatrix[1][1];
  400. qVec.z = -1;
  401. qVec.w = (1 + mProjMatrix[2][2]) / mProjMatrix[2][3];
  402. // Calculate the scaled plane vector
  403. Vector4 clipPlane4d(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
  404. Vector4 c = clipPlane4d * (2 / (clipPlane4d.dotProduct(qVec)));
  405. // Replace the third row of the projection matrix
  406. mProjMatrix[2][0] = c.x;
  407. mProjMatrix[2][1] = c.y;
  408. mProjMatrix[2][2] = c.z + 1;
  409. mProjMatrix[2][3] = c.w;
  410. }
  411. } // perspective
  412. else if (mProjType == PT_ORTHOGRAPHIC)
  413. {
  414. Real A = 2 * inv_w;
  415. Real B = 2 * inv_h;
  416. Real C = - (right + left) * inv_w;
  417. Real D = - (top + bottom) * inv_h;
  418. Real q, qn;
  419. if (mFarDist == 0)
  420. {
  421. // Can not do infinite far plane here, avoid divided zero only
  422. q = - Frustum::INFINITE_FAR_PLANE_ADJUST / mNearDist;
  423. qn = - Frustum::INFINITE_FAR_PLANE_ADJUST - 1;
  424. }
  425. else
  426. {
  427. q = - 2 * inv_d;
  428. qn = - (mFarDist + mNearDist) * inv_d;
  429. }
  430. // NB: This creates 'uniform' orthographic projection matrix,
  431. // which depth range [-1,1], right-handed rules
  432. //
  433. // [ A 0 0 C ]
  434. // [ 0 B 0 D ]
  435. // [ 0 0 q qn ]
  436. // [ 0 0 0 1 ]
  437. //
  438. // A = 2 * / (right - left)
  439. // B = 2 * / (top - bottom)
  440. // C = - (right + left) / (right - left)
  441. // D = - (top + bottom) / (top - bottom)
  442. // q = - 2 / (far - near)
  443. // qn = - (far + near) / (far - near)
  444. mProjMatrix = Matrix4::ZERO;
  445. mProjMatrix[0][0] = A;
  446. mProjMatrix[0][3] = C;
  447. mProjMatrix[1][1] = B;
  448. mProjMatrix[1][3] = D;
  449. mProjMatrix[2][2] = q;
  450. mProjMatrix[2][3] = qn;
  451. mProjMatrix[3][3] = 1;
  452. } // ortho
  453. } // !mCustomProjMatrix
  454. #if OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0
  455. // Deal with orientation mode
  456. mProjMatrix = mProjMatrix * Quaternion(Degree(mOrientationMode * 90.f), Vector3::UNIT_Z);
  457. #endif
  458. // TODO PORT - IMPORTANT - After I have render system ported make sure to enable this
  459. //RenderSystem* renderSystem = Root::getSingleton().getRenderSystem();
  460. //// API specific
  461. //renderSystem->_convertProjectionMatrix(mProjMatrix, mProjMatrixRS);
  462. //// API specific for Gpu Programs
  463. //renderSystem->_convertProjectionMatrix(mProjMatrix, mProjMatrixRSDepth, true);
  464. // Calculate bounding box (local)
  465. // Box is from 0, down -Z, max dimensions as determined from far plane
  466. // If infinite view frustum just pick a far value
  467. Real farDist = (mFarDist == 0) ? 100000 : mFarDist;
  468. // Near plane bounds
  469. Vector3 min(left, bottom, -farDist);
  470. Vector3 max(right, top, 0);
  471. if (mCustomProjMatrix)
  472. {
  473. // Some custom projection matrices can have unusual inverted settings
  474. // So make sure the AABB is the right way around to start with
  475. Vector3 tmp = min;
  476. min.makeFloor(max);
  477. max.makeCeil(tmp);
  478. }
  479. if (mProjType == PT_PERSPECTIVE)
  480. {
  481. // Merge with far plane bounds
  482. Real radio = farDist / mNearDist;
  483. min.makeFloor(Vector3(left * radio, bottom * radio, -farDist));
  484. max.makeCeil(Vector3(right * radio, top * radio, 0));
  485. }
  486. mBoundingBox.setExtents(min, max);
  487. mRecalcFrustum = false;
  488. // Signal to update frustum clipping planes
  489. mRecalcFrustumPlanes = true;
  490. }
  491. //-----------------------------------------------------------------------
  492. void Frustum::updateFrustum(void) const
  493. {
  494. if (isFrustumOutOfDate())
  495. {
  496. updateFrustumImpl();
  497. }
  498. }
  499. //-----------------------------------------------------------------------
  500. void Frustum::updateVertexData(void) const
  501. {
  502. if (mRecalcVertexData)
  503. {
  504. if (mVertexData.vertexBufferBinding->getBufferCount() <= 0)
  505. {
  506. // Initialise vertex & index data
  507. mVertexData.vertexDeclaration->addElement(0, 0, VET_FLOAT3, VES_POSITION);
  508. mVertexData.vertexCount = 32;
  509. mVertexData.vertexStart = 0;
  510. mVertexData.vertexBufferBinding->setBinding( 0,
  511. HardwareBufferManager::getSingleton().createVertexBuffer(
  512. sizeof(float)*3, 32, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY) );
  513. }
  514. // Note: Even though we can dealing with general projection matrix here,
  515. // but because it's incompatibly with infinite far plane, thus, we
  516. // still need to working with projection parameters.
  517. // Calc near plane corners
  518. Real vpLeft, vpRight, vpBottom, vpTop;
  519. calcProjectionParameters(vpLeft, vpRight, vpBottom, vpTop);
  520. // Treat infinite fardist as some arbitrary far value
  521. Real farDist = (mFarDist == 0) ? 100000 : mFarDist;
  522. // Calc far plane corners
  523. Real radio = mProjType == PT_PERSPECTIVE ? farDist / mNearDist : 1;
  524. Real farLeft = vpLeft * radio;
  525. Real farRight = vpRight * radio;
  526. Real farBottom = vpBottom * radio;
  527. Real farTop = vpTop * radio;
  528. // Calculate vertex positions (local)
  529. // 0 is the origin
  530. // 1, 2, 3, 4 are the points on the near plane, top left first, clockwise
  531. // 5, 6, 7, 8 are the points on the far plane, top left first, clockwise
  532. HardwareVertexBufferSharedPtr vbuf = mVertexData.vertexBufferBinding->getBuffer(0);
  533. float* pFloat = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
  534. // near plane (remember frustum is going in -Z direction)
  535. *pFloat++ = vpLeft; *pFloat++ = vpTop; *pFloat++ = -mNearDist;
  536. *pFloat++ = vpRight; *pFloat++ = vpTop; *pFloat++ = -mNearDist;
  537. *pFloat++ = vpRight; *pFloat++ = vpTop; *pFloat++ = -mNearDist;
  538. *pFloat++ = vpRight; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
  539. *pFloat++ = vpRight; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
  540. *pFloat++ = vpLeft; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
  541. *pFloat++ = vpLeft; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
  542. *pFloat++ = vpLeft; *pFloat++ = vpTop; *pFloat++ = -mNearDist;
  543. // far plane (remember frustum is going in -Z direction)
  544. *pFloat++ = farLeft; *pFloat++ = farTop; *pFloat++ = -farDist;
  545. *pFloat++ = farRight; *pFloat++ = farTop; *pFloat++ = -farDist;
  546. *pFloat++ = farRight; *pFloat++ = farTop; *pFloat++ = -farDist;
  547. *pFloat++ = farRight; *pFloat++ = farBottom; *pFloat++ = -farDist;
  548. *pFloat++ = farRight; *pFloat++ = farBottom; *pFloat++ = -farDist;
  549. *pFloat++ = farLeft; *pFloat++ = farBottom; *pFloat++ = -farDist;
  550. *pFloat++ = farLeft; *pFloat++ = farBottom; *pFloat++ = -farDist;
  551. *pFloat++ = farLeft; *pFloat++ = farTop; *pFloat++ = -farDist;
  552. // Sides of the pyramid
  553. *pFloat++ = 0.0f; *pFloat++ = 0.0f; *pFloat++ = 0.0f;
  554. *pFloat++ = vpLeft; *pFloat++ = vpTop; *pFloat++ = -mNearDist;
  555. *pFloat++ = 0.0f; *pFloat++ = 0.0f; *pFloat++ = 0.0f;
  556. *pFloat++ = vpRight; *pFloat++ = vpTop; *pFloat++ = -mNearDist;
  557. *pFloat++ = 0.0f; *pFloat++ = 0.0f; *pFloat++ = 0.0f;
  558. *pFloat++ = vpRight; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
  559. *pFloat++ = 0.0f; *pFloat++ = 0.0f; *pFloat++ = 0.0f;
  560. *pFloat++ = vpLeft; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
  561. // Sides of the box
  562. *pFloat++ = vpLeft; *pFloat++ = vpTop; *pFloat++ = -mNearDist;
  563. *pFloat++ = farLeft; *pFloat++ = farTop; *pFloat++ = -farDist;
  564. *pFloat++ = vpRight; *pFloat++ = vpTop; *pFloat++ = -mNearDist;
  565. *pFloat++ = farRight; *pFloat++ = farTop; *pFloat++ = -farDist;
  566. *pFloat++ = vpRight; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
  567. *pFloat++ = farRight; *pFloat++ = farBottom; *pFloat++ = -farDist;
  568. *pFloat++ = vpLeft; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
  569. *pFloat++ = farLeft; *pFloat++ = farBottom; *pFloat++ = -farDist;
  570. vbuf->unlock();
  571. mRecalcVertexData = false;
  572. }
  573. }
  574. //-----------------------------------------------------------------------
  575. bool Frustum::isViewOutOfDate(void) const
  576. {
  577. // Attached to node?
  578. // TODO PORT - Not attached to node because I'll be handling this differently
  579. //if (mParentNode)
  580. //{
  581. // if (mRecalcView ||
  582. // mParentNode->_getDerivedOrientation() != mLastParentOrientation ||
  583. // mParentNode->_getDerivedPosition() != mLastParentPosition)
  584. // {
  585. // // Ok, we're out of date with SceneNode we're attached to
  586. // mLastParentOrientation = mParentNode->_getDerivedOrientation();
  587. // mLastParentPosition = mParentNode->_getDerivedPosition();
  588. // mRecalcView = true;
  589. // }
  590. //}
  591. // Deriving reflection from linked plane?
  592. if (mLinkedReflectPlane &&
  593. !(mLastLinkedReflectionPlane == *mLinkedReflectPlane))
  594. {
  595. mReflectPlane = *mLinkedReflectPlane;
  596. mReflectMatrix = Math::buildReflectionMatrix(mReflectPlane);
  597. mLastLinkedReflectionPlane = *mLinkedReflectPlane;
  598. mRecalcView = true;
  599. }
  600. return mRecalcView;
  601. }
  602. //-----------------------------------------------------------------------
  603. bool Frustum::isFrustumOutOfDate(void) const
  604. {
  605. // Deriving custom near plane from linked plane?
  606. if (mObliqueDepthProjection)
  607. {
  608. // Out of date when view out of data since plane needs to be in view space
  609. if (isViewOutOfDate())
  610. {
  611. mRecalcFrustum = true;
  612. }
  613. // Update derived plane
  614. if (mLinkedObliqueProjPlane &&
  615. !(mLastLinkedObliqueProjPlane == *mLinkedObliqueProjPlane))
  616. {
  617. mObliqueProjPlane = *mLinkedObliqueProjPlane;
  618. mLastLinkedObliqueProjPlane = mObliqueProjPlane;
  619. mRecalcFrustum = true;
  620. }
  621. }
  622. return mRecalcFrustum;
  623. }
  624. //-----------------------------------------------------------------------
  625. void Frustum::updateViewImpl(void) const
  626. {
  627. // ----------------------
  628. // Update the view matrix
  629. // ----------------------
  630. // Get orientation from quaternion
  631. if (!mCustomViewMatrix)
  632. {
  633. Matrix3 rot;
  634. const Quaternion& orientation = getOrientationForViewUpdate();
  635. const Vector3& position = getPositionForViewUpdate();
  636. mViewMatrix = Math::makeViewMatrix(position, orientation, mReflect? &mReflectMatrix : 0);
  637. }
  638. mRecalcView = false;
  639. // Signal to update frustum clipping planes
  640. mRecalcFrustumPlanes = true;
  641. // Signal to update world space corners
  642. mRecalcWorldSpaceCorners = true;
  643. // Signal to update frustum if oblique plane enabled,
  644. // since plane needs to be in view space
  645. if (mObliqueDepthProjection)
  646. {
  647. mRecalcFrustum = true;
  648. }
  649. }
  650. //---------------------------------------------------------------------
  651. void Frustum::calcViewMatrixRelative(const Vector3& relPos, Matrix4& matToUpdate) const
  652. {
  653. Matrix4 matTrans = Matrix4::IDENTITY;
  654. matTrans.setTrans(relPos);
  655. matToUpdate = getViewMatrix() * matTrans;
  656. }
  657. //-----------------------------------------------------------------------
  658. void Frustum::updateView(void) const
  659. {
  660. if (isViewOutOfDate())
  661. {
  662. updateViewImpl();
  663. }
  664. }
  665. //-----------------------------------------------------------------------
  666. void Frustum::updateFrustumPlanesImpl(void) const
  667. {
  668. // -------------------------
  669. // Update the frustum planes
  670. // -------------------------
  671. Matrix4 combo = mProjMatrix * mViewMatrix;
  672. mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal.x = combo[3][0] + combo[0][0];
  673. mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal.y = combo[3][1] + combo[0][1];
  674. mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal.z = combo[3][2] + combo[0][2];
  675. mFrustumPlanes[FRUSTUM_PLANE_LEFT].d = combo[3][3] + combo[0][3];
  676. mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal.x = combo[3][0] - combo[0][0];
  677. mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal.y = combo[3][1] - combo[0][1];
  678. mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal.z = combo[3][2] - combo[0][2];
  679. mFrustumPlanes[FRUSTUM_PLANE_RIGHT].d = combo[3][3] - combo[0][3];
  680. mFrustumPlanes[FRUSTUM_PLANE_TOP].normal.x = combo[3][0] - combo[1][0];
  681. mFrustumPlanes[FRUSTUM_PLANE_TOP].normal.y = combo[3][1] - combo[1][1];
  682. mFrustumPlanes[FRUSTUM_PLANE_TOP].normal.z = combo[3][2] - combo[1][2];
  683. mFrustumPlanes[FRUSTUM_PLANE_TOP].d = combo[3][3] - combo[1][3];
  684. mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.x = combo[3][0] + combo[1][0];
  685. mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.y = combo[3][1] + combo[1][1];
  686. mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.z = combo[3][2] + combo[1][2];
  687. mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].d = combo[3][3] + combo[1][3];
  688. mFrustumPlanes[FRUSTUM_PLANE_NEAR].normal.x = combo[3][0] + combo[2][0];
  689. mFrustumPlanes[FRUSTUM_PLANE_NEAR].normal.y = combo[3][1] + combo[2][1];
  690. mFrustumPlanes[FRUSTUM_PLANE_NEAR].normal.z = combo[3][2] + combo[2][2];
  691. mFrustumPlanes[FRUSTUM_PLANE_NEAR].d = combo[3][3] + combo[2][3];
  692. mFrustumPlanes[FRUSTUM_PLANE_FAR].normal.x = combo[3][0] - combo[2][0];
  693. mFrustumPlanes[FRUSTUM_PLANE_FAR].normal.y = combo[3][1] - combo[2][1];
  694. mFrustumPlanes[FRUSTUM_PLANE_FAR].normal.z = combo[3][2] - combo[2][2];
  695. mFrustumPlanes[FRUSTUM_PLANE_FAR].d = combo[3][3] - combo[2][3];
  696. // Renormalise any normals which were not unit length
  697. for(int i=0; i<6; i++ )
  698. {
  699. Real length = mFrustumPlanes[i].normal.normalise();
  700. mFrustumPlanes[i].d /= length;
  701. }
  702. mRecalcFrustumPlanes = false;
  703. }
  704. //-----------------------------------------------------------------------
  705. void Frustum::updateFrustumPlanes(void) const
  706. {
  707. updateView();
  708. updateFrustum();
  709. if (mRecalcFrustumPlanes)
  710. {
  711. updateFrustumPlanesImpl();
  712. }
  713. }
  714. //-----------------------------------------------------------------------
  715. void Frustum::updateWorldSpaceCornersImpl(void) const
  716. {
  717. Matrix4 eyeToWorld = mViewMatrix.inverseAffine();
  718. // Note: Even though we can dealing with general projection matrix here,
  719. // but because it's incompatibly with infinite far plane, thus, we
  720. // still need to working with projection parameters.
  721. // Calc near plane corners
  722. Real nearLeft, nearRight, nearBottom, nearTop;
  723. calcProjectionParameters(nearLeft, nearRight, nearBottom, nearTop);
  724. // Treat infinite fardist as some arbitrary far value
  725. Real farDist = (mFarDist == 0) ? 100000 : mFarDist;
  726. // Calc far palne corners
  727. Real radio = mProjType == PT_PERSPECTIVE ? farDist / mNearDist : 1;
  728. Real farLeft = nearLeft * radio;
  729. Real farRight = nearRight * radio;
  730. Real farBottom = nearBottom * radio;
  731. Real farTop = nearTop * radio;
  732. // near
  733. mWorldSpaceCorners[0] = eyeToWorld.transformAffine(Vector3(nearRight, nearTop, -mNearDist));
  734. mWorldSpaceCorners[1] = eyeToWorld.transformAffine(Vector3(nearLeft, nearTop, -mNearDist));
  735. mWorldSpaceCorners[2] = eyeToWorld.transformAffine(Vector3(nearLeft, nearBottom, -mNearDist));
  736. mWorldSpaceCorners[3] = eyeToWorld.transformAffine(Vector3(nearRight, nearBottom, -mNearDist));
  737. // far
  738. mWorldSpaceCorners[4] = eyeToWorld.transformAffine(Vector3(farRight, farTop, -farDist));
  739. mWorldSpaceCorners[5] = eyeToWorld.transformAffine(Vector3(farLeft, farTop, -farDist));
  740. mWorldSpaceCorners[6] = eyeToWorld.transformAffine(Vector3(farLeft, farBottom, -farDist));
  741. mWorldSpaceCorners[7] = eyeToWorld.transformAffine(Vector3(farRight, farBottom, -farDist));
  742. mRecalcWorldSpaceCorners = false;
  743. }
  744. //-----------------------------------------------------------------------
  745. void Frustum::updateWorldSpaceCorners(void) const
  746. {
  747. updateView();
  748. if (mRecalcWorldSpaceCorners)
  749. {
  750. updateWorldSpaceCornersImpl();
  751. }
  752. }
  753. //-----------------------------------------------------------------------
  754. Real Frustum::getAspectRatio(void) const
  755. {
  756. return mAspect;
  757. }
  758. //-----------------------------------------------------------------------
  759. void Frustum::setAspectRatio(Real r)
  760. {
  761. mAspect = r;
  762. invalidateFrustum();
  763. }
  764. //-----------------------------------------------------------------------
  765. const AxisAlignedBox& Frustum::getBoundingBox(void) const
  766. {
  767. return mBoundingBox;
  768. }
  769. //-----------------------------------------------------------------------
  770. const String& Frustum::getMovableType(void) const
  771. {
  772. return msMovableType;
  773. }
  774. //-----------------------------------------------------------------------
  775. Real Frustum::getBoundingRadius(void) const
  776. {
  777. return (mFarDist == 0)? 100000 : mFarDist;
  778. }
  779. // -------------------------------------------------------------------
  780. void Frustum::invalidateFrustum() const
  781. {
  782. mRecalcFrustum = true;
  783. mRecalcFrustumPlanes = true;
  784. mRecalcWorldSpaceCorners = true;
  785. mRecalcVertexData = true;
  786. }
  787. // -------------------------------------------------------------------
  788. void Frustum::invalidateView() const
  789. {
  790. mRecalcView = true;
  791. mRecalcFrustumPlanes = true;
  792. mRecalcWorldSpaceCorners = true;
  793. }
  794. // -------------------------------------------------------------------
  795. const Vector3* Frustum::getWorldSpaceCorners(void) const
  796. {
  797. updateWorldSpaceCorners();
  798. return mWorldSpaceCorners;
  799. }
  800. //-----------------------------------------------------------------------
  801. void Frustum::setProjectionType(ProjectionType pt)
  802. {
  803. mProjType = pt;
  804. invalidateFrustum();
  805. }
  806. //-----------------------------------------------------------------------
  807. ProjectionType Frustum::getProjectionType(void) const
  808. {
  809. return mProjType;
  810. }
  811. //-----------------------------------------------------------------------
  812. const Vector3& Frustum::getPositionForViewUpdate(void) const
  813. {
  814. return mLastParentPosition;
  815. }
  816. //-----------------------------------------------------------------------
  817. const Quaternion& Frustum::getOrientationForViewUpdate(void) const
  818. {
  819. return mLastParentOrientation;
  820. }
  821. //-----------------------------------------------------------------------
  822. void Frustum::enableReflection(const Plane& p)
  823. {
  824. mReflect = true;
  825. mReflectPlane = p;
  826. mLinkedReflectPlane = 0;
  827. mReflectMatrix = Math::buildReflectionMatrix(p);
  828. invalidateView();
  829. }
  830. //-----------------------------------------------------------------------
  831. void Frustum::enableReflection(const Plane* p)
  832. {
  833. mReflect = true;
  834. mLinkedReflectPlane = p;
  835. mReflectPlane = *mLinkedReflectPlane;
  836. mReflectMatrix = Math::buildReflectionMatrix(mReflectPlane);
  837. mLastLinkedReflectionPlane = *mLinkedReflectPlane;
  838. invalidateView();
  839. }
  840. //-----------------------------------------------------------------------
  841. void Frustum::disableReflection(void)
  842. {
  843. mReflect = false;
  844. mLinkedReflectPlane = 0;
  845. mLastLinkedReflectionPlane.normal = Vector3::ZERO;
  846. invalidateView();
  847. }
  848. //---------------------------------------------------------------------
  849. bool Frustum::projectSphere(const Sphere& sphere,
  850. Real* left, Real* top, Real* right, Real* bottom) const
  851. {
  852. // See http://www.gamasutra.com/features/20021011/lengyel_06.htm
  853. // Transform light position into camera space
  854. updateView();
  855. Vector3 eyeSpacePos = mViewMatrix.transformAffine(sphere.getCenter());
  856. // initialise
  857. *left = *bottom = -1.0f;
  858. *right = *top = 1.0f;
  859. if (eyeSpacePos.z < 0)
  860. {
  861. updateFrustum();
  862. const Matrix4& projMatrix = getProjectionMatrix();
  863. Real r = sphere.getRadius();
  864. Real rsq = r * r;
  865. // early-exit
  866. if (eyeSpacePos.squaredLength() <= rsq)
  867. return false;
  868. Real Lxz = Math::Sqr(eyeSpacePos.x) + Math::Sqr(eyeSpacePos.z);
  869. Real Lyz = Math::Sqr(eyeSpacePos.y) + Math::Sqr(eyeSpacePos.z);
  870. // Find the tangent planes to the sphere
  871. // XZ first
  872. // calculate quadratic discriminant: b*b - 4ac
  873. // x = Nx
  874. // a = Lx^2 + Lz^2
  875. // b = -2rLx
  876. // c = r^2 - Lz^2
  877. Real a = Lxz;
  878. Real b = -2.0f * r * eyeSpacePos.x;
  879. Real c = rsq - Math::Sqr(eyeSpacePos.z);
  880. Real D = b*b - 4.0f*a*c;
  881. // two roots?
  882. if (D > 0)
  883. {
  884. Real sqrootD = Math::Sqrt(D);
  885. // solve the quadratic to get the components of the normal
  886. Real Nx0 = (-b + sqrootD) / (2 * a);
  887. Real Nx1 = (-b - sqrootD) / (2 * a);
  888. // Derive Z from this
  889. Real Nz0 = (r - Nx0 * eyeSpacePos.x) / eyeSpacePos.z;
  890. Real Nz1 = (r - Nx1 * eyeSpacePos.x) / eyeSpacePos.z;
  891. // Get the point of tangency
  892. // Only consider points of tangency in front of the camera
  893. Real Pz0 = (Lxz - rsq) / (eyeSpacePos.z - ((Nz0 / Nx0) * eyeSpacePos.x));
  894. if (Pz0 < 0)
  895. {
  896. // Project point onto near plane in worldspace
  897. Real nearx0 = (Nz0 * mNearDist) / Nx0;
  898. // now we need to map this to viewport coords
  899. // use projection matrix since that will take into account all factors
  900. Vector3 relx0 = projMatrix * Vector3(nearx0, 0, -mNearDist);
  901. // find out whether this is a left side or right side
  902. Real Px0 = -(Pz0 * Nz0) / Nx0;
  903. if (Px0 > eyeSpacePos.x)
  904. {
  905. *right = std::min(*right, relx0.x);
  906. }
  907. else
  908. {
  909. *left = std::max(*left, relx0.x);
  910. }
  911. }
  912. Real Pz1 = (Lxz - rsq) / (eyeSpacePos.z - ((Nz1 / Nx1) * eyeSpacePos.x));
  913. if (Pz1 < 0)
  914. {
  915. // Project point onto near plane in worldspace
  916. Real nearx1 = (Nz1 * mNearDist) / Nx1;
  917. // now we need to map this to viewport coords
  918. // use projection matrix since that will take into account all factors
  919. Vector3 relx1 = projMatrix * Vector3(nearx1, 0, -mNearDist);
  920. // find out whether this is a left side or right side
  921. Real Px1 = -(Pz1 * Nz1) / Nx1;
  922. if (Px1 > eyeSpacePos.x)
  923. {
  924. *right = std::min(*right, relx1.x);
  925. }
  926. else
  927. {
  928. *left = std::max(*left, relx1.x);
  929. }
  930. }
  931. }
  932. // Now YZ
  933. // calculate quadratic discriminant: b*b - 4ac
  934. // x = Ny
  935. // a = Ly^2 + Lz^2
  936. // b = -2rLy
  937. // c = r^2 - Lz^2
  938. a = Lyz;
  939. b = -2.0f * r * eyeSpacePos.y;
  940. c = rsq - Math::Sqr(eyeSpacePos.z);
  941. D = b*b - 4.0f*a*c;
  942. // two roots?
  943. if (D > 0)
  944. {
  945. Real sqrootD = Math::Sqrt(D);
  946. // solve the quadratic to get the components of the normal
  947. Real Ny0 = (-b + sqrootD) / (2 * a);
  948. Real Ny1 = (-b - sqrootD) / (2 * a);
  949. // Derive Z from this
  950. Real Nz0 = (r - Ny0 * eyeSpacePos.y) / eyeSpacePos.z;
  951. Real Nz1 = (r - Ny1 * eyeSpacePos.y) / eyeSpacePos.z;
  952. // Get the point of tangency
  953. // Only consider points of tangency in front of the camera
  954. Real Pz0 = (Lyz - rsq) / (eyeSpacePos.z - ((Nz0 / Ny0) * eyeSpacePos.y));
  955. if (Pz0 < 0)
  956. {
  957. // Project point onto near plane in worldspace
  958. Real neary0 = (Nz0 * mNearDist) / Ny0;
  959. // now we need to map this to viewport coords
  960. // use projection matriy since that will take into account all factors
  961. Vector3 rely0 = projMatrix * Vector3(0, neary0, -mNearDist);
  962. // find out whether this is a top side or bottom side
  963. Real Py0 = -(Pz0 * Nz0) / Ny0;
  964. if (Py0 > eyeSpacePos.y)
  965. {
  966. *top = std::min(*top, rely0.y);
  967. }
  968. else
  969. {
  970. *bottom = std::max(*bottom, rely0.y);
  971. }
  972. }
  973. Real Pz1 = (Lyz - rsq) / (eyeSpacePos.z - ((Nz1 / Ny1) * eyeSpacePos.y));
  974. if (Pz1 < 0)
  975. {
  976. // Project point onto near plane in worldspace
  977. Real neary1 = (Nz1 * mNearDist) / Ny1;
  978. // now we need to map this to viewport coords
  979. // use projection matriy since that will take into account all factors
  980. Vector3 rely1 = projMatrix * Vector3(0, neary1, -mNearDist);
  981. // find out whether this is a top side or bottom side
  982. Real Py1 = -(Pz1 * Nz1) / Ny1;
  983. if (Py1 > eyeSpacePos.y)
  984. {
  985. *top = std::min(*top, rely1.y);
  986. }
  987. else
  988. {
  989. *bottom = std::max(*bottom, rely1.y);
  990. }
  991. }
  992. }
  993. }
  994. return (*left != -1.0f) || (*top != 1.0f) || (*right != 1.0f) || (*bottom != -1.0f);
  995. }
  996. //---------------------------------------------------------------------
  997. void Frustum::enableCustomNearClipPlane(const Plane* plane)
  998. {
  999. mObliqueDepthProjection = true;
  1000. mLinkedObliqueProjPlane = plane;
  1001. mObliqueProjPlane = *plane;
  1002. invalidateFrustum();
  1003. }
  1004. //---------------------------------------------------------------------
  1005. void Frustum::enableCustomNearClipPlane(const Plane& plane)
  1006. {
  1007. mObliqueDepthProjection = true;
  1008. mLinkedObliqueProjPlane = 0;
  1009. mObliqueProjPlane = plane;
  1010. invalidateFrustum();
  1011. }
  1012. //---------------------------------------------------------------------
  1013. void Frustum::disableCustomNearClipPlane(void)
  1014. {
  1015. mObliqueDepthProjection = false;
  1016. mLinkedObliqueProjPlane = 0;
  1017. invalidateFrustum();
  1018. }
  1019. //---------------------------------------------------------------------
  1020. void Frustum::setCustomViewMatrix(bool enable, const Matrix4& viewMatrix)
  1021. {
  1022. mCustomViewMatrix = enable;
  1023. if (enable)
  1024. {
  1025. assert(viewMatrix.isAffine());
  1026. mViewMatrix = viewMatrix;
  1027. }
  1028. invalidateView();
  1029. }
  1030. //---------------------------------------------------------------------
  1031. void Frustum::setCustomProjectionMatrix(bool enable, const Matrix4& projMatrix)
  1032. {
  1033. mCustomProjMatrix = enable;
  1034. if (enable)
  1035. {
  1036. mProjMatrix = projMatrix;
  1037. }
  1038. invalidateFrustum();
  1039. }
  1040. //---------------------------------------------------------------------
  1041. void Frustum::setOrthoWindow(Real w, Real h)
  1042. {
  1043. mOrthoHeight = h;
  1044. mAspect = w / h;
  1045. invalidateFrustum();
  1046. }
  1047. //---------------------------------------------------------------------
  1048. void Frustum::setOrthoWindowHeight(Real h)
  1049. {
  1050. mOrthoHeight = h;
  1051. invalidateFrustum();
  1052. }
  1053. //---------------------------------------------------------------------
  1054. void Frustum::setOrthoWindowWidth(Real w)
  1055. {
  1056. mOrthoHeight = w / mAspect;
  1057. invalidateFrustum();
  1058. }
  1059. //---------------------------------------------------------------------
  1060. Real Frustum::getOrthoWindowHeight() const
  1061. {
  1062. return mOrthoHeight;
  1063. }
  1064. //---------------------------------------------------------------------
  1065. Real Frustum::getOrthoWindowWidth() const
  1066. {
  1067. return mOrthoHeight * mAspect;
  1068. }
  1069. //---------------------------------------------------------------------
  1070. void Frustum::setFrustumExtents(Real left, Real right, Real top, Real bottom)
  1071. {
  1072. mFrustumExtentsManuallySet = true;
  1073. mLeft = left;
  1074. mRight = right;
  1075. mTop = top;
  1076. mBottom = bottom;
  1077. invalidateFrustum();
  1078. }
  1079. //---------------------------------------------------------------------
  1080. void Frustum::resetFrustumExtents()
  1081. {
  1082. mFrustumExtentsManuallySet = false;
  1083. invalidateFrustum();
  1084. }
  1085. //---------------------------------------------------------------------
  1086. void Frustum::getFrustumExtents(Real& outleft, Real& outright, Real& outtop, Real& outbottom) const
  1087. {
  1088. updateFrustum();
  1089. outleft = mLeft;
  1090. outright = mRight;
  1091. outtop = mTop;
  1092. outbottom = mBottom;
  1093. }
  1094. //---------------------------------------------------------------------
  1095. void Frustum::setOrientationMode(OrientationMode orientationMode)
  1096. {
  1097. #if OGRE_NO_VIEWPORT_ORIENTATIONMODE != 0
  1098. OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
  1099. "Setting Frustrum orientation mode is not supported",
  1100. __FUNCTION__);
  1101. #endif
  1102. mOrientationMode = orientationMode;
  1103. invalidateFrustum();
  1104. }
  1105. //---------------------------------------------------------------------
  1106. OrientationMode Frustum::getOrientationMode() const
  1107. {
  1108. #if OGRE_NO_VIEWPORT_ORIENTATIONMODE != 0
  1109. OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
  1110. "Getting Frustrum orientation mode is not supported",
  1111. __FUNCTION__);
  1112. #endif
  1113. return mOrientationMode;
  1114. }
  1115. } // namespace Ogre