Camera.cpp 16 KB

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