Camera.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Core/Context.h"
  5. #include "../Graphics/Camera.h"
  6. #include "../Graphics/DebugRenderer.h"
  7. #include "../Graphics/Drawable.h"
  8. #include "../Graphics/Graphics.h"
  9. #include "../Scene/Node.h"
  10. #include "../DebugNew.h"
  11. namespace Urho3D
  12. {
  13. extern const char* SCENE_CATEGORY;
  14. static const char* fillModeNames[] =
  15. {
  16. "Solid",
  17. "Wireframe",
  18. "Point",
  19. nullptr
  20. };
  21. static const Matrix4 flipMatrix(
  22. 1.0f, 0.0f, 0.0f, 0.0f,
  23. 0.0f, -1.0f, 0.0f, 0.0f,
  24. 0.0f, 0.0f, 1.0f, 0.0f,
  25. 0.0f, 0.0f, 0.0f, 1.0f
  26. );
  27. Camera::Camera(Context* context) :
  28. Component(context),
  29. viewDirty_(true),
  30. projectionDirty_(true),
  31. frustumDirty_(true),
  32. orthographic_(false),
  33. nearClip_(DEFAULT_NEARCLIP),
  34. farClip_(DEFAULT_FARCLIP),
  35. fov_(DEFAULT_CAMERA_FOV),
  36. orthoSize_(DEFAULT_ORTHOSIZE),
  37. aspectRatio_(1.0f),
  38. zoom_(1.0f),
  39. lodBias_(1.0f),
  40. viewMask_(DEFAULT_VIEWMASK),
  41. viewOverrideFlags_(VO_NONE),
  42. fillMode_(FILL_SOLID),
  43. projectionOffset_(Vector2::ZERO),
  44. reflectionPlane_(Plane::UP),
  45. clipPlane_(Plane::UP),
  46. autoAspectRatio_(true),
  47. flipVertical_(false),
  48. useReflection_(false),
  49. useClipping_(false),
  50. customProjection_(false)
  51. {
  52. reflectionMatrix_ = reflectionPlane_.ReflectionMatrix();
  53. }
  54. Camera::~Camera() = default;
  55. void Camera::RegisterObject(Context* context)
  56. {
  57. context->RegisterFactory<Camera>(SCENE_CATEGORY);
  58. URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, true, AM_DEFAULT);
  59. URHO3D_ACCESSOR_ATTRIBUTE("Near Clip", GetNearClip, SetNearClip, DEFAULT_NEARCLIP, AM_DEFAULT);
  60. URHO3D_ACCESSOR_ATTRIBUTE("Far Clip", GetFarClip, SetFarClip, DEFAULT_FARCLIP, AM_DEFAULT);
  61. URHO3D_ACCESSOR_ATTRIBUTE("FOV", GetFov, SetFov, DEFAULT_CAMERA_FOV, AM_DEFAULT);
  62. URHO3D_ACCESSOR_ATTRIBUTE("Aspect Ratio", GetAspectRatio, SetAspectRatioInternal, 1.0f, AM_DEFAULT);
  63. URHO3D_ENUM_ATTRIBUTE("Fill Mode", fillMode_, fillModeNames, FILL_SOLID, AM_DEFAULT);
  64. URHO3D_ATTRIBUTE("Auto Aspect Ratio", autoAspectRatio_, true, AM_DEFAULT);
  65. URHO3D_ACCESSOR_ATTRIBUTE("Orthographic", IsOrthographic, SetOrthographic, false, AM_DEFAULT);
  66. URHO3D_ACCESSOR_ATTRIBUTE("Orthographic Size", GetOrthoSize, SetOrthoSizeAttr, DEFAULT_ORTHOSIZE, AM_DEFAULT);
  67. URHO3D_ACCESSOR_ATTRIBUTE("Zoom", GetZoom, SetZoom, 1.0f, AM_DEFAULT);
  68. URHO3D_ACCESSOR_ATTRIBUTE("LOD Bias", GetLodBias, SetLodBias, 1.0f, AM_DEFAULT);
  69. URHO3D_ATTRIBUTE("View Mask", viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
  70. URHO3D_ATTRIBUTE("View Override Flags", viewOverrideFlags_.AsInteger(), VO_NONE, AM_DEFAULT);
  71. URHO3D_ACCESSOR_ATTRIBUTE("Projection Offset", GetProjectionOffset, SetProjectionOffset, Vector2::ZERO, AM_DEFAULT);
  72. URHO3D_ACCESSOR_ATTRIBUTE("Reflection Plane", GetReflectionPlaneAttr, SetReflectionPlaneAttr,
  73. Vector4(0.0f, 1.0f, 0.0f, 0.0f), AM_DEFAULT);
  74. URHO3D_ACCESSOR_ATTRIBUTE("Clip Plane", GetClipPlaneAttr, SetClipPlaneAttr, Vector4(0.0f, 1.0f, 0.0f, 0.0f),
  75. AM_DEFAULT);
  76. URHO3D_ACCESSOR_ATTRIBUTE("Use Reflection", GetUseReflection, SetUseReflection, false, AM_DEFAULT);
  77. URHO3D_ACCESSOR_ATTRIBUTE("Use Clipping", GetUseClipping, SetUseClipping, false, AM_DEFAULT);
  78. }
  79. void Camera::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  80. {
  81. debug->AddFrustum(GetFrustum(), Color::WHITE, depthTest);
  82. }
  83. void Camera::SetNearClip(float nearClip)
  84. {
  85. nearClip_ = Max(nearClip, M_MIN_NEARCLIP);
  86. frustumDirty_ = true;
  87. projectionDirty_ = true;
  88. MarkNetworkUpdate();
  89. }
  90. void Camera::SetFarClip(float farClip)
  91. {
  92. farClip_ = Max(farClip, M_MIN_NEARCLIP);
  93. frustumDirty_ = true;
  94. projectionDirty_ = true;
  95. MarkNetworkUpdate();
  96. }
  97. void Camera::SetFov(float fov)
  98. {
  99. fov_ = Clamp(fov, 0.0f, M_MAX_FOV);
  100. frustumDirty_ = true;
  101. projectionDirty_ = true;
  102. MarkNetworkUpdate();
  103. }
  104. void Camera::SetOrthoSize(float orthoSize)
  105. {
  106. orthoSize_ = orthoSize;
  107. aspectRatio_ = 1.0f;
  108. frustumDirty_ = true;
  109. projectionDirty_ = true;
  110. MarkNetworkUpdate();
  111. }
  112. void Camera::SetOrthoSize(const Vector2& orthoSize)
  113. {
  114. autoAspectRatio_ = false;
  115. orthoSize_ = orthoSize.y_;
  116. aspectRatio_ = orthoSize.x_ / orthoSize.y_;
  117. frustumDirty_ = true;
  118. projectionDirty_ = true;
  119. MarkNetworkUpdate();
  120. }
  121. void Camera::SetAspectRatio(float aspectRatio)
  122. {
  123. autoAspectRatio_ = false;
  124. SetAspectRatioInternal(aspectRatio);
  125. }
  126. void Camera::SetZoom(float zoom)
  127. {
  128. zoom_ = Max(zoom, M_EPSILON);
  129. frustumDirty_ = true;
  130. projectionDirty_ = true;
  131. MarkNetworkUpdate();
  132. }
  133. void Camera::SetLodBias(float bias)
  134. {
  135. lodBias_ = Max(bias, M_EPSILON);
  136. MarkNetworkUpdate();
  137. }
  138. void Camera::SetViewMask(unsigned mask)
  139. {
  140. viewMask_ = mask;
  141. MarkNetworkUpdate();
  142. }
  143. void Camera::SetViewOverrideFlags(ViewOverrideFlags flags)
  144. {
  145. viewOverrideFlags_ = flags;
  146. MarkNetworkUpdate();
  147. }
  148. void Camera::SetFillMode(FillMode mode)
  149. {
  150. fillMode_ = mode;
  151. MarkNetworkUpdate();
  152. }
  153. void Camera::SetOrthographic(bool enable)
  154. {
  155. orthographic_ = enable;
  156. frustumDirty_ = true;
  157. projectionDirty_ = true;
  158. MarkNetworkUpdate();
  159. }
  160. void Camera::SetAutoAspectRatio(bool enable)
  161. {
  162. autoAspectRatio_ = enable;
  163. MarkNetworkUpdate();
  164. }
  165. void Camera::SetProjectionOffset(const Vector2& offset)
  166. {
  167. projectionOffset_ = offset;
  168. projectionDirty_ = true;
  169. MarkNetworkUpdate();
  170. }
  171. void Camera::SetUseReflection(bool enable)
  172. {
  173. useReflection_ = enable;
  174. viewDirty_ = true;
  175. frustumDirty_ = true;
  176. MarkNetworkUpdate();
  177. }
  178. void Camera::SetReflectionPlane(const Plane& plane)
  179. {
  180. reflectionPlane_ = plane;
  181. reflectionMatrix_ = reflectionPlane_.ReflectionMatrix();
  182. viewDirty_ = true;
  183. frustumDirty_ = true;
  184. MarkNetworkUpdate();
  185. }
  186. void Camera::SetUseClipping(bool enable)
  187. {
  188. useClipping_ = enable;
  189. projectionDirty_ = true;
  190. MarkNetworkUpdate();
  191. }
  192. void Camera::SetClipPlane(const Plane& plane)
  193. {
  194. clipPlane_ = plane;
  195. MarkNetworkUpdate();
  196. }
  197. void Camera::SetFlipVertical(bool enable)
  198. {
  199. flipVertical_ = enable;
  200. MarkNetworkUpdate();
  201. }
  202. void Camera::SetProjection(const Matrix4& projection)
  203. {
  204. projection_ = projection;
  205. Matrix4 projInverse = projection_.Inverse();
  206. // Calculate the actual near & far clip from the custom matrix
  207. projNearClip_ = (projInverse * Vector3(0.0f, 0.0f, 0.0f)).z_;
  208. projFarClip_ = (projInverse * Vector3(0.0f, 0.0f, 1.0f)).z_;
  209. projectionDirty_ = false;
  210. autoAspectRatio_ = false;
  211. frustumDirty_ = true;
  212. customProjection_ = true;
  213. // Called due to autoAspectRatio changing state, the projection itself is not serialized
  214. MarkNetworkUpdate();
  215. }
  216. float Camera::GetNearClip() const
  217. {
  218. if (projectionDirty_)
  219. UpdateProjection();
  220. return projNearClip_;
  221. }
  222. float Camera::GetFarClip() const
  223. {
  224. if (projectionDirty_)
  225. UpdateProjection();
  226. return projFarClip_;
  227. }
  228. const Frustum& Camera::GetFrustum() const
  229. {
  230. // Use projection_ instead of GetProjection() so that Y-flip has no effect. Update first if necessary
  231. if (projectionDirty_)
  232. UpdateProjection();
  233. if (frustumDirty_)
  234. {
  235. if (customProjection_)
  236. frustum_.Define(projection_ * GetView());
  237. else
  238. {
  239. // If not using a custom projection, prefer calculating frustum from projection parameters instead of matrix
  240. // for better accuracy
  241. if (!orthographic_)
  242. frustum_.Define(fov_, aspectRatio_, zoom_, GetNearClip(), GetFarClip(), GetEffectiveWorldTransform());
  243. else
  244. frustum_.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), GetFarClip(), GetEffectiveWorldTransform());
  245. }
  246. frustumDirty_ = false;
  247. }
  248. return frustum_;
  249. }
  250. Frustum Camera::GetSplitFrustum(float nearClip, float farClip) const
  251. {
  252. if (projectionDirty_)
  253. UpdateProjection();
  254. nearClip = Max(nearClip, projNearClip_);
  255. farClip = Min(farClip, projFarClip_);
  256. if (farClip < nearClip)
  257. farClip = nearClip;
  258. Frustum ret;
  259. if (customProjection_)
  260. {
  261. // DefineSplit() needs to project the near & far distances, so can not use a combined view-projection matrix.
  262. // Transform to world space afterward instead
  263. ret.DefineSplit(projection_, nearClip, farClip);
  264. ret.Transform(GetEffectiveWorldTransform());
  265. }
  266. else
  267. {
  268. if (!orthographic_)
  269. ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip, GetEffectiveWorldTransform());
  270. else
  271. ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip, GetEffectiveWorldTransform());
  272. }
  273. return ret;
  274. }
  275. Frustum Camera::GetViewSpaceFrustum() const
  276. {
  277. if (projectionDirty_)
  278. UpdateProjection();
  279. Frustum ret;
  280. if (customProjection_)
  281. ret.Define(projection_);
  282. else
  283. {
  284. if (!orthographic_)
  285. ret.Define(fov_, aspectRatio_, zoom_, GetNearClip(), GetFarClip());
  286. else
  287. ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), GetFarClip());
  288. }
  289. return ret;
  290. }
  291. Frustum Camera::GetViewSpaceSplitFrustum(float nearClip, float farClip) const
  292. {
  293. if (projectionDirty_)
  294. UpdateProjection();
  295. nearClip = Max(nearClip, projNearClip_);
  296. farClip = Min(farClip, projFarClip_);
  297. if (farClip < nearClip)
  298. farClip = nearClip;
  299. Frustum ret;
  300. if (customProjection_)
  301. ret.DefineSplit(projection_, nearClip, farClip);
  302. else
  303. {
  304. if (!orthographic_)
  305. ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip);
  306. else
  307. ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip);
  308. }
  309. return ret;
  310. }
  311. Ray Camera::GetScreenRay(float x, float y) const
  312. {
  313. Ray ret;
  314. // If projection is invalid, just return a ray pointing forward
  315. if (!IsProjectionValid())
  316. {
  317. ret.origin_ = node_ ? node_->GetWorldPosition() : Vector3::ZERO;
  318. ret.direction_ = node_ ? node_->GetWorldDirection() : Vector3::FORWARD;
  319. return ret;
  320. }
  321. Matrix4 viewProjInverse = (GetProjection() * GetView()).Inverse();
  322. // The parameters range from 0.0 to 1.0. Expand to normalized device coordinates (-1.0 to 1.0) & flip Y axis
  323. x = 2.0f * x - 1.0f;
  324. y = 1.0f - 2.0f * y;
  325. Vector3 near(x, y, 0.0f);
  326. Vector3 far(x, y, 1.0f);
  327. ret.origin_ = viewProjInverse * near;
  328. ret.direction_ = ((viewProjInverse * far) - ret.origin_).Normalized();
  329. return ret;
  330. }
  331. Vector2 Camera::WorldToScreenPoint(const Vector3& worldPos) const
  332. {
  333. Vector3 eyeSpacePos = GetView() * worldPos;
  334. Vector2 ret;
  335. if (eyeSpacePos.z_ > 0.0f)
  336. {
  337. Vector3 screenSpacePos = GetProjection() * eyeSpacePos;
  338. ret.x_ = screenSpacePos.x_;
  339. ret.y_ = screenSpacePos.y_;
  340. }
  341. else
  342. {
  343. ret.x_ = (-eyeSpacePos.x_ > 0.0f) ? -1.0f : 1.0f;
  344. ret.y_ = (-eyeSpacePos.y_ > 0.0f) ? -1.0f : 1.0f;
  345. }
  346. ret.x_ = (ret.x_ / 2.0f) + 0.5f;
  347. ret.y_ = 1.0f - ((ret.y_ / 2.0f) + 0.5f);
  348. return ret;
  349. }
  350. Vector3 Camera::ScreenToWorldPoint(const Vector3& screenPos) const
  351. {
  352. Ray ray = GetScreenRay(screenPos.x_, screenPos.y_);
  353. Vector3 viewSpaceDir = (GetView() * Vector4(ray.direction_, 0.0f));
  354. float rayDistance = (Max(screenPos.z_ - GetNearClip(), 0.0f) / viewSpaceDir.z_);
  355. return ray.origin_ + ray.direction_ * rayDistance;
  356. }
  357. Matrix4 Camera::GetProjection() const
  358. {
  359. if (projectionDirty_)
  360. UpdateProjection();
  361. return flipVertical_ ? flipMatrix * projection_ : projection_;
  362. }
  363. Matrix4 Camera::GetGPUProjection() const
  364. {
  365. if (Graphics::GetGAPI() != GAPI_OPENGL)
  366. {
  367. return GetProjection(); // Already matches API-specific format
  368. }
  369. else
  370. {
  371. // See formulation for depth range conversion at http://www.ogre3d.org/forums/viewtopic.php?f=4&t=13357
  372. Matrix4 ret = GetProjection();
  373. ret.m20_ = 2.0f * ret.m20_ - ret.m30_;
  374. ret.m21_ = 2.0f * ret.m21_ - ret.m31_;
  375. ret.m22_ = 2.0f * ret.m22_ - ret.m32_;
  376. ret.m23_ = 2.0f * ret.m23_ - ret.m33_;
  377. return ret;
  378. }
  379. }
  380. void Camera::GetFrustumSize(Vector3& near, Vector3& far) const
  381. {
  382. Frustum viewSpaceFrustum = GetViewSpaceFrustum();
  383. near = viewSpaceFrustum.vertices_[0];
  384. far = viewSpaceFrustum.vertices_[4];
  385. /// \todo Necessary? Explain this
  386. if (flipVertical_)
  387. {
  388. near.y_ = -near.y_;
  389. far.y_ = -far.y_;
  390. }
  391. }
  392. float Camera::GetHalfViewSize() const
  393. {
  394. if (!orthographic_)
  395. return tanf(fov_ * M_DEGTORAD * 0.5f) / zoom_;
  396. else
  397. return orthoSize_ * 0.5f / zoom_;
  398. }
  399. float Camera::GetDistance(const Vector3& worldPos) const
  400. {
  401. if (!orthographic_)
  402. {
  403. const Vector3& cameraPos = node_ ? node_->GetWorldPosition() : Vector3::ZERO;
  404. return (worldPos - cameraPos).Length();
  405. }
  406. else
  407. return Abs((GetView() * worldPos).z_);
  408. }
  409. float Camera::GetDistanceSquared(const Vector3& worldPos) const
  410. {
  411. if (!orthographic_)
  412. {
  413. const Vector3& cameraPos = node_ ? node_->GetWorldPosition() : Vector3::ZERO;
  414. return (worldPos - cameraPos).LengthSquared();
  415. }
  416. else
  417. {
  418. float distance = (GetView() * worldPos).z_;
  419. return distance * distance;
  420. }
  421. }
  422. float Camera::GetLodDistance(float distance, float scale, float bias) const
  423. {
  424. float d = Max(lodBias_ * bias * scale * zoom_, M_EPSILON);
  425. if (!orthographic_)
  426. return distance / d;
  427. else
  428. return orthoSize_ / d;
  429. }
  430. Quaternion Camera::GetFaceCameraRotation(const Vector3& position, const Quaternion& rotation, FaceCameraMode mode, float minAngle)
  431. {
  432. if (!node_)
  433. return rotation;
  434. switch (mode)
  435. {
  436. case FC_ROTATE_XYZ:
  437. return node_->GetWorldRotation();
  438. case FC_ROTATE_Y:
  439. {
  440. Vector3 euler = rotation.EulerAngles();
  441. euler.y_ = node_->GetWorldRotation().EulerAngles().y_;
  442. return Quaternion(euler.x_, euler.y_, euler.z_);
  443. }
  444. case FC_LOOKAT_XYZ:
  445. {
  446. Quaternion lookAt;
  447. lookAt.FromLookRotation(position - node_->GetWorldPosition());
  448. return lookAt;
  449. }
  450. case FC_LOOKAT_Y:
  451. case FC_LOOKAT_MIXED:
  452. {
  453. // Mixed mode needs true look-at vector
  454. const Vector3 lookAtVec(position - node_->GetWorldPosition());
  455. // While Y-only lookat happens on an XZ plane to make sure there are no unwanted transitions or singularities
  456. const Vector3 lookAtVecXZ(lookAtVec.x_, 0.0f, lookAtVec.z_);
  457. Quaternion lookAt;
  458. lookAt.FromLookRotation(lookAtVecXZ);
  459. Vector3 euler = rotation.EulerAngles();
  460. if (mode == FC_LOOKAT_MIXED)
  461. {
  462. const float angle = lookAtVec.Angle(rotation * Vector3::UP);
  463. if (angle > 180 - minAngle)
  464. euler.x_ += minAngle - (180 - angle);
  465. else if (angle < minAngle)
  466. euler.x_ -= minAngle - angle;
  467. }
  468. euler.y_ = lookAt.EulerAngles().y_;
  469. return Quaternion(euler.x_, euler.y_, euler.z_);
  470. }
  471. default:
  472. return rotation;
  473. }
  474. }
  475. Matrix3x4 Camera::GetEffectiveWorldTransform() const
  476. {
  477. Matrix3x4 worldTransform = node_ ? Matrix3x4(node_->GetWorldPosition(), node_->GetWorldRotation(), 1.0f) : Matrix3x4::IDENTITY;
  478. return useReflection_ ? reflectionMatrix_ * worldTransform : worldTransform;
  479. }
  480. bool Camera::IsProjectionValid() const
  481. {
  482. return GetFarClip() > GetNearClip();
  483. }
  484. const Matrix3x4& Camera::GetView() const
  485. {
  486. if (viewDirty_)
  487. {
  488. // Note: view matrix is unaffected by node or parent scale
  489. view_ = GetEffectiveWorldTransform().Inverse();
  490. viewDirty_ = false;
  491. }
  492. return view_;
  493. }
  494. void Camera::SetAspectRatioInternal(float aspectRatio)
  495. {
  496. if (aspectRatio != aspectRatio_)
  497. {
  498. aspectRatio_ = aspectRatio;
  499. frustumDirty_ = true;
  500. projectionDirty_ = true;
  501. }
  502. MarkNetworkUpdate();
  503. }
  504. void Camera::SetOrthoSizeAttr(float orthoSize)
  505. {
  506. orthoSize_ = orthoSize;
  507. frustumDirty_ = true;
  508. projectionDirty_ = true;
  509. MarkNetworkUpdate();
  510. }
  511. void Camera::SetReflectionPlaneAttr(const Vector4& value)
  512. {
  513. SetReflectionPlane(Plane(value));
  514. }
  515. void Camera::SetClipPlaneAttr(const Vector4& value)
  516. {
  517. SetClipPlane(Plane(value));
  518. }
  519. Vector4 Camera::GetReflectionPlaneAttr() const
  520. {
  521. return reflectionPlane_.ToVector4();
  522. }
  523. Vector4 Camera::GetClipPlaneAttr() const
  524. {
  525. return clipPlane_.ToVector4();
  526. }
  527. void Camera::OnNodeSet(Node* node)
  528. {
  529. if (node)
  530. node->AddListener(this);
  531. }
  532. void Camera::OnMarkedDirty(Node* node)
  533. {
  534. frustumDirty_ = true;
  535. viewDirty_ = true;
  536. }
  537. void Camera::UpdateProjection() const
  538. {
  539. // Start from a zero matrix in case it was custom previously
  540. projection_ = Matrix4::ZERO;
  541. if (!orthographic_)
  542. {
  543. float h = (1.0f / tanf(fov_ * M_DEGTORAD * 0.5f)) * zoom_;
  544. float w = h / aspectRatio_;
  545. float q = farClip_ / (farClip_ - nearClip_);
  546. float r = -q * nearClip_;
  547. projection_.m00_ = w;
  548. projection_.m02_ = projectionOffset_.x_ * 2.0f;
  549. projection_.m11_ = h;
  550. projection_.m12_ = projectionOffset_.y_ * 2.0f;
  551. projection_.m22_ = q;
  552. projection_.m23_ = r;
  553. projection_.m32_ = 1.0f;
  554. projNearClip_ = nearClip_;
  555. projFarClip_ = farClip_;
  556. }
  557. else
  558. {
  559. float h = (1.0f / (orthoSize_ * 0.5f)) * zoom_;
  560. float w = h / aspectRatio_;
  561. float q = 1.0f / farClip_;
  562. float r = 0.0f;
  563. projection_.m00_ = w;
  564. projection_.m03_ = projectionOffset_.x_ * 2.0f;
  565. projection_.m11_ = h;
  566. projection_.m13_ = projectionOffset_.y_ * 2.0f;
  567. projection_.m22_ = q;
  568. projection_.m23_ = r;
  569. projection_.m33_ = 1.0f;
  570. // Near clip does not affect depth accuracy in ortho projection, so let it stay 0 to avoid problems with shader depth parameters
  571. projNearClip_ = 0.0f;
  572. projFarClip_ = farClip_;
  573. }
  574. projectionDirty_ = false;
  575. customProjection_ = false;
  576. }
  577. }