2
0

BsCamera.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. #include "BsCamera.h"
  2. #include "BsCameraRTTI.h"
  3. #include "BsMath.h"
  4. #include "BsMatrix3.h"
  5. #include "BsVector2.h"
  6. #include "BsAABox.h"
  7. #include "BsSphere.h"
  8. #include "BsHardwareBufferManager.h"
  9. #include "BsVertexBuffer.h"
  10. #include "BsIndexBuffer.h"
  11. #include "BsException.h"
  12. #include "BsRenderSystem.h"
  13. #include "BsSceneObject.h"
  14. namespace BansheeEngine
  15. {
  16. const float Camera::INFINITE_FAR_PLANE_ADJUST = 0.00001f;
  17. Camera::Camera(const HSceneObject& parent, RenderTargetPtr target, float left, float top, float width, float height)
  18. : Component(parent), mProjType(PT_PERSPECTIVE), mHorzFOV(Radian(Math::PI/4.0f)), mFarDist(100000.0f),
  19. mNearDist(100.0f), mAspect(1.33333333333333f), mOrthoHeight(1000), mRecalcFrustum(true), mRecalcFrustumPlanes(true),
  20. mCustomViewMatrix(false), mCustomProjMatrix(false), mFrustumExtentsManuallySet(false), mIgnoreSceneRenderables(false),
  21. mPriority(0), mLayers(0xFFFFFFFFFFFFFFFF)
  22. {
  23. setName("Camera");
  24. updateView();
  25. updateFrustum();
  26. invalidateFrustum();
  27. mViewMatrix = Matrix4::ZERO;
  28. mProjMatrixRS = Matrix4::ZERO;
  29. target->synchronize();
  30. mViewport = bs_shared_ptr<Viewport, PoolAlloc>(target, left, top, width, height);
  31. }
  32. Camera::~Camera()
  33. {
  34. }
  35. void Camera::setHorzFOV(const Radian& fov)
  36. {
  37. mHorzFOV = fov;
  38. invalidateFrustum();
  39. }
  40. const Radian& Camera::getHorzFOV() const
  41. {
  42. return mHorzFOV;
  43. }
  44. void Camera::setFarClipDistance(float farPlane)
  45. {
  46. mFarDist = farPlane;
  47. invalidateFrustum();
  48. }
  49. float Camera::getFarClipDistance() const
  50. {
  51. return mFarDist;
  52. }
  53. void Camera::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. }
  62. float Camera::getNearClipDistance() const
  63. {
  64. return mNearDist;
  65. }
  66. const Matrix4& Camera::getProjectionMatrix() const
  67. {
  68. updateFrustum();
  69. return mProjMatrix;
  70. }
  71. const Matrix4& Camera::getProjectionMatrixRS() const
  72. {
  73. updateFrustum();
  74. return mProjMatrixRS;
  75. }
  76. const Matrix4& Camera::getViewMatrix() const
  77. {
  78. updateView();
  79. return mViewMatrix;
  80. }
  81. const Plane* Camera::getFrustumPlanes() const
  82. {
  83. // Make any pending updates to the calculated frustum planes
  84. updateFrustumPlanes();
  85. return mFrustumPlanes;
  86. }
  87. const Plane& Camera::getFrustumPlane(UINT16 plane) const
  88. {
  89. // Make any pending updates to the calculated frustum planes
  90. updateFrustumPlanes();
  91. return mFrustumPlanes[plane];
  92. }
  93. bool Camera::isVisible(const AABox& bound, FrustumPlane* culledBy) const
  94. {
  95. // Make any pending updates to the calculated frustum planes
  96. updateFrustumPlanes();
  97. // For each plane, see if all points are on the negative side
  98. // If so, object is not visible
  99. for (int plane = 0; plane < 6; ++plane)
  100. {
  101. // Skip far plane if infinite view frustum
  102. if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0)
  103. continue;
  104. Plane::Side side = mFrustumPlanes[plane].getSide(bound);
  105. if (side == Plane::NEGATIVE_SIDE)
  106. {
  107. // ALL corners on negative side therefore out of view
  108. if (culledBy)
  109. *culledBy = (FrustumPlane)plane;
  110. return false;
  111. }
  112. }
  113. return true;
  114. }
  115. bool Camera::isVisible(const Vector3& vert, FrustumPlane* culledBy) const
  116. {
  117. // Make any pending updates to the calculated frustum planes
  118. updateFrustumPlanes();
  119. // For each plane, see if all points are on the negative side
  120. // If so, object is not visible
  121. for (int plane = 0; plane < 6; ++plane)
  122. {
  123. // Skip far plane if infinite view frustum
  124. if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0)
  125. continue;
  126. if (mFrustumPlanes[plane].getSide(vert) == Plane::NEGATIVE_SIDE)
  127. {
  128. // ALL corners on negative side therefore out of view
  129. if (culledBy)
  130. *culledBy = (FrustumPlane)plane;
  131. return false;
  132. }
  133. }
  134. return true;
  135. }
  136. bool Camera::isVisible(const Sphere& sphere, FrustumPlane* culledBy) const
  137. {
  138. // Make any pending updates to the calculated frustum planes
  139. updateFrustumPlanes();
  140. // For each plane, see if sphere is on negative side
  141. // If so, object is not visible
  142. for (int plane = 0; plane < 6; ++plane)
  143. {
  144. // Skip far plane if infinite view frustum
  145. if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0)
  146. continue;
  147. // If the distance from sphere center to plane is negative, and 'more negative'
  148. // than the radius of the sphere, sphere is outside frustum
  149. if (mFrustumPlanes[plane].getDistance(sphere.getCenter()) < -sphere.getRadius())
  150. {
  151. // ALL corners on negative side therefore out of view
  152. if (culledBy)
  153. *culledBy = (FrustumPlane)plane;
  154. return false;
  155. }
  156. }
  157. return true;
  158. }
  159. void Camera::calcProjectionParameters(float& left, float& right, float& bottom, float& top) const
  160. {
  161. if (mCustomProjMatrix)
  162. {
  163. // Convert clipspace corners to camera space
  164. Matrix4 invProj = mProjMatrix.inverse();
  165. Vector3 topLeft(-0.5f, 0.5f, 0.0f);
  166. Vector3 bottomRight(0.5f, -0.5f, 0.0f);
  167. topLeft = invProj.multiply(topLeft);
  168. bottomRight = invProj.multiply(bottomRight);
  169. left = topLeft.x;
  170. top = topLeft.y;
  171. right = bottomRight.x;
  172. bottom = bottomRight.y;
  173. }
  174. else
  175. {
  176. if (mFrustumExtentsManuallySet)
  177. {
  178. left = mLeft;
  179. right = mRight;
  180. top = mTop;
  181. bottom = mBottom;
  182. }
  183. else if (mProjType == PT_PERSPECTIVE)
  184. {
  185. Radian thetaY (mHorzFOV * 0.5f);
  186. float tanThetaY = Math::tan(thetaY);
  187. float tanThetaX = tanThetaY * mAspect;
  188. float half_w = tanThetaX * mNearDist;
  189. float half_h = tanThetaY * mNearDist;
  190. left = -half_w;
  191. right = half_w;
  192. bottom = -half_h;
  193. top = half_h;
  194. mLeft = left;
  195. mRight = right;
  196. mTop = top;
  197. mBottom = bottom;
  198. }
  199. else
  200. {
  201. float half_w = getOrthoWindowWidth() * 0.5f;
  202. float half_h = getOrthoWindowHeight() * 0.5f;
  203. left = -half_w;
  204. right = half_w;
  205. bottom = -half_h;
  206. top = half_h;
  207. mLeft = left;
  208. mRight = right;
  209. mTop = top;
  210. mBottom = bottom;
  211. }
  212. }
  213. }
  214. void Camera::updateFrustum() const
  215. {
  216. if (isFrustumOutOfDate())
  217. {
  218. float left, right, bottom, top;
  219. calcProjectionParameters(left, right, bottom, top);
  220. if (!mCustomProjMatrix)
  221. {
  222. float inv_w = 1 / (right - left);
  223. float inv_h = 1 / (top - bottom);
  224. float inv_d = 1 / (mFarDist - mNearDist);
  225. if (mProjType == PT_PERSPECTIVE)
  226. {
  227. float A = 2 * mNearDist * inv_w;
  228. float B = 2 * mNearDist * inv_h;
  229. float C = (right + left) * inv_w;
  230. float D = (top + bottom) * inv_h;
  231. float q, qn;
  232. if (mFarDist == 0)
  233. {
  234. // Infinite far plane
  235. q = Camera::INFINITE_FAR_PLANE_ADJUST - 1;
  236. qn = mNearDist * (Camera::INFINITE_FAR_PLANE_ADJUST - 2);
  237. }
  238. else
  239. {
  240. q = - (mFarDist + mNearDist) * inv_d;
  241. qn = -2 * (mFarDist * mNearDist) * inv_d;
  242. }
  243. mProjMatrix = Matrix4::ZERO;
  244. mProjMatrix[0][0] = A;
  245. mProjMatrix[0][2] = C;
  246. mProjMatrix[1][1] = B;
  247. mProjMatrix[1][2] = D;
  248. mProjMatrix[2][2] = q;
  249. mProjMatrix[2][3] = qn;
  250. mProjMatrix[3][2] = -1;
  251. }
  252. else if (mProjType == PT_ORTHOGRAPHIC)
  253. {
  254. float A = 2 * inv_w;
  255. float B = 2 * inv_h;
  256. float C = - (right + left) * inv_w;
  257. float D = - (top + bottom) * inv_h;
  258. float q, qn;
  259. if (mFarDist == 0)
  260. {
  261. // Can not do infinite far plane here, avoid divided zero only
  262. q = - Camera::INFINITE_FAR_PLANE_ADJUST / mNearDist;
  263. qn = - Camera::INFINITE_FAR_PLANE_ADJUST - 1;
  264. }
  265. else
  266. {
  267. q = - 2 * inv_d;
  268. qn = - (mFarDist + mNearDist) * inv_d;
  269. }
  270. mProjMatrix = Matrix4::ZERO;
  271. mProjMatrix[0][0] = A;
  272. mProjMatrix[0][3] = C;
  273. mProjMatrix[1][1] = B;
  274. mProjMatrix[1][3] = D;
  275. mProjMatrix[2][2] = q;
  276. mProjMatrix[2][3] = qn;
  277. mProjMatrix[3][3] = 1;
  278. }
  279. }
  280. RenderSystem* renderSystem = BansheeEngine::RenderSystem::instancePtr();
  281. renderSystem->convertProjectionMatrix(mProjMatrix, mProjMatrixRS);
  282. // Calculate bounding box (local)
  283. // Box is from 0, down -Z, max dimensions as determined from far plane
  284. // If infinite view frustum just pick a far value
  285. float farDist = (mFarDist == 0) ? 100000 : mFarDist;
  286. // Near plane bounds
  287. Vector3 min(left, bottom, -farDist);
  288. Vector3 max(right, top, 0);
  289. if (mCustomProjMatrix)
  290. {
  291. // Some custom projection matrices can have unusual inverted settings
  292. // So make sure the AABB is the right way around to start with
  293. Vector3 tmp = min;
  294. min.floor(max);
  295. max.ceil(tmp);
  296. }
  297. if (mProjType == PT_PERSPECTIVE)
  298. {
  299. // Merge with far plane bounds
  300. float radio = farDist / mNearDist;
  301. min.floor(Vector3(left * radio, bottom * radio, -farDist));
  302. max.ceil(Vector3(right * radio, top * radio, 0));
  303. }
  304. mBoundingBox.setExtents(min, max);
  305. mRecalcFrustum = false;
  306. mRecalcFrustumPlanes = true;
  307. }
  308. }
  309. bool Camera::isFrustumOutOfDate() const
  310. {
  311. return mRecalcFrustum;
  312. }
  313. void Camera::updateView() const
  314. {
  315. if (!mCustomViewMatrix)
  316. {
  317. Matrix3 rot;
  318. const Quaternion& orientation = sceneObject()->getWorldRotation();
  319. const Vector3& position = sceneObject()->getWorldPosition();
  320. mViewMatrix.makeView(position, orientation);
  321. }
  322. }
  323. void Camera::updateFrustumPlanes() const
  324. {
  325. updateView();
  326. updateFrustum();
  327. if (mRecalcFrustumPlanes)
  328. {
  329. Matrix4 combo = mProjMatrix * mViewMatrix;
  330. mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal.x = combo[3][0] + combo[0][0];
  331. mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal.y = combo[3][1] + combo[0][1];
  332. mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal.z = combo[3][2] + combo[0][2];
  333. mFrustumPlanes[FRUSTUM_PLANE_LEFT].d = combo[3][3] + combo[0][3];
  334. mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal.x = combo[3][0] - combo[0][0];
  335. mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal.y = combo[3][1] - combo[0][1];
  336. mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal.z = combo[3][2] - combo[0][2];
  337. mFrustumPlanes[FRUSTUM_PLANE_RIGHT].d = combo[3][3] - combo[0][3];
  338. mFrustumPlanes[FRUSTUM_PLANE_TOP].normal.x = combo[3][0] - combo[1][0];
  339. mFrustumPlanes[FRUSTUM_PLANE_TOP].normal.y = combo[3][1] - combo[1][1];
  340. mFrustumPlanes[FRUSTUM_PLANE_TOP].normal.z = combo[3][2] - combo[1][2];
  341. mFrustumPlanes[FRUSTUM_PLANE_TOP].d = combo[3][3] - combo[1][3];
  342. mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.x = combo[3][0] + combo[1][0];
  343. mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.y = combo[3][1] + combo[1][1];
  344. mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.z = combo[3][2] + combo[1][2];
  345. mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].d = combo[3][3] + combo[1][3];
  346. mFrustumPlanes[FRUSTUM_PLANE_NEAR].normal.x = combo[3][0] + combo[2][0];
  347. mFrustumPlanes[FRUSTUM_PLANE_NEAR].normal.y = combo[3][1] + combo[2][1];
  348. mFrustumPlanes[FRUSTUM_PLANE_NEAR].normal.z = combo[3][2] + combo[2][2];
  349. mFrustumPlanes[FRUSTUM_PLANE_NEAR].d = combo[3][3] + combo[2][3];
  350. mFrustumPlanes[FRUSTUM_PLANE_FAR].normal.x = combo[3][0] - combo[2][0];
  351. mFrustumPlanes[FRUSTUM_PLANE_FAR].normal.y = combo[3][1] - combo[2][1];
  352. mFrustumPlanes[FRUSTUM_PLANE_FAR].normal.z = combo[3][2] - combo[2][2];
  353. mFrustumPlanes[FRUSTUM_PLANE_FAR].d = combo[3][3] - combo[2][3];
  354. for(int i=0; i<6; i++ )
  355. {
  356. float length = mFrustumPlanes[i].normal.normalize();
  357. mFrustumPlanes[i].d /= length;
  358. }
  359. mRecalcFrustumPlanes = false;
  360. }
  361. }
  362. float Camera::getAspectRatio(void) const
  363. {
  364. return mAspect;
  365. }
  366. void Camera::setAspectRatio(float r)
  367. {
  368. mAspect = r;
  369. invalidateFrustum();
  370. }
  371. const AABox& Camera::getBoundingBox() const
  372. {
  373. updateFrustum();
  374. return mBoundingBox;
  375. }
  376. void Camera::setProjectionType(ProjectionType pt)
  377. {
  378. mProjType = pt;
  379. invalidateFrustum();
  380. }
  381. ProjectionType Camera::getProjectionType() const
  382. {
  383. return mProjType;
  384. }
  385. void Camera::setCustomViewMatrix(bool enable, const Matrix4& viewMatrix)
  386. {
  387. mCustomViewMatrix = enable;
  388. if (enable)
  389. {
  390. assert(viewMatrix.isAffine());
  391. mViewMatrix = viewMatrix;
  392. }
  393. }
  394. void Camera::setCustomProjectionMatrix(bool enable, const Matrix4& projMatrix)
  395. {
  396. mCustomProjMatrix = enable;
  397. if (enable)
  398. mProjMatrix = projMatrix;
  399. invalidateFrustum();
  400. }
  401. void Camera::setOrthoWindow(float w, float h)
  402. {
  403. mOrthoHeight = h;
  404. mAspect = w / h;
  405. invalidateFrustum();
  406. }
  407. void Camera::setOrthoWindowHeight(float h)
  408. {
  409. mOrthoHeight = h;
  410. invalidateFrustum();
  411. }
  412. void Camera::setOrthoWindowWidth(float w)
  413. {
  414. mOrthoHeight = w / mAspect;
  415. invalidateFrustum();
  416. }
  417. float Camera::getOrthoWindowHeight() const
  418. {
  419. return mOrthoHeight;
  420. }
  421. float Camera::getOrthoWindowWidth() const
  422. {
  423. return mOrthoHeight * mAspect;
  424. }
  425. void Camera::setFrustumExtents(float left, float right, float top, float bottom)
  426. {
  427. mFrustumExtentsManuallySet = true;
  428. mLeft = left;
  429. mRight = right;
  430. mTop = top;
  431. mBottom = bottom;
  432. invalidateFrustum();
  433. }
  434. void Camera::resetFrustumExtents()
  435. {
  436. mFrustumExtentsManuallySet = false;
  437. invalidateFrustum();
  438. }
  439. void Camera::getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const
  440. {
  441. updateFrustum();
  442. outleft = mLeft;
  443. outright = mRight;
  444. outtop = mTop;
  445. outbottom = mBottom;
  446. }
  447. void Camera::invalidateFrustum() const
  448. {
  449. mRecalcFrustumPlanes = true;
  450. }
  451. RTTITypeBase* Camera::getRTTIStatic()
  452. {
  453. return CameraRTTI::instance();
  454. }
  455. RTTITypeBase* Camera::getRTTI() const
  456. {
  457. return Camera::getRTTIStatic();
  458. }
  459. }