BsCamera.cpp 25 KB

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