BsCamera.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsCamera.h"
  4. #include "BsCameraRTTI.h"
  5. #include "BsMath.h"
  6. #include "BsMatrix3.h"
  7. #include "BsVector2.h"
  8. #include "BsAABox.h"
  9. #include "BsSphere.h"
  10. #include "BsException.h"
  11. #include "BsRenderAPI.h"
  12. #include "BsSceneObject.h"
  13. #include "BsRendererManager.h"
  14. #include "BsCoreRenderer.h"
  15. #include "BsFrameAlloc.h"
  16. namespace BansheeEngine
  17. {
  18. const float CameraBase::INFINITE_FAR_PLANE_ADJUST = 0.00001f;
  19. CameraBase::CameraBase()
  20. : mLayers(0xFFFFFFFFFFFFFFFF), mCameraFlags(CameraFlag::HDR), mIsActive(true), mProjType(PT_PERSPECTIVE)
  21. , mHorzFOV(Degree(90.0f)), mFarDist(1000.0f), mNearDist(0.05f), mAspect(1.33333333333333f), mOrthoHeight(5)
  22. , mPriority(0), mCustomViewMatrix(false), mCustomProjMatrix(false), mMSAA(1), mFrustumExtentsManuallySet(false)
  23. , mRecalcFrustum(true), mRecalcFrustumPlanes(true), mRecalcView(true)
  24. {
  25. mPPSettings = RendererManager::instance().getActive()->createPostProcessSettings();
  26. mViewMatrix = Matrix4::ZERO;
  27. mProjMatrixRS = Matrix4::ZERO;
  28. mViewMatrixInv = Matrix4::ZERO;
  29. mProjMatrixRSInv = Matrix4::ZERO;
  30. mProjMatrixInv = Matrix4::ZERO;
  31. invalidateFrustum();
  32. }
  33. void CameraBase::setHorzFOV(const Radian& fov)
  34. {
  35. mHorzFOV = fov;
  36. invalidateFrustum();
  37. _markCoreDirty();
  38. }
  39. const Radian& CameraBase::getHorzFOV() const
  40. {
  41. return mHorzFOV;
  42. }
  43. void CameraBase::setFarClipDistance(float farPlane)
  44. {
  45. mFarDist = farPlane;
  46. invalidateFrustum();
  47. _markCoreDirty();
  48. }
  49. float CameraBase::getFarClipDistance() const
  50. {
  51. return mFarDist;
  52. }
  53. void CameraBase::setNearClipDistance(float nearPlane)
  54. {
  55. if (nearPlane <= 0)
  56. {
  57. BS_EXCEPT(InvalidParametersException, "Near clip distance must be greater than zero.");
  58. }
  59. mNearDist = nearPlane;
  60. invalidateFrustum();
  61. _markCoreDirty();
  62. }
  63. float CameraBase::getNearClipDistance() const
  64. {
  65. return mNearDist;
  66. }
  67. const Matrix4& CameraBase::getProjectionMatrix() const
  68. {
  69. updateFrustum();
  70. return mProjMatrix;
  71. }
  72. const Matrix4& CameraBase::getProjectionMatrixInv() const
  73. {
  74. updateFrustum();
  75. return mProjMatrixInv;
  76. }
  77. const Matrix4& CameraBase::getProjectionMatrixRS() const
  78. {
  79. updateFrustum();
  80. return mProjMatrixRS;
  81. }
  82. const Matrix4& CameraBase::getProjectionMatrixRSInv() const
  83. {
  84. updateFrustum();
  85. return mProjMatrixRSInv;
  86. }
  87. const Matrix4& CameraBase::getViewMatrix() const
  88. {
  89. updateView();
  90. return mViewMatrix;
  91. }
  92. const Matrix4& CameraBase::getViewMatrixInv() const
  93. {
  94. updateView();
  95. return mViewMatrixInv;
  96. }
  97. const ConvexVolume& CameraBase::getFrustum() const
  98. {
  99. // Make any pending updates to the calculated frustum planes
  100. updateFrustumPlanes();
  101. return mFrustum;
  102. }
  103. ConvexVolume CameraBase::getWorldFrustum() const
  104. {
  105. const Vector<Plane>& frustumPlanes = getFrustum().getPlanes();
  106. Matrix4 worldMatrix;
  107. worldMatrix.setTRS(mPosition, mRotation, Vector3::ONE);
  108. Vector<Plane> worldPlanes(frustumPlanes.size());
  109. UINT32 i = 0;
  110. for (auto& plane : frustumPlanes)
  111. {
  112. worldPlanes[i] = worldMatrix.multiplyAffine(plane);
  113. i++;
  114. }
  115. return ConvexVolume(worldPlanes);
  116. }
  117. void CameraBase::calcProjectionParameters(float& left, float& right, float& bottom, float& top) const
  118. {
  119. if (mCustomProjMatrix)
  120. {
  121. // Convert clipspace corners to camera space
  122. Matrix4 invProj = mProjMatrix.inverse();
  123. Vector3 topLeft(-0.5f, 0.5f, 0.0f);
  124. Vector3 bottomRight(0.5f, -0.5f, 0.0f);
  125. topLeft = invProj.multiply(topLeft);
  126. bottomRight = invProj.multiply(bottomRight);
  127. left = topLeft.x;
  128. top = topLeft.y;
  129. right = bottomRight.x;
  130. bottom = bottomRight.y;
  131. }
  132. else
  133. {
  134. if (mFrustumExtentsManuallySet)
  135. {
  136. left = mLeft;
  137. right = mRight;
  138. top = mTop;
  139. bottom = mBottom;
  140. }
  141. else if (mProjType == PT_PERSPECTIVE)
  142. {
  143. Radian thetaX(mHorzFOV * 0.5f);
  144. float tanThetaX = Math::tan(thetaX);
  145. float tanThetaY = tanThetaX / mAspect;
  146. float half_w = tanThetaX * mNearDist;
  147. float half_h = tanThetaY * mNearDist;
  148. left = -half_w;
  149. right = half_w;
  150. bottom = -half_h;
  151. top = half_h;
  152. mLeft = left;
  153. mRight = right;
  154. mTop = top;
  155. mBottom = bottom;
  156. }
  157. else
  158. {
  159. float half_w = getOrthoWindowWidth() * 0.5f;
  160. float half_h = getOrthoWindowHeight() * 0.5f;
  161. left = -half_w;
  162. right = half_w;
  163. bottom = -half_h;
  164. top = half_h;
  165. mLeft = left;
  166. mRight = right;
  167. mTop = top;
  168. mBottom = bottom;
  169. }
  170. }
  171. }
  172. void CameraBase::updateFrustum() const
  173. {
  174. if (isFrustumOutOfDate())
  175. {
  176. float left, right, bottom, top;
  177. calcProjectionParameters(left, right, bottom, top);
  178. if (!mCustomProjMatrix)
  179. {
  180. float inv_w = 1 / (right - left);
  181. float inv_h = 1 / (top - bottom);
  182. float inv_d = 1 / (mFarDist - mNearDist);
  183. if (mProjType == PT_PERSPECTIVE)
  184. {
  185. float A = 2 * mNearDist * inv_w;
  186. float B = 2 * mNearDist * inv_h;
  187. float C = (right + left) * inv_w;
  188. float D = (top + bottom) * inv_h;
  189. float q, qn;
  190. if (mFarDist == 0)
  191. {
  192. // Infinite far plane
  193. q = CameraBase::INFINITE_FAR_PLANE_ADJUST - 1;
  194. qn = mNearDist * (CameraBase::INFINITE_FAR_PLANE_ADJUST - 2);
  195. }
  196. else
  197. {
  198. q = -(mFarDist + mNearDist) * inv_d;
  199. qn = -2 * (mFarDist * mNearDist) * inv_d;
  200. }
  201. mProjMatrix = Matrix4::ZERO;
  202. mProjMatrix[0][0] = A;
  203. mProjMatrix[0][2] = C;
  204. mProjMatrix[1][1] = B;
  205. mProjMatrix[1][2] = D;
  206. mProjMatrix[2][2] = q;
  207. mProjMatrix[2][3] = qn;
  208. mProjMatrix[3][2] = -1;
  209. }
  210. else if (mProjType == PT_ORTHOGRAPHIC)
  211. {
  212. float A = 2 * inv_w;
  213. float B = 2 * inv_h;
  214. float C = -(right + left) * inv_w;
  215. float D = -(top + bottom) * inv_h;
  216. float q, qn;
  217. if (mFarDist == 0)
  218. {
  219. // Can not do infinite far plane here, avoid divided zero only
  220. q = -CameraBase::INFINITE_FAR_PLANE_ADJUST / mNearDist;
  221. qn = -CameraBase::INFINITE_FAR_PLANE_ADJUST - 1;
  222. }
  223. else
  224. {
  225. q = -2 * inv_d;
  226. qn = -(mFarDist + mNearDist) * inv_d;
  227. }
  228. mProjMatrix = Matrix4::ZERO;
  229. mProjMatrix[0][0] = A;
  230. mProjMatrix[0][3] = C;
  231. mProjMatrix[1][1] = B;
  232. mProjMatrix[1][3] = D;
  233. mProjMatrix[2][2] = q;
  234. mProjMatrix[2][3] = qn;
  235. mProjMatrix[3][3] = 1;
  236. }
  237. }
  238. RenderAPICore* renderAPI = BansheeEngine::RenderAPICore::instancePtr();
  239. renderAPI->convertProjectionMatrix(mProjMatrix, mProjMatrixRS);
  240. mProjMatrixInv = mProjMatrix.inverse();
  241. mProjMatrixRSInv = mProjMatrixRS.inverse();
  242. // Calculate bounding box (local)
  243. // Box is from 0, down -Z, max dimensions as determined from far plane
  244. // If infinite view frustum just pick a far value
  245. float farDist = (mFarDist == 0) ? 100000 : mFarDist;
  246. // Near plane bounds
  247. Vector3 min(left, bottom, -farDist);
  248. Vector3 max(right, top, 0);
  249. if (mCustomProjMatrix)
  250. {
  251. // Some custom projection matrices can have unusual inverted settings
  252. // So make sure the AABB is the right way around to start with
  253. Vector3 tmp = min;
  254. min.floor(max);
  255. max.ceil(tmp);
  256. }
  257. if (mProjType == PT_PERSPECTIVE)
  258. {
  259. // Merge with far plane bounds
  260. float radio = farDist / mNearDist;
  261. min.floor(Vector3(left * radio, bottom * radio, -farDist));
  262. max.ceil(Vector3(right * radio, top * radio, 0));
  263. }
  264. mBoundingBox.setExtents(min, max);
  265. mRecalcFrustum = false;
  266. mRecalcFrustumPlanes = true;
  267. }
  268. }
  269. bool CameraBase::isFrustumOutOfDate() const
  270. {
  271. return mRecalcFrustum;
  272. }
  273. void CameraBase::updateView() const
  274. {
  275. if (!mCustomViewMatrix && mRecalcView)
  276. {
  277. mViewMatrix.makeView(mPosition, mRotation);
  278. mViewMatrixInv = mViewMatrix.inverseAffine();
  279. mRecalcView = false;
  280. }
  281. }
  282. void CameraBase::updateFrustumPlanes() const
  283. {
  284. updateFrustum();
  285. if (mRecalcFrustumPlanes)
  286. {
  287. Vector<Plane> frustumPlanes(6);
  288. Matrix4 combo = mProjMatrix;
  289. frustumPlanes[FRUSTUM_PLANE_LEFT].normal.x = combo[3][0] + combo[0][0];
  290. frustumPlanes[FRUSTUM_PLANE_LEFT].normal.y = combo[3][1] + combo[0][1];
  291. frustumPlanes[FRUSTUM_PLANE_LEFT].normal.z = combo[3][2] + combo[0][2];
  292. frustumPlanes[FRUSTUM_PLANE_LEFT].d = combo[3][3] + combo[0][3];
  293. frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.x = combo[3][0] - combo[0][0];
  294. frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.y = combo[3][1] - combo[0][1];
  295. frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.z = combo[3][2] - combo[0][2];
  296. frustumPlanes[FRUSTUM_PLANE_RIGHT].d = combo[3][3] - combo[0][3];
  297. frustumPlanes[FRUSTUM_PLANE_TOP].normal.x = combo[3][0] - combo[1][0];
  298. frustumPlanes[FRUSTUM_PLANE_TOP].normal.y = combo[3][1] - combo[1][1];
  299. frustumPlanes[FRUSTUM_PLANE_TOP].normal.z = combo[3][2] - combo[1][2];
  300. frustumPlanes[FRUSTUM_PLANE_TOP].d = combo[3][3] - combo[1][3];
  301. frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.x = combo[3][0] + combo[1][0];
  302. frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.y = combo[3][1] + combo[1][1];
  303. frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.z = combo[3][2] + combo[1][2];
  304. frustumPlanes[FRUSTUM_PLANE_BOTTOM].d = combo[3][3] + combo[1][3];
  305. frustumPlanes[FRUSTUM_PLANE_NEAR].normal.x = combo[3][0] + combo[2][0];
  306. frustumPlanes[FRUSTUM_PLANE_NEAR].normal.y = combo[3][1] + combo[2][1];
  307. frustumPlanes[FRUSTUM_PLANE_NEAR].normal.z = combo[3][2] + combo[2][2];
  308. frustumPlanes[FRUSTUM_PLANE_NEAR].d = combo[3][3] + combo[2][3];
  309. frustumPlanes[FRUSTUM_PLANE_FAR].normal.x = combo[3][0] - combo[2][0];
  310. frustumPlanes[FRUSTUM_PLANE_FAR].normal.y = combo[3][1] - combo[2][1];
  311. frustumPlanes[FRUSTUM_PLANE_FAR].normal.z = combo[3][2] - combo[2][2];
  312. frustumPlanes[FRUSTUM_PLANE_FAR].d = combo[3][3] - combo[2][3];
  313. for (UINT32 i = 0; i < 6; i++)
  314. {
  315. float length = frustumPlanes[i].normal.normalize();
  316. frustumPlanes[i].d /= -length;
  317. }
  318. mFrustum = ConvexVolume(frustumPlanes);
  319. mRecalcFrustumPlanes = false;
  320. }
  321. }
  322. float CameraBase::getAspectRatio() const
  323. {
  324. return mAspect;
  325. }
  326. void CameraBase::setAspectRatio(float r)
  327. {
  328. mAspect = r;
  329. invalidateFrustum();
  330. _markCoreDirty();
  331. }
  332. const AABox& CameraBase::getBoundingBox() const
  333. {
  334. updateFrustum();
  335. return mBoundingBox;
  336. }
  337. void CameraBase::setProjectionType(ProjectionType pt)
  338. {
  339. mProjType = pt;
  340. invalidateFrustum();
  341. _markCoreDirty();
  342. }
  343. ProjectionType CameraBase::getProjectionType() const
  344. {
  345. return mProjType;
  346. }
  347. void CameraBase::setCustomViewMatrix(bool enable, const Matrix4& viewMatrix)
  348. {
  349. mCustomViewMatrix = enable;
  350. if (enable)
  351. {
  352. BS_ASSERT(viewMatrix.isAffine());
  353. mViewMatrix = viewMatrix;
  354. mViewMatrixInv = mViewMatrix.inverseAffine();
  355. }
  356. _markCoreDirty();
  357. }
  358. void CameraBase::setCustomProjectionMatrix(bool enable, const Matrix4& projMatrix)
  359. {
  360. mCustomProjMatrix = enable;
  361. if (enable)
  362. mProjMatrix = projMatrix;
  363. invalidateFrustum();
  364. _markCoreDirty();
  365. }
  366. void CameraBase::setOrthoWindow(float w, float h)
  367. {
  368. mOrthoHeight = h;
  369. mAspect = w / h;
  370. invalidateFrustum();
  371. _markCoreDirty();
  372. }
  373. void CameraBase::setOrthoWindowHeight(float h)
  374. {
  375. mOrthoHeight = h;
  376. invalidateFrustum();
  377. _markCoreDirty();
  378. }
  379. void CameraBase::setOrthoWindowWidth(float w)
  380. {
  381. mOrthoHeight = w / mAspect;
  382. invalidateFrustum();
  383. _markCoreDirty();
  384. }
  385. float CameraBase::getOrthoWindowHeight() const
  386. {
  387. return mOrthoHeight;
  388. }
  389. float CameraBase::getOrthoWindowWidth() const
  390. {
  391. return mOrthoHeight * mAspect;
  392. }
  393. void CameraBase::setFrustumExtents(float left, float right, float top, float bottom)
  394. {
  395. mFrustumExtentsManuallySet = true;
  396. mLeft = left;
  397. mRight = right;
  398. mTop = top;
  399. mBottom = bottom;
  400. invalidateFrustum();
  401. _markCoreDirty();
  402. }
  403. void CameraBase::resetFrustumExtents()
  404. {
  405. mFrustumExtentsManuallySet = false;
  406. invalidateFrustum();
  407. _markCoreDirty();
  408. }
  409. void CameraBase::getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const
  410. {
  411. updateFrustum();
  412. outleft = mLeft;
  413. outright = mRight;
  414. outtop = mTop;
  415. outbottom = mBottom;
  416. }
  417. void CameraBase::setFlag(const CameraFlag& flag, bool enable)
  418. {
  419. if (enable)
  420. mCameraFlags.set(flag);
  421. else
  422. mCameraFlags.unset(flag);
  423. _markCoreDirty();
  424. }
  425. void CameraBase::setPosition(const Vector3& position)
  426. {
  427. mPosition = position;
  428. mRecalcView = true;
  429. _markCoreDirty(CameraDirtyFlag::Transform);
  430. }
  431. void CameraBase::setRotation(const Quaternion& rotation)
  432. {
  433. mRotation = rotation;
  434. mRecalcView = true;
  435. _markCoreDirty(CameraDirtyFlag::Transform);
  436. }
  437. void CameraBase::invalidateFrustum() const
  438. {
  439. mRecalcFrustum = true;
  440. mRecalcFrustumPlanes = true;
  441. }
  442. Vector2I CameraBase::worldToScreenPoint(const Vector3& worldPoint) const
  443. {
  444. Vector2 ndcPoint = worldToNdcPoint(worldPoint);
  445. return ndcToScreenPoint(ndcPoint);
  446. }
  447. Vector2 CameraBase::worldToNdcPoint(const Vector3& worldPoint) const
  448. {
  449. Vector3 viewPoint = worldToViewPoint(worldPoint);
  450. return viewToNdcPoint(viewPoint);
  451. }
  452. Vector3 CameraBase::worldToViewPoint(const Vector3& worldPoint) const
  453. {
  454. return getViewMatrix().multiplyAffine(worldPoint);
  455. }
  456. Vector3 CameraBase::screenToWorldPoint(const Vector2I& screenPoint, float depth) const
  457. {
  458. Vector2 ndcPoint = screenToNdcPoint(screenPoint);
  459. return ndcToWorldPoint(ndcPoint, depth);
  460. }
  461. Vector3 CameraBase::screenToViewPoint(const Vector2I& screenPoint, float depth) const
  462. {
  463. Vector2 ndcPoint = screenToNdcPoint(screenPoint);
  464. return ndcToViewPoint(ndcPoint, depth);
  465. }
  466. Vector2 CameraBase::screenToNdcPoint(const Vector2I& screenPoint) const
  467. {
  468. Rect2I viewport = getViewportRect();
  469. Vector2 ndcPoint;
  470. ndcPoint.x = (float)(((screenPoint.x - viewport.x) / (float)viewport.width) * 2.0f - 1.0f);
  471. ndcPoint.y = (float)((1.0f - ((screenPoint.y - viewport.y) / (float)viewport.height)) * 2.0f - 1.0f);
  472. return ndcPoint;
  473. }
  474. Vector3 CameraBase::viewToWorldPoint(const Vector3& viewPoint) const
  475. {
  476. return getViewMatrix().inverseAffine().multiplyAffine(viewPoint);
  477. }
  478. Vector2I CameraBase::viewToScreenPoint(const Vector3& viewPoint) const
  479. {
  480. Vector2 ndcPoint = viewToNdcPoint(viewPoint);
  481. return ndcToScreenPoint(ndcPoint);
  482. }
  483. Vector2 CameraBase::viewToNdcPoint(const Vector3& viewPoint) const
  484. {
  485. Vector3 projPoint = projectPoint(viewPoint);
  486. return Vector2(projPoint.x, projPoint.y);
  487. }
  488. Vector3 CameraBase::ndcToWorldPoint(const Vector2& ndcPoint, float depth) const
  489. {
  490. Vector3 viewPoint = ndcToViewPoint(ndcPoint, depth);
  491. return viewToWorldPoint(viewPoint);
  492. }
  493. Vector3 CameraBase::ndcToViewPoint(const Vector2& ndcPoint, float depth) const
  494. {
  495. return unprojectPoint(Vector3(ndcPoint.x, ndcPoint.y, depth));
  496. }
  497. Vector2I CameraBase::ndcToScreenPoint(const Vector2& ndcPoint) const
  498. {
  499. Rect2I viewport = getViewportRect();
  500. Vector2I screenPoint;
  501. screenPoint.x = Math::roundToInt(viewport.x + ((ndcPoint.x + 1.0f) * 0.5f) * viewport.width);
  502. screenPoint.y = Math::roundToInt(viewport.y + (1.0f - (ndcPoint.y + 1.0f) * 0.5f) * viewport.height);
  503. return screenPoint;
  504. }
  505. Ray CameraBase::screenPointToRay(const Vector2I& screenPoint) const
  506. {
  507. Vector2 ndcPoint = screenToNdcPoint(screenPoint);
  508. Vector3 near = unprojectPoint(Vector3(ndcPoint.x, ndcPoint.y, mNearDist));
  509. Vector3 far = unprojectPoint(Vector3(ndcPoint.x, ndcPoint.y, mNearDist + 1.0f));
  510. Ray ray(near, Vector3::normalize(far - near));
  511. ray.transformAffine(getViewMatrix().inverseAffine());
  512. return ray;
  513. }
  514. Vector3 CameraBase::projectPoint(const Vector3& point) const
  515. {
  516. Vector4 projPoint4(point.x, point.y, point.z, 1.0f);
  517. projPoint4 = getProjectionMatrixRS().multiply(projPoint4);
  518. if (Math::abs(projPoint4.w) > 1e-7f)
  519. {
  520. float invW = 1.0f / projPoint4.w;
  521. projPoint4.x *= invW;
  522. projPoint4.y *= invW;
  523. projPoint4.z *= invW;
  524. }
  525. else
  526. {
  527. projPoint4.x = 0.0f;
  528. projPoint4.y = 0.0f;
  529. projPoint4.z = 0.0f;
  530. }
  531. return Vector3(projPoint4.x, projPoint4.y, projPoint4.z);
  532. }
  533. Vector3 CameraBase::unprojectPoint(const Vector3& point) const
  534. {
  535. // Point.z is expected to be in view space, so we need to do some extra work to get the proper coordinates
  536. // (as opposed to if point.z was in device coordinates, in which case we could just inverse project)
  537. // Get world position for a point near the far plane (0.95f)
  538. Vector4 farAwayPoint(point.x, point.y, 0.95f, 1.0f);
  539. farAwayPoint = getProjectionMatrixRS().inverse().multiply(farAwayPoint);
  540. // Can't proceed if w is too small
  541. if (Math::abs(farAwayPoint.w) > 1e-7f)
  542. {
  543. // Perspective divide, to get the values that make sense in 3D space
  544. float invW = 1.0f / farAwayPoint.w;
  545. Vector3 farAwayPoint3D;
  546. farAwayPoint3D.x = farAwayPoint.x * invW;
  547. farAwayPoint3D.y = farAwayPoint.y * invW;
  548. farAwayPoint3D.z = farAwayPoint.z * invW;
  549. // Find the distance to the far point along the camera's viewing axis
  550. float distAlongZ = farAwayPoint3D.dot(-Vector3::UNIT_Z);
  551. // Do nothing if point is behind the camera
  552. if (distAlongZ >= 0.0f)
  553. {
  554. if (mProjType == PT_PERSPECTIVE)
  555. {
  556. // Direction from origin to our point
  557. Vector3 dir = farAwayPoint3D; // Camera is at (0, 0, 0) so it's the same vector
  558. // Our view space depth (point.z) is distance along the camera's viewing axis. Since our direction
  559. // vector is not parallel to the viewing axis, instead of normalizing it with its own length, we
  560. // "normalize" with the length projected along the camera's viewing axis.
  561. dir /= distAlongZ;
  562. // And now we just find the final position along the direction
  563. return dir * point.z;
  564. }
  565. else // Ortographic
  566. {
  567. // Depth difference between our arbitrary point and actual depth
  568. float depthDiff = distAlongZ - point.z;
  569. // Depth difference along viewing direction
  570. Vector3 depthDiffVec = depthDiff * -Vector3::UNIT_Z;
  571. // Return point that is depthDiff closer than our arbitrary point
  572. return farAwayPoint3D - depthDiffVec;
  573. }
  574. }
  575. }
  576. return Vector3(0.0f, 0.0f, 0.0f);
  577. }
  578. CameraCore::~CameraCore()
  579. {
  580. RendererManager::instance().getActive()->notifyCameraRemoved(this);
  581. }
  582. CameraCore::CameraCore(SPtr<RenderTargetCore> target, float left, float top, float width, float height)
  583. {
  584. mViewport = ViewportCore::create(target, left, top, width, height);
  585. }
  586. CameraCore::CameraCore(const SPtr<ViewportCore>& viewport)
  587. {
  588. mViewport = viewport;
  589. }
  590. void CameraCore::initialize()
  591. {
  592. RendererManager::instance().getActive()->notifyCameraAdded(this);
  593. CoreObjectCore::initialize();
  594. }
  595. Rect2I CameraCore::getViewportRect() const
  596. {
  597. return mViewport->getArea();
  598. }
  599. void CameraCore::syncToCore(const CoreSyncData& data)
  600. {
  601. char* dataPtr = (char*)data.getBuffer();
  602. CameraDirtyFlag dirtyFlag;
  603. dataPtr = rttiReadElem(dirtyFlag, dataPtr);
  604. dataPtr = rttiReadElem(mPosition, dataPtr);
  605. dataPtr = rttiReadElem(mRotation, dataPtr);
  606. mRecalcFrustum = true;
  607. mRecalcFrustumPlanes = true;
  608. mRecalcView = true;
  609. if (dirtyFlag != CameraDirtyFlag::Transform)
  610. {
  611. dataPtr = rttiReadElem(mLayers, dataPtr);
  612. dataPtr = rttiReadElem(mProjType, dataPtr);
  613. dataPtr = rttiReadElem(mHorzFOV, dataPtr);
  614. dataPtr = rttiReadElem(mFarDist, dataPtr);
  615. dataPtr = rttiReadElem(mNearDist, dataPtr);
  616. dataPtr = rttiReadElem(mAspect, dataPtr);
  617. dataPtr = rttiReadElem(mOrthoHeight, dataPtr);
  618. dataPtr = rttiReadElem(mPriority, dataPtr);
  619. dataPtr = rttiReadElem(mCustomViewMatrix, dataPtr);
  620. dataPtr = rttiReadElem(mCustomProjMatrix, dataPtr);
  621. dataPtr = rttiReadElem(mFrustumExtentsManuallySet, dataPtr);
  622. dataPtr = rttiReadElem(mCameraFlags, dataPtr);
  623. dataPtr = rttiReadElem(mIsActive, dataPtr);
  624. dataPtr = rttiReadElem(mMSAA, dataPtr);
  625. UINT32 ppSize = 0;
  626. dataPtr = rttiReadElem(ppSize, dataPtr);
  627. if(ppSize > 0)
  628. {
  629. if (mPPSettings == nullptr)
  630. mPPSettings = RendererManager::instance().getActive()->createPostProcessSettings();
  631. mPPSettings->_setSyncData((UINT8*)dataPtr, ppSize);
  632. dataPtr += ppSize;
  633. }
  634. }
  635. RendererManager::instance().getActive()->notifyCameraUpdated(this, (UINT32)dirtyFlag);
  636. }
  637. Camera::Camera(SPtr<RenderTarget> target, float left, float top, float width, float height)
  638. :mMain(false), mLastUpdateHash(0)
  639. {
  640. if (target != nullptr)
  641. target->blockUntilCoreInitialized();
  642. mViewport = Viewport::create(target, left, top, width, height);
  643. }
  644. SPtr<CameraCore> Camera::getCore() const
  645. {
  646. return std::static_pointer_cast<CameraCore>(mCoreSpecific);
  647. }
  648. SPtr<Camera> Camera::create(SPtr<RenderTarget> target, float left, float top, float width, float height)
  649. {
  650. Camera* handler = new (bs_alloc<Camera>()) Camera(target, left, top, width, height);
  651. SPtr<Camera> handlerPtr = bs_core_ptr<Camera>(handler);
  652. handlerPtr->_setThisPtr(handlerPtr);
  653. handlerPtr->initialize();
  654. return handlerPtr;
  655. }
  656. SPtr<Camera> Camera::createEmpty()
  657. {
  658. Camera* handler = new (bs_alloc<Camera>()) Camera();
  659. SPtr<Camera> handlerPtr = bs_core_ptr<Camera>(handler);
  660. handlerPtr->_setThisPtr(handlerPtr);
  661. return handlerPtr;
  662. }
  663. SPtr<CoreObjectCore> Camera::createCore() const
  664. {
  665. CameraCore* handler = new (bs_alloc<CameraCore>()) CameraCore(mViewport->getCore());
  666. SPtr<CameraCore> handlerPtr = bs_shared_ptr<CameraCore>(handler);
  667. handlerPtr->_setThisPtr(handlerPtr);
  668. return handlerPtr;
  669. }
  670. Rect2I Camera::getViewportRect() const
  671. {
  672. return mViewport->getArea();
  673. }
  674. CoreSyncData Camera::syncToCore(FrameAlloc* allocator)
  675. {
  676. UINT32 dirtyFlag = getCoreDirtyFlags();
  677. UINT32 size = 0;
  678. size += rttiGetElemSize(dirtyFlag);
  679. size += rttiGetElemSize(mPosition);
  680. size += rttiGetElemSize(mRotation);
  681. UINT32 ppSize = 0;
  682. if (dirtyFlag != (UINT32)CameraDirtyFlag::Transform)
  683. {
  684. size += rttiGetElemSize(mLayers);
  685. size += rttiGetElemSize(mProjType);
  686. size += rttiGetElemSize(mHorzFOV);
  687. size += rttiGetElemSize(mFarDist);
  688. size += rttiGetElemSize(mNearDist);
  689. size += rttiGetElemSize(mAspect);
  690. size += rttiGetElemSize(mOrthoHeight);
  691. size += rttiGetElemSize(mPriority);
  692. size += rttiGetElemSize(mCustomViewMatrix);
  693. size += rttiGetElemSize(mCustomProjMatrix);
  694. size += rttiGetElemSize(mFrustumExtentsManuallySet);
  695. size += rttiGetElemSize(mCameraFlags);
  696. size += rttiGetElemSize(mIsActive);
  697. size += rttiGetElemSize(mMSAA);
  698. size += sizeof(UINT32);
  699. if(mPPSettings != nullptr)
  700. {
  701. mPPSettings->_getSyncData(nullptr, ppSize);
  702. size += ppSize;
  703. }
  704. }
  705. UINT8* buffer = allocator->alloc(size);
  706. char* dataPtr = (char*)buffer;
  707. dataPtr = rttiWriteElem(dirtyFlag, dataPtr);
  708. dataPtr = rttiWriteElem(mPosition, dataPtr);
  709. dataPtr = rttiWriteElem(mRotation, dataPtr);
  710. if (dirtyFlag != (UINT32)CameraDirtyFlag::Transform)
  711. {
  712. dataPtr = rttiWriteElem(mLayers, dataPtr);
  713. dataPtr = rttiWriteElem(mProjType, dataPtr);
  714. dataPtr = rttiWriteElem(mHorzFOV, dataPtr);
  715. dataPtr = rttiWriteElem(mFarDist, dataPtr);
  716. dataPtr = rttiWriteElem(mNearDist, dataPtr);
  717. dataPtr = rttiWriteElem(mAspect, dataPtr);
  718. dataPtr = rttiWriteElem(mOrthoHeight, dataPtr);
  719. dataPtr = rttiWriteElem(mPriority, dataPtr);
  720. dataPtr = rttiWriteElem(mCustomViewMatrix, dataPtr);
  721. dataPtr = rttiWriteElem(mCustomProjMatrix, dataPtr);
  722. dataPtr = rttiWriteElem(mFrustumExtentsManuallySet, dataPtr);
  723. dataPtr = rttiWriteElem(mCameraFlags, dataPtr);
  724. dataPtr = rttiWriteElem(mIsActive, dataPtr);
  725. dataPtr = rttiWriteElem(mMSAA, dataPtr);
  726. dataPtr = rttiWriteElem(ppSize, dataPtr);
  727. if(mPPSettings != nullptr)
  728. mPPSettings->_getSyncData((UINT8*)dataPtr, ppSize);
  729. dataPtr += ppSize;
  730. }
  731. return CoreSyncData(buffer, size);
  732. }
  733. void Camera::getCoreDependencies(Vector<CoreObject*>& dependencies)
  734. {
  735. dependencies.push_back(mViewport.get());
  736. }
  737. void Camera::_markCoreDirty(CameraDirtyFlag flag)
  738. {
  739. markCoreDirty((UINT32)flag);
  740. }
  741. RTTITypeBase* Camera::getRTTIStatic()
  742. {
  743. return CameraRTTI::instance();
  744. }
  745. RTTITypeBase* Camera::getRTTI() const
  746. {
  747. return Camera::getRTTIStatic();
  748. }
  749. }