Camera.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. #include "Base.h"
  2. #include "Camera.h"
  3. #include "Game.h"
  4. #include "Node.h"
  5. // Camera dirty bits
  6. #define CAMERA_DIRTY_VIEW 1
  7. #define CAMERA_DIRTY_PROJ 2
  8. #define CAMERA_DIRTY_VIEW_PROJ 4
  9. #define CAMERA_DIRTY_INV_VIEW 8
  10. #define CAMERA_DIRTY_INV_VIEW_PROJ 16
  11. #define CAMERA_DIRTY_BOUNDS 32
  12. #define CAMERA_DIRTY_ALL (CAMERA_DIRTY_VIEW | CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS)
  13. namespace gameplay
  14. {
  15. Camera::Camera(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
  16. : _type(PERSPECTIVE), _fieldOfView(fieldOfView), _aspectRatio(aspectRatio), _nearPlane(nearPlane), _farPlane(farPlane),
  17. _dirtyBits(CAMERA_DIRTY_ALL), _node(NULL)
  18. {
  19. }
  20. Camera::Camera(float zoomX, float zoomY, float aspectRatio, float nearPlane, float farPlane)
  21. : _type(ORTHOGRAPHIC), _aspectRatio(aspectRatio), _nearPlane(nearPlane), _farPlane(farPlane),
  22. _dirtyBits(CAMERA_DIRTY_ALL), _node(NULL)
  23. {
  24. // Orthographic camera.
  25. _zoom[0] = zoomX;
  26. _zoom[1] = zoomY;
  27. }
  28. Camera::~Camera()
  29. {
  30. }
  31. Camera* Camera::createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
  32. {
  33. return new Camera(fieldOfView, aspectRatio, nearPlane, farPlane);
  34. }
  35. Camera* Camera::createOrthographic(float zoomX, float zoomY, float aspectRatio, float nearPlane, float farPlane)
  36. {
  37. return new Camera(zoomX, zoomY, aspectRatio, nearPlane, farPlane);
  38. }
  39. Camera::Type Camera::getCameraType() const
  40. {
  41. return _type;
  42. }
  43. float Camera::getFieldOfView() const
  44. {
  45. assert(_type == Camera::PERSPECTIVE);
  46. return _fieldOfView;
  47. }
  48. void Camera::setFieldOfView(float fieldOfView)
  49. {
  50. assert(_type == Camera::PERSPECTIVE);
  51. _fieldOfView = fieldOfView;
  52. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  53. }
  54. float Camera::getZoomX() const
  55. {
  56. assert(_type == Camera::ORTHOGRAPHIC);
  57. return _zoom[0];
  58. }
  59. void Camera::setZoomX(float zoomX)
  60. {
  61. assert(_type == Camera::ORTHOGRAPHIC);
  62. _zoom[0] = zoomX;
  63. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  64. }
  65. float Camera::getZoomY() const
  66. {
  67. assert(_type == Camera::ORTHOGRAPHIC);
  68. return _zoom[1];
  69. }
  70. void Camera::setZoomY(float zoomY)
  71. {
  72. assert(_type == Camera::ORTHOGRAPHIC);
  73. _zoom[1] = zoomY;
  74. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  75. }
  76. float Camera::getAspectRatio() const
  77. {
  78. return _aspectRatio;
  79. }
  80. void Camera::setAspectRatio(float aspectRatio)
  81. {
  82. _aspectRatio = aspectRatio;
  83. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  84. }
  85. float Camera::getNearPlane() const
  86. {
  87. return _nearPlane;
  88. }
  89. void Camera::setNearPlane(float nearPlane)
  90. {
  91. _nearPlane = nearPlane;
  92. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  93. }
  94. float Camera::getFarPlane() const
  95. {
  96. return _farPlane;
  97. }
  98. void Camera::setFarPlane(float farPlane)
  99. {
  100. _farPlane = farPlane;
  101. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  102. }
  103. Node* Camera::getNode() const
  104. {
  105. return _node;
  106. }
  107. void Camera::setNode(Node* node)
  108. {
  109. if (_node != node)
  110. {
  111. if (_node)
  112. {
  113. _node->removeListener(this);
  114. }
  115. // Connect the new node.
  116. _node = node;
  117. if (_node)
  118. {
  119. _node->addListener(this);
  120. }
  121. _dirtyBits |= CAMERA_DIRTY_VIEW | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  122. }
  123. }
  124. const Matrix& Camera::getViewMatrix() const
  125. {
  126. if (_dirtyBits & CAMERA_DIRTY_VIEW)
  127. {
  128. if (_node)
  129. {
  130. // The view matrix is the inverse of our transform matrix.
  131. _node->getMatrix().invert(&_view);
  132. }
  133. else
  134. {
  135. _view.setIdentity();
  136. }
  137. _dirtyBits &= ~CAMERA_DIRTY_VIEW;
  138. }
  139. return _view;
  140. }
  141. const Matrix& Camera::getInverseViewMatrix() const
  142. {
  143. if (_dirtyBits & CAMERA_DIRTY_INV_VIEW)
  144. {
  145. getViewMatrix().invert(&_inverseView);
  146. _dirtyBits &= ~CAMERA_DIRTY_INV_VIEW;
  147. }
  148. return _inverseView;
  149. }
  150. const Matrix& Camera::getProjectionMatrix() const
  151. {
  152. if (_dirtyBits & CAMERA_DIRTY_PROJ)
  153. {
  154. if (_type == PERSPECTIVE)
  155. {
  156. Matrix::createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane, &_projection);
  157. }
  158. else
  159. {
  160. Matrix::createOrthographic(_zoom[0], _zoom[1], _nearPlane, _farPlane, &_projection);
  161. }
  162. _dirtyBits &= ~CAMERA_DIRTY_PROJ;
  163. }
  164. return _projection;
  165. }
  166. const Matrix& Camera::getViewProjectionMatrix() const
  167. {
  168. if (_dirtyBits & CAMERA_DIRTY_VIEW_PROJ)
  169. {
  170. Matrix::multiply(getProjectionMatrix(), getViewMatrix(), &_viewProjection);
  171. _dirtyBits &= ~CAMERA_DIRTY_VIEW_PROJ;
  172. }
  173. return _viewProjection;
  174. }
  175. const Matrix& Camera::getInverseViewProjectionMatrix() const
  176. {
  177. if (_dirtyBits & CAMERA_DIRTY_INV_VIEW_PROJ)
  178. {
  179. getViewProjectionMatrix().invert(&_inverseViewProjection);
  180. _dirtyBits &= ~CAMERA_DIRTY_INV_VIEW_PROJ;
  181. }
  182. return _inverseViewProjection;
  183. }
  184. const Frustum& Camera::getFrustum() const
  185. {
  186. if (_dirtyBits & CAMERA_DIRTY_BOUNDS)
  187. {
  188. // Update our bounding frustum from our view projection matrix.
  189. _bounds.set(getViewProjectionMatrix());
  190. _dirtyBits &= ~CAMERA_DIRTY_BOUNDS;
  191. }
  192. return _bounds;
  193. }
  194. void Camera::project(const Viewport* viewport, const Vector3& position, float* x, float* y, float* depth)
  195. {
  196. // Determine viewport coords to use.
  197. float vpx, vpy, vpw, vph;
  198. if (viewport)
  199. {
  200. vpx = viewport->getX();
  201. vpy = viewport->getY();
  202. vpw = viewport->getWidth();
  203. vph = viewport->getHeight();
  204. }
  205. else
  206. {
  207. vpx = 0;
  208. vpy = 0;
  209. vpw = Game::getInstance()->getWidth();
  210. vph = Game::getInstance()->getHeight();
  211. }
  212. // Transform the point to clip-space.
  213. Vector4 clipPos;
  214. getViewProjectionMatrix().transformVector(Vector4(position.x, position.y, position.z, 1.0f), &clipPos);
  215. // Compute normalized device coordinates.
  216. float ndcX = clipPos.x / clipPos.w;
  217. float ndcY = clipPos.y / clipPos.w;
  218. // Compute screen coordinates by applying our viewport transformation.
  219. *x = vpx + (ndcX + 1.0f) * 0.5f * vpw;
  220. *y = vpy + (1.0f - (ndcY + 1.0f) * 0.5f) * vph;
  221. if (depth)
  222. {
  223. float ndcZ = clipPos.z / clipPos.w;
  224. *depth = ndcZ + 1.0f / 2.0f;
  225. }
  226. }
  227. void Camera::unproject(const Viewport* viewport, float x, float y, float depth, Vector3* dst)
  228. {
  229. // Determine viewport coords to use.
  230. float vpx, vpy, vpw, vph;
  231. if (viewport)
  232. {
  233. vpx = viewport->getX();
  234. vpy = viewport->getY();
  235. vpw = viewport->getWidth();
  236. vph = viewport->getHeight();
  237. }
  238. else
  239. {
  240. vpx = 0;
  241. vpy = 0;
  242. vpw = Game::getInstance()->getWidth();
  243. vph = Game::getInstance()->getHeight();
  244. }
  245. // Create our screen space position in NDC.
  246. Vector4 screen(
  247. ((float)x - (float)vpx) / (float)vpw,
  248. ((float)(vph - y) - (float)vpy) / (float)vph,
  249. depth,
  250. 1.0f );
  251. // Map to range -1 to 1.
  252. screen.x = screen.x * 2.0f - 1.0f;
  253. screen.y = screen.y * 2.0f - 1.0f;
  254. screen.z = screen.z * 2.0f - 1.0f;
  255. // Transform the screen-space NDC by our inverse view projection matrix.
  256. getInverseViewProjectionMatrix().transformVector(screen, &screen);
  257. // Divide by our W coordinate.
  258. if (screen.w != 0.0f)
  259. {
  260. screen.x /= screen.w;
  261. screen.y /= screen.w;
  262. screen.z /= screen.w;
  263. }
  264. dst->set(screen.x, screen.y, screen.z);
  265. }
  266. void Camera::pickRay(const Viewport* viewport, float x, float y, Ray* dst)
  267. {
  268. // Get the world-space position at the near clip plane.
  269. Vector3 nearPoint;
  270. unproject(viewport, x, y, 0.0f, &nearPoint);
  271. // Get the world-space position at the far clip plane.
  272. Vector3 farPoint;
  273. unproject(viewport, x, y, 1.0f, &farPoint);
  274. // Set the direction of the ray.
  275. Vector3 direction;
  276. Vector3::subtract(farPoint, nearPoint, &direction);
  277. direction.normalize();
  278. dst->set(nearPoint, direction);
  279. }
  280. void Camera::transformChanged(Transform* transform)
  281. {
  282. _dirtyBits |= CAMERA_DIRTY_VIEW | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  283. }
  284. }