Camera.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. #include "Base.h"
  2. #include "Camera.h"
  3. #include "Game.h"
  4. #include "Node.h"
  5. #include "Game.h"
  6. #include "PhysicsController.h"
  7. // Camera dirty bits
  8. #define CAMERA_DIRTY_VIEW 1
  9. #define CAMERA_DIRTY_PROJ 2
  10. #define CAMERA_DIRTY_VIEW_PROJ 4
  11. #define CAMERA_DIRTY_INV_VIEW 8
  12. #define CAMERA_DIRTY_INV_VIEW_PROJ 16
  13. #define CAMERA_DIRTY_BOUNDS 32
  14. #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)
  15. namespace gameplay
  16. {
  17. Camera::Camera(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
  18. : _type(PERSPECTIVE), _fieldOfView(fieldOfView), _aspectRatio(aspectRatio), _nearPlane(nearPlane), _farPlane(farPlane),
  19. _dirtyBits(CAMERA_DIRTY_ALL), _node(NULL)
  20. {
  21. }
  22. Camera::Camera(float zoomX, float zoomY, float aspectRatio, float nearPlane, float farPlane)
  23. : _type(ORTHOGRAPHIC), _aspectRatio(aspectRatio), _nearPlane(nearPlane), _farPlane(farPlane),
  24. _dirtyBits(CAMERA_DIRTY_ALL), _node(NULL)
  25. {
  26. // Orthographic camera.
  27. _zoom[0] = zoomX;
  28. _zoom[1] = zoomY;
  29. }
  30. Camera::~Camera()
  31. {
  32. }
  33. Camera* Camera::createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
  34. {
  35. return new Camera(fieldOfView, aspectRatio, nearPlane, farPlane);
  36. }
  37. Camera* Camera::createOrthographic(float zoomX, float zoomY, float aspectRatio, float nearPlane, float farPlane)
  38. {
  39. return new Camera(zoomX, zoomY, aspectRatio, nearPlane, farPlane);
  40. }
  41. Camera* Camera::create(Properties* properties)
  42. {
  43. GP_ASSERT(properties);
  44. // Read camera type
  45. std::string typeStr;
  46. if (properties->exists("type"))
  47. typeStr = properties->getString("type");
  48. Camera::Type type;
  49. if (typeStr == "PERSPECTIVE")
  50. {
  51. type = Camera::PERSPECTIVE;
  52. }
  53. else if (typeStr == "ORTHOGRAPHIC")
  54. {
  55. type = Camera::ORTHOGRAPHIC;
  56. }
  57. else
  58. {
  59. GP_ERROR("Invalid 'type' parameter for camera definition.");
  60. return NULL;
  61. }
  62. // Read common parameters
  63. float aspectRatio, nearPlane, farPlane;
  64. if (properties->exists("aspectRatio"))
  65. {
  66. aspectRatio = properties->getFloat("aspectRatio");
  67. }
  68. else
  69. {
  70. // Use default aspect ratio
  71. aspectRatio = (float)Game::getInstance()->getWidth() / Game::getInstance()->getHeight();
  72. }
  73. if (properties->exists("nearPlane"))
  74. nearPlane = properties->getFloat("nearPlane");
  75. else
  76. nearPlane = 0.2f; // use some reasonable default value
  77. if (properties->exists("farPlane"))
  78. farPlane = properties->getFloat("farPlane");
  79. else
  80. farPlane = 100; // use some reasonable default value
  81. Camera* camera = NULL;
  82. switch (type)
  83. {
  84. case Camera::PERSPECTIVE:
  85. // If field of view is not specified, use a default of 60 degrees
  86. camera = createPerspective(
  87. properties->exists("fieldOfView") ? properties->getFloat("fieldOfView") : 60.0f,
  88. aspectRatio, nearPlane, farPlane);
  89. break;
  90. case Camera::ORTHOGRAPHIC:
  91. // If zoomX and zoomY are not specified, use screen width/height
  92. camera = createOrthographic(
  93. properties->exists("zoomX") ? properties->getFloat("zoomX") : Game::getInstance()->getWidth(),
  94. properties->exists("zoomY") ? properties->getFloat("zoomY") : Game::getInstance()->getHeight(),
  95. aspectRatio, nearPlane, farPlane);
  96. break;
  97. }
  98. return camera;
  99. }
  100. Camera::Type Camera::getCameraType() const
  101. {
  102. return _type;
  103. }
  104. float Camera::getFieldOfView() const
  105. {
  106. GP_ASSERT(_type == Camera::PERSPECTIVE);
  107. return _fieldOfView;
  108. }
  109. void Camera::setFieldOfView(float fieldOfView)
  110. {
  111. GP_ASSERT(_type == Camera::PERSPECTIVE);
  112. _fieldOfView = fieldOfView;
  113. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  114. }
  115. float Camera::getZoomX() const
  116. {
  117. GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
  118. return _zoom[0];
  119. }
  120. void Camera::setZoomX(float zoomX)
  121. {
  122. GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
  123. _zoom[0] = zoomX;
  124. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  125. }
  126. float Camera::getZoomY() const
  127. {
  128. GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
  129. return _zoom[1];
  130. }
  131. void Camera::setZoomY(float zoomY)
  132. {
  133. GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
  134. _zoom[1] = zoomY;
  135. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  136. }
  137. float Camera::getAspectRatio() const
  138. {
  139. return _aspectRatio;
  140. }
  141. void Camera::setAspectRatio(float aspectRatio)
  142. {
  143. _aspectRatio = aspectRatio;
  144. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  145. }
  146. float Camera::getNearPlane() const
  147. {
  148. return _nearPlane;
  149. }
  150. void Camera::setNearPlane(float nearPlane)
  151. {
  152. _nearPlane = nearPlane;
  153. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  154. }
  155. float Camera::getFarPlane() const
  156. {
  157. return _farPlane;
  158. }
  159. void Camera::setFarPlane(float farPlane)
  160. {
  161. _farPlane = farPlane;
  162. _dirtyBits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  163. }
  164. Node* Camera::getNode() const
  165. {
  166. return _node;
  167. }
  168. void Camera::setNode(Node* node)
  169. {
  170. if (_node != node)
  171. {
  172. if (_node)
  173. {
  174. _node->removeListener(this);
  175. }
  176. // Connect the new node.
  177. _node = node;
  178. if (_node)
  179. {
  180. _node->addListener(this);
  181. }
  182. _dirtyBits |= CAMERA_DIRTY_VIEW | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  183. }
  184. }
  185. const Matrix& Camera::getViewMatrix() const
  186. {
  187. if (_dirtyBits & CAMERA_DIRTY_VIEW)
  188. {
  189. if (_node)
  190. {
  191. // The view matrix is the inverse of our transform matrix.
  192. _node->getWorldMatrix().invert(&_view);
  193. }
  194. else
  195. {
  196. _view.setIdentity();
  197. }
  198. _dirtyBits &= ~CAMERA_DIRTY_VIEW;
  199. }
  200. return _view;
  201. }
  202. const Matrix& Camera::getInverseViewMatrix() const
  203. {
  204. if (_dirtyBits & CAMERA_DIRTY_INV_VIEW)
  205. {
  206. getViewMatrix().invert(&_inverseView);
  207. _dirtyBits &= ~CAMERA_DIRTY_INV_VIEW;
  208. }
  209. return _inverseView;
  210. }
  211. const Matrix& Camera::getProjectionMatrix() const
  212. {
  213. if (_dirtyBits & CAMERA_DIRTY_PROJ)
  214. {
  215. if (_type == PERSPECTIVE)
  216. {
  217. Matrix::createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane, &_projection);
  218. }
  219. else
  220. {
  221. Matrix::createOrthographic(_zoom[0], _zoom[1], _nearPlane, _farPlane, &_projection);
  222. }
  223. _dirtyBits &= ~CAMERA_DIRTY_PROJ;
  224. }
  225. return _projection;
  226. }
  227. const Matrix& Camera::getViewProjectionMatrix() const
  228. {
  229. if (_dirtyBits & CAMERA_DIRTY_VIEW_PROJ)
  230. {
  231. Matrix::multiply(getProjectionMatrix(), getViewMatrix(), &_viewProjection);
  232. _dirtyBits &= ~CAMERA_DIRTY_VIEW_PROJ;
  233. }
  234. return _viewProjection;
  235. }
  236. const Matrix& Camera::getInverseViewProjectionMatrix() const
  237. {
  238. if (_dirtyBits & CAMERA_DIRTY_INV_VIEW_PROJ)
  239. {
  240. getViewProjectionMatrix().invert(&_inverseViewProjection);
  241. _dirtyBits &= ~CAMERA_DIRTY_INV_VIEW_PROJ;
  242. }
  243. return _inverseViewProjection;
  244. }
  245. const Frustum& Camera::getFrustum() const
  246. {
  247. if (_dirtyBits & CAMERA_DIRTY_BOUNDS)
  248. {
  249. // Update our bounding frustum from our view projection matrix.
  250. _bounds.set(getViewProjectionMatrix());
  251. _dirtyBits &= ~CAMERA_DIRTY_BOUNDS;
  252. }
  253. return _bounds;
  254. }
  255. void Camera::project(const Rectangle& viewport, const Vector3& position, float* x, float* y, float* depth) const
  256. {
  257. GP_ASSERT(x);
  258. GP_ASSERT(y);
  259. // Transform the point to clip-space.
  260. Vector4 clipPos;
  261. getViewProjectionMatrix().transformVector(Vector4(position.x, position.y, position.z, 1.0f), &clipPos);
  262. // Compute normalized device coordinates.
  263. GP_ASSERT(clipPos.w != 0.0f);
  264. float ndcX = clipPos.x / clipPos.w;
  265. float ndcY = clipPos.y / clipPos.w;
  266. // Compute screen coordinates by applying our viewport transformation.
  267. *x = viewport.x + (ndcX + 1.0f) * 0.5f * viewport.width;
  268. *y = viewport.y + (1.0f - (ndcY + 1.0f) * 0.5f) * viewport.height;
  269. if (depth)
  270. {
  271. float ndcZ = clipPos.z / clipPos.w;
  272. *depth = ndcZ + 1.0f / 2.0f;
  273. }
  274. }
  275. void Camera::unproject(const Rectangle& viewport, float x, float y, float depth, Vector3* dst) const
  276. {
  277. GP_ASSERT(dst);
  278. // Create our screen space position in NDC.
  279. GP_ASSERT(viewport.width != 0.0f && viewport.height != 0.0f);
  280. Vector4 screen((x - viewport.x) / viewport.width, ((viewport.height - y) - viewport.y) / viewport.height, depth, 1.0f);
  281. // Map to range -1 to 1.
  282. screen.x = screen.x * 2.0f - 1.0f;
  283. screen.y = screen.y * 2.0f - 1.0f;
  284. screen.z = screen.z * 2.0f - 1.0f;
  285. // Transform the screen-space NDC by our inverse view projection matrix.
  286. getInverseViewProjectionMatrix().transformVector(screen, &screen);
  287. // Divide by our W coordinate.
  288. if (screen.w != 0.0f)
  289. {
  290. screen.x /= screen.w;
  291. screen.y /= screen.w;
  292. screen.z /= screen.w;
  293. }
  294. dst->set(screen.x, screen.y, screen.z);
  295. }
  296. void Camera::pickRay(const Rectangle& viewport, float x, float y, Ray* dst) const
  297. {
  298. GP_ASSERT(dst);
  299. // Get the world-space position at the near clip plane.
  300. Vector3 nearPoint;
  301. unproject(viewport, x, y, 0.0f, &nearPoint);
  302. // Get the world-space position at the far clip plane.
  303. Vector3 farPoint;
  304. unproject(viewport, x, y, 1.0f, &farPoint);
  305. // Set the direction of the ray.
  306. Vector3 direction;
  307. Vector3::subtract(farPoint, nearPoint, &direction);
  308. direction.normalize();
  309. dst->set(nearPoint, direction);
  310. }
  311. Camera* Camera::clone(NodeCloneContext &context) const
  312. {
  313. Camera* cameraClone = NULL;
  314. if (getCameraType() == PERSPECTIVE)
  315. {
  316. cameraClone = createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane);
  317. }
  318. else if (getCameraType() == ORTHOGRAPHIC)
  319. {
  320. cameraClone = createOrthographic(getZoomX(), getZoomY(), getAspectRatio(), _nearPlane, _farPlane);
  321. }
  322. GP_ASSERT(cameraClone);
  323. if (Node* node = context.findClonedNode(getNode()))
  324. {
  325. cameraClone->setNode(node);
  326. }
  327. return cameraClone;
  328. }
  329. void Camera::transformChanged(Transform* transform, long cookie)
  330. {
  331. _dirtyBits |= CAMERA_DIRTY_VIEW | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
  332. }
  333. }