Camera.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  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. #include "Precompiled.h"
  24. #include "Camera.h"
  25. #include "RendererDefs.h"
  26. #include "ReplicationUtils.h"
  27. #include "XMLElement.h"
  28. #include <cstring>
  29. #include "DebugNew.h"
  30. static const float DEFAULT_NEARCLIP = 0.1f;
  31. static const float DEFAULT_FARCLIP = 1000.0f;
  32. static const float DEFAULT_FOV = 45.0f;
  33. static const float DEFAULT_ORTHOSIZE = 20.0f;
  34. Camera::Camera(const std::string& name) :
  35. Node(NODE_CAMERA, name),
  36. mNearClip(DEFAULT_NEARCLIP),
  37. mFarClip(DEFAULT_FARCLIP),
  38. mFov(DEFAULT_FOV),
  39. mOrthoSize(DEFAULT_ORTHOSIZE),
  40. mAspectRatio(1.0f),
  41. mZoom(1.0f),
  42. mLodBias(1.0f),
  43. mOrthographic(false),
  44. mAutoAspectRatio(true),
  45. mViewMask(VIEW_MAIN),
  46. mDrawShadowsOverride(true),
  47. mLightDetailLevelOverride(QUALITY_MAX),
  48. mMaterialQualityOverride(QUALITY_MAX),
  49. mMaxOccluderTrianglesOverride(M_MAX_INT),
  50. mInverseWorldTransformDirty(true),
  51. mFrustumDirty(true),
  52. mProjectionDirty(true),
  53. mFrustumSizeDirty(true)
  54. {
  55. }
  56. Camera::~Camera()
  57. {
  58. }
  59. void Camera::save(Serializer& dest)
  60. {
  61. // Write Node properties
  62. Node::save(dest);
  63. // Write Camera properties
  64. dest.writeFloat(mNearClip);
  65. dest.writeFloat(mFarClip);
  66. dest.writeFloat(mFov);
  67. dest.writeFloat(mOrthoSize);
  68. dest.writeFloat(mAspectRatio);
  69. dest.writeFloat(mZoom);
  70. dest.writeFloat(mLodBias);
  71. dest.writeBool(mOrthographic);
  72. dest.writeBool(mAutoAspectRatio);
  73. dest.writeUInt(mViewMask);
  74. dest.writeBool(mDrawShadowsOverride);
  75. dest.writeUByte(mLightDetailLevelOverride);
  76. dest.writeUByte(mMaterialQualityOverride);
  77. dest.writeInt(mMaxOccluderTrianglesOverride);
  78. }
  79. void Camera::load(Deserializer& source, ResourceCache* cache)
  80. {
  81. // Read Node properties
  82. Node::load(source, cache);
  83. // Read Camera properties
  84. mNearClip = source.readFloat();
  85. mFarClip = source.readFloat();
  86. mFov = source.readFloat();
  87. mOrthoSize = source.readFloat();
  88. mAspectRatio = source.readFloat();
  89. mZoom = source.readFloat();
  90. mLodBias = source.readFloat();
  91. mOrthographic = source.readBool();
  92. mAutoAspectRatio = source.readBool();
  93. mViewMask = source.readUInt();
  94. mDrawShadowsOverride = source.readBool();
  95. mLightDetailLevelOverride = source.readUByte();
  96. mMaterialQualityOverride = source.readUByte();
  97. mMaxOccluderTrianglesOverride = source.readInt();
  98. markProjectionDirty();
  99. }
  100. void Camera::saveXML(XMLElement& dest)
  101. {
  102. // Write Node properties
  103. Node::saveXML(dest);
  104. // Write Camera properties
  105. XMLElement projectionElem = dest.createChildElement("projection");
  106. projectionElem.setFloat("nearclip", mNearClip);
  107. projectionElem.setFloat("farclip", mFarClip);
  108. projectionElem.setBool("orthographic", mOrthographic);
  109. projectionElem.setFloat("fov", mFov);
  110. projectionElem.setFloat("orthosize", mOrthoSize);
  111. projectionElem.setFloat("aspectratio", mAspectRatio);
  112. projectionElem.setBool("autoaspect", mAutoAspectRatio);
  113. projectionElem.setFloat("zoom", mZoom);
  114. XMLElement lodElem = dest.createChildElement("lod");
  115. lodElem.setInt("viewmask", mViewMask);
  116. lodElem.setFloat("lodbias", mLodBias);
  117. XMLElement overrideElem = dest.createChildElement("override");
  118. overrideElem.setBool("drawshadows", mDrawShadowsOverride);
  119. overrideElem.setInt("lightdetail", mLightDetailLevelOverride);
  120. overrideElem.setInt("matquality", mMaterialQualityOverride);
  121. overrideElem.setInt("occludertris", mMaxOccluderTrianglesOverride);
  122. }
  123. void Camera::loadXML(const XMLElement& source, ResourceCache* cache)
  124. {
  125. // Read Node properties
  126. Node::loadXML(source, cache);
  127. // Read Camera properties
  128. XMLElement projectionElem = source.getChildElement("projection");
  129. mNearClip = projectionElem.getFloat("nearclip");
  130. mFarClip = projectionElem.getFloat("farclip");
  131. mOrthographic = projectionElem.getBool("orthographic");
  132. mFov = projectionElem.getFloat("fov");
  133. mOrthoSize = projectionElem.getFloat("orthosize");
  134. mAspectRatio = projectionElem.getFloat("aspectratio");
  135. mAutoAspectRatio = projectionElem.getFloat("autoaspectratio");
  136. mZoom = projectionElem.getFloat("zoom");
  137. XMLElement lodElem = source.getChildElement("lod");
  138. mViewMask = lodElem.getInt("viewmask");
  139. mLodBias = lodElem.getFloat("lodbias");
  140. XMLElement overrideElem = source.getChildElement("override");
  141. mDrawShadowsOverride = overrideElem.getBool("drawshadows");
  142. mLightDetailLevelOverride = overrideElem.getInt("lightdetail");
  143. mMaterialQualityOverride = overrideElem.getInt("matquality");
  144. mMaxOccluderTrianglesOverride = overrideElem.getInt("occludertris");
  145. }
  146. bool Camera::writeNetUpdate(Serializer& dest, Serializer& destRevision, Deserializer& baseRevision, const NetUpdateInfo& info)
  147. {
  148. // Write Node properties and see if there were any changes
  149. bool prevBits = Node::writeNetUpdate(dest, destRevision, baseRevision, info);
  150. // Build bitmask of changed properties
  151. unsigned char bits = 0;
  152. unsigned char qualityOverrides = mLightDetailLevelOverride | (mMaterialQualityOverride << 4);
  153. checkFloat(mNearClip, DEFAULT_NEARCLIP, baseRevision, bits, 1);
  154. checkFloat(mFarClip, DEFAULT_FARCLIP, baseRevision, bits, 1);
  155. checkFloat(mFov, DEFAULT_FOV, baseRevision, bits, 2);
  156. checkFloat(mOrthoSize, DEFAULT_ORTHOSIZE, baseRevision, bits, 4);
  157. checkBool(mOrthographic, false, baseRevision, bits, 4);
  158. checkFloat(mAspectRatio, 1.0f, baseRevision, bits, 8);
  159. checkBool(mAutoAspectRatio, true, baseRevision, bits, 8);
  160. checkFloat(mZoom, 1.0f, baseRevision, bits, 16);
  161. checkFloat(mLodBias, 1.0f, baseRevision, bits, 32);
  162. checkUInt(mViewMask, VIEW_ALL, baseRevision, bits, 64);
  163. checkBool(mDrawShadowsOverride, true, baseRevision, bits, 128);
  164. checkUByte(qualityOverrides, QUALITY_MAX | (QUALITY_MAX << 4), baseRevision, bits, 128);
  165. checkInt(mMaxOccluderTrianglesOverride, M_MAX_INT, baseRevision, bits, 128);
  166. // Update replication state fully, and network stream by delta
  167. dest.writeUByte(bits);
  168. writeFloatDelta(mNearClip, dest, destRevision, bits & 1);
  169. writeFloatDelta(mFarClip, dest, destRevision, bits & 1);
  170. writeFloatDelta(mFov, dest, destRevision, bits & 2);
  171. writeFloatDelta(mOrthoSize, dest, destRevision, bits & 4);
  172. writeBoolDelta(mOrthographic, dest, destRevision, bits & 4);
  173. writeFloatDelta(mAspectRatio, dest, destRevision, bits & 8);
  174. writeBoolDelta(mAutoAspectRatio, dest, destRevision, bits & 8);
  175. writeFloatDelta(mZoom, dest, destRevision, bits & 16);
  176. writeFloatDelta(mLodBias, dest, destRevision, bits & 32);
  177. writeUIntDelta(mViewMask, dest, destRevision, bits & 64);
  178. writeBoolDelta(mDrawShadowsOverride, dest, destRevision, bits & 128);
  179. writeUByteDelta(qualityOverrides, dest, destRevision, bits & 128);
  180. writeIntDelta(mMaxOccluderTrianglesOverride, dest, destRevision, bits & 128);
  181. return prevBits || (bits != 0);
  182. }
  183. void Camera::readNetUpdate(Deserializer& source, ResourceCache* cache, const NetUpdateInfo& info)
  184. {
  185. // Read Node properties
  186. Node::readNetUpdate(source, cache, info);
  187. unsigned char bits = source.readUByte();
  188. readFloatDelta(mNearClip, source, bits & 1);
  189. readFloatDelta(mFarClip, source, bits & 1);
  190. readFloatDelta(mFov, source, bits & 2);
  191. readFloatDelta(mOrthoSize, source, bits & 4);
  192. readBoolDelta(mOrthographic, source, bits & 4);
  193. readFloatDelta(mAspectRatio, source, bits & 8);
  194. readBoolDelta(mAutoAspectRatio, source, bits & 8);
  195. readFloatDelta(mZoom, source, bits & 16);
  196. readFloatDelta(mLodBias, source, bits & 32);
  197. readUIntDelta(mViewMask, source, bits & 64);
  198. if (bits & 128)
  199. {
  200. mDrawShadowsOverride = source.readBool();
  201. unsigned char qualityOverrides = source.readUByte();
  202. mLightDetailLevelOverride = qualityOverrides & 15;
  203. mMaterialQualityOverride = qualityOverrides >> 4;
  204. mMaxOccluderTrianglesOverride = source.readInt();
  205. }
  206. if (bits)
  207. markProjectionDirty();
  208. }
  209. void Camera::setNearClip(float nearClip)
  210. {
  211. mNearClip = max(nearClip, 0.0f);
  212. markProjectionDirty();
  213. }
  214. void Camera::setFarClip(float farClip)
  215. {
  216. mFarClip = max(farClip, 0.0f);
  217. markProjectionDirty();
  218. }
  219. void Camera::setFov(float fov)
  220. {
  221. mFov = clamp(fov, 0.0f, M_MAX_FOV);
  222. markProjectionDirty();
  223. }
  224. void Camera::setOrthoSize(float orthoSize)
  225. {
  226. mOrthoSize = orthoSize;
  227. mAspectRatio = 1.0f;
  228. markProjectionDirty();
  229. }
  230. void Camera::setOrthoSize(const Vector2& orthoSize)
  231. {
  232. mOrthoSize = orthoSize.mY;
  233. mAspectRatio = orthoSize.mX / orthoSize.mY;
  234. markProjectionDirty();
  235. }
  236. void Camera::setAspectRatio(float aspectRatio)
  237. {
  238. mAspectRatio = aspectRatio;
  239. markProjectionDirty();
  240. }
  241. void Camera::setZoom(float zoom)
  242. {
  243. mZoom = max(zoom, M_EPSILON);
  244. markProjectionDirty();
  245. }
  246. void Camera::setLodBias(float bias)
  247. {
  248. mLodBias = max(bias, M_EPSILON);
  249. }
  250. void Camera::setOrthographic(bool enable)
  251. {
  252. mOrthographic = enable;
  253. markProjectionDirty();
  254. }
  255. void Camera::setAutoAspectRatio(bool enable)
  256. {
  257. mAutoAspectRatio = enable;
  258. }
  259. void Camera::setViewMask(unsigned mask)
  260. {
  261. mViewMask = mask;
  262. }
  263. void Camera::setDrawShadowsOverride(bool enable)
  264. {
  265. mDrawShadowsOverride = enable;
  266. }
  267. void Camera::setLightDetailLevelOverride(int quality)
  268. {
  269. mLightDetailLevelOverride = clamp(quality, QUALITY_LOW, QUALITY_MAX);
  270. }
  271. void Camera::setMaterialQualityOverride(int quality)
  272. {
  273. mMaterialQualityOverride = clamp(quality, QUALITY_LOW, QUALITY_MAX);
  274. }
  275. void Camera::setMaxOccluderTrianglesOverride(int triangles)
  276. {
  277. mMaxOccluderTrianglesOverride = triangles;
  278. }
  279. float Camera::getNearClip() const
  280. {
  281. // Orthographic camera has always near clip at 0 to avoid trouble with shader depth parameters,
  282. // and unlike in perspective mode there should be no depth buffer precision issue
  283. if (!mOrthographic)
  284. return mNearClip;
  285. else
  286. return 0.0f;
  287. }
  288. Frustum Camera::getViewSpaceFrustum() const
  289. {
  290. Frustum ret;
  291. if (!mOrthographic)
  292. ret.define(mFov, mAspectRatio, mZoom, getNearClip(), mFarClip);
  293. else
  294. ret.defineOrtho(mOrthoSize, mAspectRatio, mZoom, getNearClip(), mFarClip);
  295. return ret;
  296. }
  297. Frustum Camera::getSplitFrustum(float nearClip, float farClip)
  298. {
  299. Frustum ret;
  300. nearClip = max(nearClip, getNearClip());
  301. farClip = min(farClip, mFarClip);
  302. if (farClip < nearClip)
  303. farClip = nearClip;
  304. if (!mOrthographic)
  305. ret.define(mFov, mAspectRatio, mZoom, nearClip, farClip, getWorldTransform());
  306. else
  307. ret.defineOrtho(mOrthoSize, mAspectRatio, mZoom, nearClip, farClip, getWorldTransform());
  308. return ret;
  309. }
  310. Ray Camera::getScreenRay(float x, float y)
  311. {
  312. Matrix4 viewProjInverse = (getProjection() * getInverseWorldTransform()).getInverse();
  313. // The parameters range from 0.0 to 1.0. Expand to normalized device coordinates (-1.0 to 1.0) & flip Y axis
  314. x = 2.0f * x - 1.0f;
  315. y = 1.0f - 2.0f * y;
  316. Vector3 near(x, y, 0.0f);
  317. Vector3 far(x, y, 1.0f);
  318. Ray ray;
  319. ray.mOrigin = viewProjInverse * near;
  320. ray.mDirection = ((viewProjInverse * far) - ray.mOrigin).getNormalized();
  321. return ray;
  322. }
  323. const Matrix4x3& Camera::getInverseWorldTransform()
  324. {
  325. if (mInverseWorldTransformDirty)
  326. {
  327. mInverseWorldTransform = getWorldTransform().getInverse();
  328. mInverseWorldTransformDirty = false;
  329. }
  330. return mInverseWorldTransform;
  331. }
  332. const Frustum& Camera::getFrustum()
  333. {
  334. if (mFrustumDirty)
  335. {
  336. if (!mOrthographic)
  337. mFrustum.define(mFov, mAspectRatio, mZoom, getNearClip(), mFarClip, getWorldTransform());
  338. else
  339. mFrustum.defineOrtho(mOrthoSize, mAspectRatio, mZoom, getNearClip(), mFarClip, getWorldTransform());
  340. mFrustumDirty = false;
  341. }
  342. return mFrustum;
  343. }
  344. const Matrix4& Camera::getProjection()
  345. {
  346. if (mProjectionDirty)
  347. {
  348. memset(&mProjection, 0, sizeof(mProjection));
  349. if (!mOrthographic)
  350. {
  351. float nearClip = getNearClip();
  352. float h = (1.0f / tanf(mFov * M_DEGTORAD * 0.5f)) * mZoom;
  353. float w = h / mAspectRatio;
  354. float q = mFarClip / (mFarClip - nearClip);
  355. mProjection.m00 = w;
  356. mProjection.m11 = h;
  357. mProjection.m22 = q;
  358. mProjection.m23 = -q * nearClip;
  359. mProjection.m32 = 1.0f;
  360. }
  361. else
  362. {
  363. // Disregard near clip, because it does not affect depth precision as with perspective projection
  364. float h = (1.0f / (mOrthoSize * 0.5f)) * mZoom;
  365. float w = h / mAspectRatio;
  366. float q = 1.0f / mFarClip;
  367. mProjection.m00 = w;
  368. mProjection.m11 = h;
  369. mProjection.m22 = q;
  370. mProjection.m33 = 1.0f;
  371. }
  372. mProjectionDirty = false;
  373. }
  374. return mProjection;
  375. }
  376. const Vector3& Camera::getFrustumNearSize()
  377. {
  378. if (mFrustumSizeDirty)
  379. updateFrustumSize();
  380. return mNear;
  381. }
  382. const Vector3& Camera::getFrustumFarSize()
  383. {
  384. if (mFrustumSizeDirty)
  385. updateFrustumSize();
  386. return mFar;
  387. }
  388. float Camera::getHalfViewSize() const
  389. {
  390. if (!mOrthographic)
  391. return tanf(mFov * M_DEGTORAD * 0.5f) / mZoom;
  392. else
  393. return mOrthoSize * 0.5f / mZoom;
  394. }
  395. Vector3 Camera::getForwardVector()
  396. {
  397. return getWorldRotation() * Vector3::sForward;
  398. }
  399. Vector3 Camera::getRightVector()
  400. {
  401. return getWorldRotation() * Vector3::sRight;
  402. }
  403. Vector3 Camera::getUpVector()
  404. {
  405. return getWorldRotation() * Vector3::sUp;
  406. }
  407. float Camera::getDistance(const Vector3& worldPos)
  408. {
  409. if (!mOrthographic)
  410. return (worldPos - getWorldPosition()).getLengthFast();
  411. else
  412. return fabsf((getInverseWorldTransform() * worldPos).mZ);
  413. }
  414. float Camera::getDistanceSquared(const Vector3& worldPos)
  415. {
  416. if (!mOrthographic)
  417. return (worldPos - getWorldPosition()).getLengthSquared();
  418. else
  419. {
  420. float distance = (getInverseWorldTransform() * worldPos).mZ;
  421. return distance * distance;
  422. }
  423. }
  424. float Camera::getLodDistance(float distance, float scale, float bias) const
  425. {
  426. float d = max(mLodBias * bias * scale * mZoom, M_EPSILON);
  427. if (!mOrthographic)
  428. return distance / d;
  429. else
  430. return mOrthoSize / d;
  431. }
  432. void Camera::onMarkedDirty()
  433. {
  434. mInverseWorldTransformDirty = true;
  435. mFrustumDirty = true;
  436. mProjectionDirty = true;
  437. }
  438. void Camera::markProjectionDirty()
  439. {
  440. mFrustumDirty = true;
  441. mProjectionDirty = true;
  442. mFrustumSizeDirty = true;
  443. }
  444. void Camera::updateFrustumSize()
  445. {
  446. mNear.mZ = getNearClip();
  447. mFar.mZ = mFarClip;
  448. if (!mOrthographic)
  449. {
  450. float halfViewSize = tanf(mFov * M_DEGTORAD * 0.5f) / mZoom;
  451. mNear.mY = mNear.mZ * halfViewSize;
  452. mNear.mX = mNear.mY * mAspectRatio;
  453. mFar.mY = mFar.mZ * halfViewSize;
  454. mFar.mX = mFar.mY * mAspectRatio;
  455. }
  456. else
  457. {
  458. float halfViewSize = mOrthoSize * 0.5f / mZoom;
  459. mNear.mY = mFar.mY = halfViewSize;
  460. mNear.mX = mFar.mX = mNear.mY * mAspectRatio;
  461. }
  462. mFrustumSizeDirty = false;
  463. }