OgreFrustum.cpp 43 KB

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