Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

Camera.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. /*!
  2. * \file src/Camera.cpp
  3. * \brief Camera class
  4. *
  5. * \author Mongoose
  6. * \author xythobuz
  7. */
  8. #include <limits>
  9. #include "global.h"
  10. #include "RunTime.h"
  11. #include "system/Shader.h"
  12. #include "system/Window.h"
  13. #include "Camera.h"
  14. #include <glm/gtc/epsilon.hpp>
  15. #include <glm/gtc/matrix_transform.hpp>
  16. #include <glm/gtc/quaternion.hpp>
  17. #include <glm/gtx/quaternion.hpp>
  18. static bool equal(float a, float b) {
  19. return glm::epsilonEqual(a, b, std::numeric_limits<float>::epsilon());
  20. }
  21. static bool equal(glm::vec2 a, float b) {
  22. return equal(a.x, b) && equal(a.y, b);
  23. }
  24. static bool equal(glm::vec3 a, float b) {
  25. return equal(a.x, b) && equal(a.y, b) && equal(a.z, b);
  26. }
  27. // ----------------------------------------------------------------------------
  28. const static float fov = 45.0f;
  29. const static float nearDist = 0.1f;
  30. const static float farDist = 75000.0f;
  31. const static float maxSpeed = 3072.0f;
  32. const static float controllerViewFactor = glm::pi<float>();
  33. const static float controllerDeadZone = 0.2f;
  34. const static glm::vec3 rightUnit(1.0f, 0.0f, 0.0f);
  35. const static glm::vec3 upUnit(0.0f, 1.0f, 0.0f);
  36. const static glm::vec3 dirUnit(0.0f, 0.0f, -1.0f);
  37. glm::vec3 Camera::pos(0.0f, 0.0f, 0.0f);
  38. glm::vec2 Camera::rot(glm::pi<float>(), 0.0f);
  39. glm::vec3 Camera::posSpeed(0.0f, 0.0f, 0.0f);
  40. glm::vec2 Camera::rotSpeed(0.0f, 0.0f);
  41. glm::mat4 Camera::projection(1.0f);
  42. glm::mat4 Camera::view(1.0f);
  43. float Camera::rotationDeltaX = 0.75f;
  44. float Camera::rotationDeltaY = 0.75f;
  45. bool Camera::updateViewFrustum = true;
  46. bool Camera::dirty = true;
  47. void Camera::reset() {
  48. pos = glm::vec3(0.0f, 0.0f, 0.0f);
  49. rot = glm::vec2(glm::pi<float>(), 0.0f);
  50. posSpeed = glm::vec3(0.0f, 0.0f, 0.0f);
  51. rotSpeed = glm::vec2(0.0f, 0.0f);
  52. dirty = true;
  53. projection = glm::mat4(1.0f);
  54. view = glm::mat4(1.0f);
  55. setSize(Window::getSize());
  56. }
  57. void Camera::setSize(glm::i32vec2 s) {
  58. //! \fixme TODO instead of mirroring the Y axis in the shader, scale with -1 here
  59. projection = glm::perspective(fov, float(s.x) / float(s.y), nearDist, farDist);
  60. }
  61. void Camera::handleAction(ActionEvents action, bool isFinished) {
  62. float factor = 1.0f;
  63. if (isFinished)
  64. factor = -1.0f;
  65. if (action == forwardAction) {
  66. posSpeed += dirUnit * maxSpeed * factor;
  67. } else if (action == backwardAction) {
  68. posSpeed -= dirUnit * maxSpeed * factor;
  69. } else if (action == leftAction) {
  70. posSpeed += rightUnit * maxSpeed * factor;
  71. } else if (action == rightAction) {
  72. posSpeed -= rightUnit * maxSpeed * factor;
  73. } else if (action == jumpAction) {
  74. posSpeed += upUnit * maxSpeed * factor;
  75. } else if (action == crouchAction) {
  76. posSpeed -= upUnit * maxSpeed * factor;
  77. } else {
  78. return;
  79. }
  80. dirty = true;
  81. }
  82. void Camera::handleMouseMotion(int x, int y) {
  83. if ((x != 0) || (y != 0))
  84. dirty = true;
  85. while (x > 0) {
  86. rot.x += rotationDeltaX;
  87. x--;
  88. }
  89. while (x < 0) {
  90. rot.x -= rotationDeltaX;
  91. x++;
  92. }
  93. while (y > 0) {
  94. if (rot.y > -(glm::pi<float>() / 2.0f)) {
  95. rot.y -= rotationDeltaY;
  96. }
  97. y--;
  98. }
  99. while (y < 0) {
  100. if (rot.y < (glm::pi<float>() / 2.0f)) {
  101. rot.y += rotationDeltaY;
  102. }
  103. y++;
  104. }
  105. while (rot.x > (glm::pi<float>() * 2.0f))
  106. rot.x -= glm::pi<float>() * 2.0f;
  107. while (rot.x < -(glm::pi<float>() * 2.0f))
  108. rot.x += glm::pi<float>() * 2.0f;
  109. }
  110. void Camera::handleControllerAxis(float value, KeyboardButton axis) {
  111. if (glm::epsilonEqual(value, 0.0f, controllerDeadZone))
  112. value = 0.0f;
  113. // TODO clamp Y rotation axis somehow...?
  114. if (axis == leftXAxis) {
  115. posSpeed.x = -maxSpeed * value;
  116. } else if (axis == leftYAxis) {
  117. posSpeed.z = maxSpeed * value;
  118. } else if (axis == rightXAxis) {
  119. rotSpeed.x = controllerViewFactor * value;
  120. } else if (axis == rightYAxis) {
  121. rotSpeed.y = -controllerViewFactor * value;
  122. } else {
  123. return;
  124. }
  125. dirty = true;
  126. }
  127. void Camera::handleControllerButton(KeyboardButton button, bool released) {
  128. if (button == aButton) {
  129. handleAction(jumpAction, released);
  130. } else if (button == bButton) {
  131. handleAction(crouchAction, released);
  132. } else if (button == padUp) {
  133. handleAction(forwardAction, released);
  134. } else if (button == padDown) {
  135. handleAction(backwardAction, released);
  136. } else if (button == padLeft) {
  137. handleAction(leftAction, released);
  138. } else if (button == padRight) {
  139. handleAction(rightAction, released);
  140. } else {
  141. return;
  142. }
  143. dirty = true;
  144. }
  145. bool Camera::update() {
  146. if ((!dirty) && equal(posSpeed, 0.0f) && equal(rotSpeed, 0.0f))
  147. return false;
  148. float dT = RunTime::getLastFrameTime();
  149. rot += rotSpeed * dT;
  150. glm::quat quatY = glm::angleAxis(rot.x, glm::vec3(0.0f, 1.0f, 0.0f));
  151. glm::quat quatX = glm::angleAxis(rot.y, glm::vec3(1.0f, 0.0f, 0.0f));
  152. glm::quat quaternion = quatY * quatX;
  153. glm::vec3 clampedSpeed(posSpeed);
  154. if (glm::length(clampedSpeed) > maxSpeed) {
  155. clampedSpeed = glm::normalize(clampedSpeed) * maxSpeed;
  156. }
  157. pos += quaternion * clampedSpeed * dT;
  158. glm::mat4 translate = glm::translate(glm::mat4(1.0f), pos);
  159. glm::mat4 rotate = glm::toMat4(quaternion);
  160. view = glm::inverse(translate * rotate);
  161. if (updateViewFrustum)
  162. calculateFrustumPlanes();
  163. dirty = false;
  164. return updateViewFrustum;
  165. }
  166. // ----------------------------------------------------------------------------
  167. class FrustumPlane {
  168. public:
  169. FrustumPlane() : normal(glm::vec3(0.0f, 0.0f, 0.0f)), d(0.0f) { }
  170. void set(glm::vec3 v1, glm::vec3 v2, glm::vec3 v3) {
  171. normal = glm::normalize(glm::cross(v3 - v2, v1 - v2));
  172. d = -glm::dot(normal, v2);
  173. }
  174. float distance(glm::vec3 p) {
  175. return d + glm::dot(normal, p);
  176. }
  177. private:
  178. glm::vec3 normal;
  179. float d;
  180. };
  181. // ----------------------------------------------------------------------------
  182. #define NEAR 0
  183. #define FAR 1
  184. #define TOP 2
  185. #define BOTTOM 3
  186. #define LEFT 4
  187. #define RIGHT 5
  188. #define NTL 0
  189. #define NBL 1
  190. #define NBR 2
  191. #define NTR 3
  192. #define FTL 4
  193. #define FBL 5
  194. #define FBR 6
  195. #define FTR 7
  196. static FrustumPlane planes[6];
  197. static glm::vec3 frustumColors[6] = {
  198. glm::vec3(1.0f, 0.0f, 0.0f), // NEAR, red
  199. glm::vec3(0.0f, 1.0f, 0.0f), // FAR, green
  200. glm::vec3(0.0f, 0.0f, 1.0f), // TOP, blue
  201. glm::vec3(1.0f, 1.0f, 0.0f), // BOTTOM, yellow
  202. glm::vec3(0.0f, 1.0f, 1.0f), // LEFT, light-blue
  203. glm::vec3(1.0f, 0.0f, 1.0f) // RIGHT, pink
  204. };
  205. static glm::vec3 frustumVertices[8];
  206. static ShaderBuffer vertexBuffer;
  207. static ShaderBuffer colorBuffer;
  208. static ShaderBuffer indexBuffer;
  209. static ShaderBuffer vertexPointBuffer;
  210. static ShaderBuffer colorPointBuffer;
  211. void Camera::calculateFrustumPlanes() {
  212. glm::mat4 combo = projection * view;
  213. // Calculate frustum corners to display them
  214. glm::mat4 inverse = glm::inverse(combo);
  215. frustumVertices[NTL] = glm::vec3(1.0f, 1.0f, 0.0f);
  216. frustumVertices[NTR] = glm::vec3(-1.0f, 1.0f, 0.0f);
  217. frustumVertices[NBL] = glm::vec3(1.0f, -1.0f, 0.0f);
  218. frustumVertices[NBR] = glm::vec3(-1.0f, -1.0f, 0.0f);
  219. frustumVertices[FTL] = glm::vec3(1.0f, 1.0f, 1.0f);
  220. frustumVertices[FTR] = glm::vec3(-1.0f, 1.0f, 1.0f);
  221. frustumVertices[FBL] = glm::vec3(1.0f, -1.0f, 1.0f);
  222. frustumVertices[FBR] = glm::vec3(-1.0f, -1.0f, 1.0f);
  223. for (int i = 0; i < 8; i++) {
  224. glm::vec4 t = inverse * glm::vec4(frustumVertices[i], 1.0f);
  225. frustumVertices[i] = glm::vec3(t) / t.w;
  226. frustumVertices[i].y *= -1.0f;
  227. }
  228. // Set planes used for frustum culling
  229. planes[TOP].set(frustumVertices[NTR], frustumVertices[NTL], frustumVertices[FTL]);
  230. planes[BOTTOM].set(frustumVertices[NBL], frustumVertices[NBR], frustumVertices[FBR]);
  231. planes[LEFT].set(frustumVertices[NTL], frustumVertices[NBL], frustumVertices[FBL]);
  232. planes[RIGHT].set(frustumVertices[NBR], frustumVertices[NTR], frustumVertices[FBR]);
  233. planes[NEAR].set(frustumVertices[NTL], frustumVertices[NTR], frustumVertices[NBR]);
  234. planes[FAR].set(frustumVertices[FTR], frustumVertices[FTL], frustumVertices[FBL]);
  235. std::vector<glm::vec3> verts;
  236. // Near
  237. verts.push_back(frustumVertices[NTL]);
  238. verts.push_back(frustumVertices[NTR]);
  239. verts.push_back(frustumVertices[NBR]);
  240. verts.push_back(frustumVertices[NBL]);
  241. // Far
  242. verts.push_back(frustumVertices[FTR]);
  243. verts.push_back(frustumVertices[FTL]);
  244. verts.push_back(frustumVertices[FBL]);
  245. verts.push_back(frustumVertices[FBR]);
  246. // Top
  247. verts.push_back(frustumVertices[NTR]);
  248. verts.push_back(frustumVertices[NTL]);
  249. verts.push_back(frustumVertices[FTL]);
  250. verts.push_back(frustumVertices[FTR]);
  251. // Bottom
  252. verts.push_back(frustumVertices[NBL]);
  253. verts.push_back(frustumVertices[NBR]);
  254. verts.push_back(frustumVertices[FBR]);
  255. verts.push_back(frustumVertices[FBL]);
  256. // Left
  257. verts.push_back(frustumVertices[NTL]);
  258. verts.push_back(frustumVertices[NBL]);
  259. verts.push_back(frustumVertices[FBL]);
  260. verts.push_back(frustumVertices[FTL]);
  261. // Right
  262. verts.push_back(frustumVertices[NBR]);
  263. verts.push_back(frustumVertices[NTR]);
  264. verts.push_back(frustumVertices[FTR]);
  265. verts.push_back(frustumVertices[FBR]);
  266. vertexBuffer.bufferData(verts);
  267. verts.clear();
  268. std::vector<glm::vec3> cols;
  269. verts.push_back(getPosition());
  270. cols.push_back(glm::vec3(1.0f, 1.0f, 1.0f));
  271. vertexPointBuffer.bufferData(verts);
  272. colorPointBuffer.bufferData(cols);
  273. if (colorBuffer.getSize() == 0) {
  274. cols.clear();
  275. for (int i = 0; i < 6; i++) {
  276. for (int j = 0; j < 4; j++) {
  277. cols.push_back(frustumColors[i]);
  278. }
  279. }
  280. colorBuffer.bufferData(cols);
  281. }
  282. if (indexBuffer.getSize() == 0) {
  283. std::vector<unsigned short> inds;
  284. for (int i = 0; i < 6; i++) {
  285. inds.push_back(4 * i);
  286. inds.push_back((4 * i) + 1);
  287. inds.push_back((4 * i) + 2);
  288. inds.push_back((4 * i) + 3);
  289. inds.push_back((4 * i) + 2);
  290. inds.push_back(4 * i);
  291. }
  292. indexBuffer.bufferData(inds);
  293. }
  294. }
  295. bool Camera::boxInFrustum(BoundingBox b) {
  296. for (int i = 0; i < 6; i++) {
  297. int out = 0, in = 0;
  298. for (int c = 0; (c < 8) && ((in == 0) || (out == 0)); c++) {
  299. if (planes[i].distance(b.getCorner(c)) < 0)
  300. out++;
  301. else
  302. in++;
  303. }
  304. if (in == 0)
  305. return false;
  306. }
  307. return true;
  308. }
  309. void Camera::displayFrustum(glm::mat4 MVP) {
  310. Shader::set2DState(true, false);
  311. Shader::drawGL(vertexBuffer, colorBuffer, indexBuffer, MVP);
  312. Shader::drawGL(vertexPointBuffer, colorPointBuffer, MVP, GL_POINTS);
  313. Shader::set2DState(false, false);
  314. }