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 12KB

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