CmCamera.cpp 43 KB

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