Camera.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Camera.h"
  24. #include "Context.h"
  25. #include "Drawable.h"
  26. #include "Node.h"
  27. #include "DebugNew.h"
  28. namespace Urho3D
  29. {
  30. extern const char* SCENE_CATEGORY;
  31. static const float DEFAULT_NEARCLIP = 0.1f;
  32. static const float DEFAULT_FARCLIP = 1000.0f;
  33. static const float DEFAULT_FOV = 45.0f;
  34. static const float DEFAULT_ORTHOSIZE = 20.0f;
  35. static const char* fillModeNames[] =
  36. {
  37. "Solid",
  38. "Wireframe",
  39. "Point",
  40. 0
  41. };
  42. static const Matrix4 flipMatrix(
  43. 1.0f, 0.0f, 0.0f, 0.0f,
  44. 0.0f, -1.0f, 0.0f, 0.0f,
  45. 0.0f, 0.0f, 1.0f, 0.0f,
  46. 0.0f, 0.0f, 0.0f, 1.0f
  47. );
  48. OBJECTTYPESTATIC(Camera);
  49. Camera::Camera(Context* context) :
  50. Component(context),
  51. inverseWorldDirty_(true),
  52. projectionDirty_(true),
  53. frustumDirty_(true),
  54. orthographic_(false),
  55. nearClip_(DEFAULT_NEARCLIP),
  56. farClip_(DEFAULT_FARCLIP),
  57. fov_(DEFAULT_FOV),
  58. orthoSize_(DEFAULT_ORTHOSIZE),
  59. aspectRatio_(1.0f),
  60. zoom_(1.0f),
  61. lodBias_(1.0f),
  62. viewMask_(DEFAULT_VIEWMASK),
  63. viewOverrideFlags_(VO_NONE),
  64. fillMode_(FILL_SOLID),
  65. projectionOffset_(Vector2::ZERO),
  66. autoAspectRatio_(true),
  67. flipVertical_(false)
  68. {
  69. }
  70. Camera::~Camera()
  71. {
  72. }
  73. void Camera::RegisterObject(Context* context)
  74. {
  75. context->RegisterComponentFactory<Camera>(SCENE_CATEGORY);
  76. ACCESSOR_ATTRIBUTE(Camera, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
  77. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "Near Clip", GetNearClip, SetNearClip, float, DEFAULT_NEARCLIP, AM_DEFAULT);
  78. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "Far Clip", GetFarClip, SetFarClip, float, DEFAULT_FARCLIP, AM_DEFAULT);
  79. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "FOV", GetFov, SetFov, float, DEFAULT_FOV, AM_DEFAULT);
  80. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "Aspect Ratio", GetAspectRatio, SetAspectRatio, float, 1.0f, AM_DEFAULT);
  81. ENUM_ATTRIBUTE(Camera, "Fill Mode", fillMode_, fillModeNames, FILL_SOLID, AM_DEFAULT);
  82. ATTRIBUTE(Camera, VAR_BOOL, "Auto Aspect Ratio", autoAspectRatio_, true, AM_DEFAULT);
  83. ACCESSOR_ATTRIBUTE(Camera, VAR_BOOL, "Orthographic", IsOrthographic, SetOrthographic, bool, false, AM_DEFAULT);
  84. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "Orthographic Size", GetOrthoSize, SetOrthoSize, float, DEFAULT_ORTHOSIZE, AM_DEFAULT);
  85. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "Zoom", GetZoom, SetZoom, float, 1.0f, AM_DEFAULT);
  86. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
  87. ATTRIBUTE(Camera, VAR_INT, "View Mask", viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
  88. ATTRIBUTE(Camera, VAR_INT, "View Override Flags", viewOverrideFlags_, VO_NONE, AM_DEFAULT);
  89. REF_ACCESSOR_ATTRIBUTE(Camera, VAR_VECTOR2, "Projection Offset", GetProjectionOffset, SetProjectionOffset, Vector2, Vector2::ZERO, AM_DEFAULT);
  90. }
  91. void Camera::SetNearClip(float nearClip)
  92. {
  93. nearClip_ = Max(nearClip, M_MIN_NEARCLIP);
  94. frustumDirty_ = true;
  95. projectionDirty_ = true;
  96. MarkNetworkUpdate();
  97. }
  98. void Camera::SetFarClip(float farClip)
  99. {
  100. farClip_ = Max(farClip, M_MIN_NEARCLIP);
  101. frustumDirty_ = true;
  102. projectionDirty_ = true;
  103. MarkNetworkUpdate();
  104. }
  105. void Camera::SetFov(float fov)
  106. {
  107. fov_ = Clamp(fov, 0.0f, M_MAX_FOV);
  108. frustumDirty_ = true;
  109. projectionDirty_ = true;
  110. MarkNetworkUpdate();
  111. }
  112. void Camera::SetOrthoSize(float orthoSize)
  113. {
  114. orthoSize_ = orthoSize;
  115. aspectRatio_ = 1.0f;
  116. frustumDirty_ = true;
  117. projectionDirty_ = true;
  118. MarkNetworkUpdate();
  119. }
  120. void Camera::SetOrthoSize(const Vector2& orthoSize)
  121. {
  122. orthoSize_ = orthoSize.y_;
  123. aspectRatio_ = orthoSize.x_ / orthoSize.y_;
  124. frustumDirty_ = true;
  125. projectionDirty_ = true;
  126. MarkNetworkUpdate();
  127. }
  128. void Camera::SetAspectRatio(float aspectRatio)
  129. {
  130. aspectRatio_ = aspectRatio;
  131. frustumDirty_ = true;
  132. projectionDirty_ = true;
  133. MarkNetworkUpdate();
  134. }
  135. void Camera::SetZoom(float zoom)
  136. {
  137. zoom_ = Max(zoom, M_EPSILON);
  138. frustumDirty_ = true;
  139. projectionDirty_ = true;
  140. MarkNetworkUpdate();
  141. }
  142. void Camera::SetLodBias(float bias)
  143. {
  144. lodBias_ = Max(bias, M_EPSILON);
  145. MarkNetworkUpdate();
  146. }
  147. void Camera::SetViewMask(unsigned mask)
  148. {
  149. viewMask_ = mask;
  150. MarkNetworkUpdate();
  151. }
  152. void Camera::SetViewOverrideFlags(unsigned flags)
  153. {
  154. viewOverrideFlags_ = flags;
  155. MarkNetworkUpdate();
  156. }
  157. void Camera::SetFillMode(FillMode mode)
  158. {
  159. fillMode_ = mode;
  160. MarkNetworkUpdate();
  161. }
  162. void Camera::SetOrthographic(bool enable)
  163. {
  164. orthographic_ = enable;
  165. frustumDirty_ = true;
  166. projectionDirty_ = true;
  167. MarkNetworkUpdate();
  168. }
  169. void Camera::SetAutoAspectRatio(bool enable)
  170. {
  171. autoAspectRatio_ = enable;
  172. MarkNetworkUpdate();
  173. }
  174. void Camera::SetProjectionOffset(const Vector2& offset)
  175. {
  176. projectionOffset_ = offset;
  177. projectionDirty_ = true;
  178. MarkNetworkUpdate();
  179. }
  180. void Camera::SetFlipVertical(bool enable)
  181. {
  182. flipVertical_ = enable;
  183. projectionDirty_ = true;
  184. MarkNetworkUpdate();
  185. }
  186. float Camera::GetNearClip() const
  187. {
  188. // Orthographic camera has always near clip at 0 to avoid trouble with shader depth parameters,
  189. // and unlike in perspective mode there should be no depth buffer precision issue
  190. if (!orthographic_)
  191. return nearClip_;
  192. else
  193. return 0.0f;
  194. }
  195. Frustum Camera::GetSplitFrustum(float nearClip, float farClip) const
  196. {
  197. Frustum ret;
  198. const Matrix3x4& worldTransform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
  199. nearClip = Max(nearClip, GetNearClip());
  200. farClip = Min(farClip, farClip_);
  201. if (farClip < nearClip)
  202. farClip = nearClip;
  203. if (!orthographic_)
  204. ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip, worldTransform);
  205. else
  206. ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip, worldTransform);
  207. return ret;
  208. }
  209. Frustum Camera::GetViewSpaceFrustum() const
  210. {
  211. Frustum ret;
  212. if (!orthographic_)
  213. ret.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_);
  214. else
  215. ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_);
  216. return ret;
  217. }
  218. Frustum Camera::GetViewSpaceSplitFrustum(float nearClip, float farClip) const
  219. {
  220. Frustum ret;
  221. nearClip = Max(nearClip, GetNearClip());
  222. farClip = Min(farClip, farClip_);
  223. if (farClip < nearClip)
  224. farClip = nearClip;
  225. if (!orthographic_)
  226. ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip);
  227. else
  228. ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip);
  229. return ret;
  230. }
  231. Ray Camera::GetScreenRay(float x, float y) const
  232. {
  233. Ray ret;
  234. // If projection is invalid, just return a ray pointing forward
  235. if (!IsProjectionValid())
  236. {
  237. ret.origin_ = node_ ? node_->GetWorldPosition() : Vector3::ZERO;
  238. ret.direction_ = GetForwardVector();
  239. return ret;
  240. }
  241. Matrix4 viewProjInverse = (GetProjection(false) * GetInverseWorldTransform()).Inverse();
  242. // The parameters range from 0.0 to 1.0. Expand to normalized device coordinates (-1.0 to 1.0) & flip Y axis
  243. x = 2.0f * x - 1.0f;
  244. y = 1.0f - 2.0f * y;
  245. Vector3 near(x, y, 0.0f);
  246. Vector3 far(x, y, 1.0f);
  247. ret.origin_ = viewProjInverse * near;
  248. ret.direction_ = ((viewProjInverse * far) - ret.origin_).Normalized();
  249. return ret;
  250. }
  251. Vector2 Camera::WorldToScreenPoint(const Vector3& worldPos) const
  252. {
  253. Vector3 eyeSpacePos = GetInverseWorldTransform() * worldPos;
  254. Vector2 ret;
  255. if(eyeSpacePos.z_ > 0.0f)
  256. {
  257. Vector3 screenSpacePos = GetProjection(false) * eyeSpacePos;
  258. ret.x_ = screenSpacePos.x_;
  259. ret.y_ = screenSpacePos.y_;
  260. }
  261. else
  262. {
  263. ret.x_ = (-eyeSpacePos.x_ > 0.0f) ? -1.0f : 1.0f;
  264. ret.y_ = (-eyeSpacePos.y_ > 0.0f) ? -1.0f : 1.0f;
  265. }
  266. ret.x_ = (ret.x_ / 2.0f) + 0.5f;
  267. ret.y_ = 1.0f - ((ret.y_ / 2.0f) + 0.5f);
  268. return ret;
  269. }
  270. Vector3 Camera::ScreenToWorldPoint(const Vector3& screenPos) const
  271. {
  272. Ray ray = GetScreenRay(screenPos.x_, screenPos.y_);
  273. return ray.origin_ + ray.direction_ * screenPos.z_;
  274. }
  275. const Frustum& Camera::GetFrustum() const
  276. {
  277. if (frustumDirty_)
  278. {
  279. const Matrix3x4& worldTransform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
  280. if (!orthographic_)
  281. frustum_.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_, worldTransform);
  282. else
  283. frustum_.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_, worldTransform);
  284. frustumDirty_ = false;
  285. }
  286. return frustum_;
  287. }
  288. const Matrix4& Camera::GetProjection() const
  289. {
  290. if (projectionDirty_)
  291. {
  292. projection_ = GetProjection(true);
  293. projectionDirty_ = false;
  294. }
  295. return projection_;
  296. }
  297. Matrix4 Camera::GetProjection(bool apiSpecific) const
  298. {
  299. Matrix4 ret(Matrix4::ZERO);
  300. if (!orthographic_)
  301. {
  302. float nearClip = GetNearClip();
  303. float h = (1.0f / tanf(fov_ * M_DEGTORAD * 0.5f)) * zoom_;
  304. float w = h / aspectRatio_;
  305. float q, r;
  306. if (apiSpecific)
  307. {
  308. #ifdef USE_OPENGL
  309. q = (farClip_ + nearClip) / (farClip_ - nearClip);
  310. r = -2.0f * farClip_ * nearClip / (farClip_ - nearClip);
  311. #else
  312. q = farClip_ / (farClip_ - nearClip);
  313. r = -q * nearClip;
  314. #endif
  315. }
  316. else
  317. {
  318. q = farClip_ / (farClip_ - nearClip);
  319. r = -q * nearClip;
  320. }
  321. ret.m00_ = w;
  322. ret.m02_ = projectionOffset_.x_ * 2.0f;
  323. ret.m11_ = h;
  324. ret.m12_ = projectionOffset_.y_ * 2.0f;
  325. ret.m22_ = q;
  326. ret.m23_ = r;
  327. ret.m32_ = 1.0f;
  328. }
  329. else
  330. {
  331. // Disregard near clip, because it does not affect depth precision as with perspective projection
  332. float h = (1.0f / (orthoSize_ * 0.5f)) * zoom_;
  333. float w = h / aspectRatio_;
  334. float q, r;
  335. if (apiSpecific)
  336. {
  337. #ifdef USE_OPENGL
  338. q = 2.0f / farClip_;
  339. r = -1.0f;
  340. #else
  341. q = 1.0f / farClip_;
  342. r = 0.0f;
  343. #endif
  344. }
  345. else
  346. {
  347. q = 1.0f / farClip_;
  348. r = 0.0f;
  349. }
  350. ret.m00_ = w;
  351. ret.m03_ = projectionOffset_.x_ * 2.0f;
  352. ret.m11_ = h;
  353. ret.m13_ = projectionOffset_.y_ * 2.0f;
  354. ret.m22_ = q;
  355. ret.m23_ = r;
  356. ret.m33_ = 1.0f;
  357. }
  358. if (flipVertical_)
  359. ret = flipMatrix * ret;
  360. return ret;
  361. }
  362. void Camera::GetFrustumSize(Vector3& near, Vector3& far) const
  363. {
  364. near.z_ = GetNearClip();
  365. far.z_ = farClip_;
  366. if (!orthographic_)
  367. {
  368. float halfViewSize = tanf(fov_ * M_DEGTORAD * 0.5f) / zoom_;
  369. near.y_ = near.z_ * halfViewSize;
  370. near.x_ = near.y_ * aspectRatio_;
  371. far.y_ = far.z_ * halfViewSize;
  372. far.x_ = far.y_ * aspectRatio_;
  373. }
  374. else
  375. {
  376. float halfViewSize = orthoSize_ * 0.5f / zoom_;
  377. near.y_ = far.y_ = halfViewSize;
  378. near.x_ = far.x_ = near.y_ * aspectRatio_;
  379. }
  380. if (flipVertical_)
  381. {
  382. near.y_ = -near.y_;
  383. far.y_ = -far.y_;
  384. }
  385. }
  386. float Camera::GetHalfViewSize() const
  387. {
  388. if (!orthographic_)
  389. return tanf(fov_ * M_DEGTORAD * 0.5f) / zoom_;
  390. else
  391. return orthoSize_ * 0.5f / zoom_;
  392. }
  393. Vector3 Camera::GetForwardVector() const
  394. {
  395. return node_ ? node_->GetWorldDirection() : Vector3::FORWARD;
  396. }
  397. Vector3 Camera::GetRightVector() const
  398. {
  399. return node_ ? node_->GetWorldTransform().RotationMatrix() * Vector3::RIGHT : Vector3::RIGHT;
  400. }
  401. Vector3 Camera::GetUpVector() const
  402. {
  403. return node_ ? node_->GetWorldTransform().RotationMatrix() * Vector3::UP : Vector3::UP;
  404. }
  405. float Camera::GetDistance(const Vector3& worldPos) const
  406. {
  407. if (!orthographic_)
  408. {
  409. const Vector3& cameraPos = node_ ? node_->GetWorldPosition() : Vector3::ZERO;
  410. return (worldPos - cameraPos).Length();
  411. }
  412. else
  413. return Abs((GetInverseWorldTransform() * worldPos).z_);
  414. }
  415. float Camera::GetDistanceSquared(const Vector3& worldPos) const
  416. {
  417. if (!orthographic_)
  418. {
  419. const Vector3& cameraPos = node_ ? node_->GetWorldPosition() : Vector3::ZERO;
  420. return (worldPos - cameraPos).LengthSquared();
  421. }
  422. else
  423. {
  424. float distance = (GetInverseWorldTransform() * worldPos).z_;
  425. return distance * distance;
  426. }
  427. }
  428. float Camera::GetLodDistance(float distance, float scale, float bias) const
  429. {
  430. float d = Max(lodBias_ * bias * scale * zoom_, M_EPSILON);
  431. if (!orthographic_)
  432. return distance / d;
  433. else
  434. return orthoSize_ / d;
  435. }
  436. bool Camera::IsProjectionValid() const
  437. {
  438. return farClip_ > GetNearClip();
  439. }
  440. const Matrix3x4& Camera::GetInverseWorldTransform() const
  441. {
  442. if (inverseWorldDirty_)
  443. {
  444. const Matrix3x4& worldTransform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
  445. inverseWorld_ = worldTransform.Inverse();
  446. inverseWorldDirty_ = false;
  447. }
  448. return inverseWorld_;
  449. }
  450. void Camera::OnNodeSet(Node* node)
  451. {
  452. if (node)
  453. node->AddListener(this);
  454. }
  455. void Camera::OnMarkedDirty(Node* node)
  456. {
  457. frustumDirty_ = true;
  458. inverseWorldDirty_ = true;
  459. }
  460. }