2
0

Camera.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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 "Context.h"
  26. #include "Drawable.h"
  27. #include "DebugNew.h"
  28. static const float DEFAULT_NEARCLIP = 0.1f;
  29. static const float DEFAULT_FARCLIP = 1000.0f;
  30. static const float DEFAULT_FOV = 45.0f;
  31. static const float DEFAULT_ORTHOSIZE = 20.0f;
  32. OBJECTTYPESTATIC(Camera);
  33. Camera::Camera(Context* context) :
  34. Component(context),
  35. projectionOffset_(Vector2::ZERO),
  36. nearClip_(DEFAULT_NEARCLIP),
  37. farClip_(DEFAULT_FARCLIP),
  38. fov_(DEFAULT_FOV),
  39. orthoSize_(DEFAULT_ORTHOSIZE),
  40. aspectRatio_(1.0f),
  41. zoom_(1.0f),
  42. lodBias_(1.0f),
  43. viewMask_(DEFAULT_VIEWMASK),
  44. viewOverrideFlags_(VO_NONE),
  45. orthographic_(false),
  46. autoAspectRatio_(true),
  47. flipVertical_(false)
  48. {
  49. }
  50. Camera::~Camera()
  51. {
  52. }
  53. void Camera::RegisterObject(Context* context)
  54. {
  55. context->RegisterFactory<Camera>();
  56. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "Near Clip", GetNearClip, SetNearClip, float, DEFAULT_NEARCLIP, AM_DEFAULT);
  57. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "Far Clip", GetFarClip, SetFarClip, float, DEFAULT_FARCLIP, AM_DEFAULT);
  58. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "FOV", GetFov, SetFov, float, DEFAULT_FOV, AM_DEFAULT);
  59. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "Aspect Ratio", GetAspectRatio, SetAspectRatio, float, 1.0f, AM_DEFAULT);
  60. ATTRIBUTE(Camera, VAR_BOOL, "Auto Aspect Ratio", autoAspectRatio_, true, AM_DEFAULT);
  61. ATTRIBUTE(Camera, VAR_BOOL, "Orthographic", orthographic_, false, AM_DEFAULT);
  62. ATTRIBUTE(Camera, VAR_FLOAT, "Orthographic Size", orthoSize_, DEFAULT_ORTHOSIZE, AM_DEFAULT);
  63. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "Zoom", GetZoom, SetZoom, float, 1.0f, AM_DEFAULT);
  64. ACCESSOR_ATTRIBUTE(Camera, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
  65. ATTRIBUTE(Camera, VAR_INT, "View Mask", viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
  66. ATTRIBUTE(Camera, VAR_INT, "View Override Flags", viewOverrideFlags_, VO_NONE, AM_DEFAULT);
  67. ATTRIBUTE(Camera, VAR_VECTOR2, "Projection Offset", projectionOffset_, Vector2::ZERO, AM_DEFAULT);
  68. }
  69. void Camera::SetNearClip(float nearClip)
  70. {
  71. nearClip_ = Max(nearClip, M_MIN_NEARCLIP);
  72. }
  73. void Camera::SetFarClip(float farClip)
  74. {
  75. farClip_ = Max(farClip, M_MIN_NEARCLIP);
  76. }
  77. void Camera::SetFov(float fov)
  78. {
  79. fov_ = Clamp(fov, 0.0f, M_MAX_FOV);
  80. }
  81. void Camera::SetOrthoSize(float orthoSize)
  82. {
  83. orthoSize_ = orthoSize;
  84. aspectRatio_ = 1.0f;
  85. }
  86. void Camera::SetOrthoSize(const Vector2& orthoSize)
  87. {
  88. orthoSize_ = orthoSize.y_;
  89. aspectRatio_ = orthoSize.x_ / orthoSize.y_;
  90. }
  91. void Camera::SetAspectRatio(float aspectRatio)
  92. {
  93. aspectRatio_ = aspectRatio;
  94. }
  95. void Camera::SetZoom(float zoom)
  96. {
  97. zoom_ = Max(zoom, M_EPSILON);
  98. }
  99. void Camera::SetLodBias(float bias)
  100. {
  101. lodBias_ = Max(bias, M_EPSILON);
  102. }
  103. void Camera::SetViewMask(unsigned mask)
  104. {
  105. viewMask_ = mask;
  106. }
  107. void Camera::SetViewOverrideFlags(unsigned flags)
  108. {
  109. viewOverrideFlags_ = flags;
  110. }
  111. void Camera::SetOrthographic(bool enable)
  112. {
  113. orthographic_ = enable;
  114. }
  115. void Camera::SetAutoAspectRatio(bool enable)
  116. {
  117. autoAspectRatio_ = enable;
  118. }
  119. void Camera::SetProjectionOffset(const Vector2& offset)
  120. {
  121. projectionOffset_ = offset;
  122. }
  123. void Camera::SetFlipVertical(bool enable)
  124. {
  125. flipVertical_ = enable;
  126. }
  127. float Camera::GetNearClip() const
  128. {
  129. // Orthographic camera has always near clip at 0 to avoid trouble with shader depth parameters,
  130. // and unlike in perspective mode there should be no depth buffer precision issue
  131. if (!orthographic_)
  132. return nearClip_;
  133. else
  134. return 0.0f;
  135. }
  136. Frustum Camera::GetSplitFrustum(float nearClip, float farClip)
  137. {
  138. Frustum ret;
  139. nearClip = Max(nearClip, GetNearClip());
  140. farClip = Min(farClip, farClip_);
  141. if (farClip < nearClip)
  142. farClip = nearClip;
  143. if (!orthographic_)
  144. ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip, GetWorldTransform());
  145. else
  146. ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip, GetWorldTransform());
  147. return ret;
  148. }
  149. Frustum Camera::GetViewSpaceFrustum() const
  150. {
  151. Frustum ret;
  152. if (!orthographic_)
  153. ret.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_);
  154. else
  155. ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_);
  156. return ret;
  157. }
  158. Frustum Camera::GetViewSpaceSplitFrustum(float nearClip, float farClip) const
  159. {
  160. Frustum ret;
  161. nearClip = Max(nearClip, GetNearClip());
  162. farClip = Min(farClip, farClip_);
  163. if (farClip < nearClip)
  164. farClip = nearClip;
  165. if (!orthographic_)
  166. ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip);
  167. else
  168. ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip);
  169. return ret;
  170. }
  171. Ray Camera::GetScreenRay(float x, float y)
  172. {
  173. Ray ret;
  174. // If projection is invalid, just return a ray pointing forward
  175. if (!IsProjectionValid())
  176. {
  177. ret.origin_ = GetWorldPosition();
  178. ret.direction_ = GetForwardVector();
  179. return ret;
  180. }
  181. Matrix4 viewProjInverse = (GetProjection() * GetInverseWorldTransform()).Inverse();
  182. // The parameters range from 0.0 to 1.0. Expand to normalized device coordinates (-1.0 to 1.0) & flip Y axis
  183. x = 2.0f * x - 1.0f;
  184. y = 1.0f - 2.0f * y;
  185. #ifdef USE_OPENGL
  186. Vector3 near(x, y, -1.0f);
  187. Vector3 far(x, y, 1.0f);
  188. #else
  189. Vector3 near(x, y, 0.0f);
  190. Vector3 far(x, y, 1.0f);
  191. #endif
  192. ret.origin_ = viewProjInverse * near;
  193. ret.direction_ = ((viewProjInverse * far) - ret.origin_).Normalized();
  194. return ret;
  195. }
  196. Frustum Camera::GetFrustum() const
  197. {
  198. Frustum ret;
  199. if (!orthographic_)
  200. ret.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_, GetWorldTransform());
  201. else
  202. ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_, GetWorldTransform());
  203. return ret;
  204. }
  205. Matrix4 Camera::GetProjection() const
  206. {
  207. Matrix4 ret(Matrix4::ZERO);
  208. if (!orthographic_)
  209. {
  210. float nearClip = GetNearClip();
  211. float h = (1.0f / tanf(fov_ * M_DEGTORAD * 0.5f)) * zoom_;
  212. float w = h / aspectRatio_;
  213. #ifdef USE_OPENGL
  214. float q = (farClip_ + nearClip) / (farClip_ - nearClip);
  215. float r = -2.0f * farClip_ * nearClip / (farClip_ - nearClip);
  216. #else
  217. float q = farClip_ / (farClip_ - nearClip);
  218. float r = -q * nearClip;
  219. #endif
  220. ret.m00_ = w;
  221. ret.m02_ = projectionOffset_.x_ * 2.0f;
  222. ret.m11_ = h;
  223. ret.m12_ = projectionOffset_.y_ * 2.0f;
  224. ret.m22_ = q;
  225. ret.m23_ = r;
  226. ret.m32_ = 1.0f;
  227. }
  228. else
  229. {
  230. // Disregard near clip, because it does not affect depth precision as with perspective projection
  231. float h = (1.0f / (orthoSize_ * 0.5f)) * zoom_;
  232. float w = h / aspectRatio_;
  233. #ifdef USE_OPENGL
  234. float q = 2.0f / farClip_;
  235. float r = -1.0f;
  236. #else
  237. float q = 1.0f / farClip_;
  238. float r = 0.0f;
  239. #endif
  240. ret.m00_ = w;
  241. ret.m03_ = projectionOffset_.x_ * 2.0f;
  242. ret.m11_ = h;
  243. ret.m13_ = projectionOffset_.y_ * 2.0f;
  244. ret.m22_ = q;
  245. ret.m23_ = r;
  246. ret.m33_ = 1.0f;
  247. }
  248. if (flipVertical_)
  249. {
  250. Matrix4 flip(
  251. 1.0f, 0.0f, 0.0f, 0.0f,
  252. 0.0f, -1.0f, 0.0f, 0.0f,
  253. 0.0f, 0.0f, 1.0f, 0.0f,
  254. 0.0f, 0.0f, 0.0f, 1.0f
  255. );
  256. ret = flip * ret;
  257. }
  258. return ret;
  259. }
  260. void Camera::GetFrustumSize(Vector3& near, Vector3& far) const
  261. {
  262. near.z_ = GetNearClip();
  263. far.z_ = farClip_;
  264. if (!orthographic_)
  265. {
  266. float halfViewSize = tanf(fov_ * M_DEGTORAD * 0.5f) / zoom_;
  267. near.y_ = near.z_ * halfViewSize;
  268. near.x_ = near.y_ * aspectRatio_;
  269. far.y_ = far.z_ * halfViewSize;
  270. far.x_ = far.y_ * aspectRatio_;
  271. }
  272. else
  273. {
  274. float halfViewSize = orthoSize_ * 0.5f / zoom_;
  275. near.y_ = far.y_ = halfViewSize;
  276. near.x_ = far.x_ = near.y_ * aspectRatio_;
  277. }
  278. if (flipVertical_)
  279. {
  280. near.y_ = -near.y_;
  281. far.y_ = -far.y_;
  282. }
  283. }
  284. float Camera::GetHalfViewSize() const
  285. {
  286. if (!orthographic_)
  287. return tanf(fov_ * M_DEGTORAD * 0.5f) / zoom_;
  288. else
  289. return orthoSize_ * 0.5f / zoom_;
  290. }
  291. Vector3 Camera::GetForwardVector()
  292. {
  293. return GetWorldTransform().RotationMatrix() * Vector3::FORWARD;
  294. }
  295. Vector3 Camera::GetRightVector()
  296. {
  297. return GetWorldTransform().RotationMatrix() * Vector3::RIGHT;
  298. }
  299. Vector3 Camera::GetUpVector()
  300. {
  301. return GetWorldTransform().RotationMatrix() * Vector3::UP;
  302. }
  303. float Camera::GetDistance(const Vector3& worldPos)
  304. {
  305. if (!orthographic_)
  306. return (worldPos - GetWorldPosition()).Length();
  307. else
  308. return fabsf((GetInverseWorldTransform() * worldPos).z_);
  309. }
  310. float Camera::GetDistanceSquared(const Vector3& worldPos)
  311. {
  312. if (!orthographic_)
  313. return (worldPos - GetWorldPosition()).LengthSquared();
  314. else
  315. {
  316. float distance = (GetInverseWorldTransform() * worldPos).z_;
  317. return distance * distance;
  318. }
  319. }
  320. float Camera::GetLodDistance(float distance, float scale, float bias) const
  321. {
  322. float d = Max(lodBias_ * bias * scale * zoom_, M_EPSILON);
  323. if (!orthographic_)
  324. return distance / d;
  325. else
  326. return orthoSize_ / d;
  327. }
  328. bool Camera::IsProjectionValid() const
  329. {
  330. return farClip_ > GetNearClip();
  331. }