cam.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /*
  2. * Copyright (c), Recep Aslantas.
  3. *
  4. * MIT License (MIT), http://opensource.org/licenses/MIT
  5. * Full license can be found in the LICENSE file
  6. */
  7. /*
  8. Functions:
  9. CGLM_INLINE void glm_frustum(float left, float right,
  10. float bottom, float top,
  11. float nearVal, float farVal,
  12. mat4 dest)
  13. CGLM_INLINE void glm_ortho(float left, float right,
  14. float bottom, float top,
  15. float nearVal, float farVal,
  16. mat4 dest)
  17. CGLM_INLINE void glm_ortho_aabb(vec3 box[2], mat4 dest)
  18. CGLM_INLINE void glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest)
  19. CGLM_INLINE void glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest)
  20. CGLM_INLINE void glm_ortho_default(float aspect, mat4 dest)
  21. CGLM_INLINE void glm_ortho_default_s(float aspect, float size, mat4 dest)
  22. CGLM_INLINE void glm_perspective(float fovy,
  23. float aspect,
  24. float nearVal,
  25. float farVal,
  26. mat4 dest)
  27. CGLM_INLINE void glm_perspective_default(float aspect, mat4 dest)
  28. CGLM_INLINE void glm_perspective_resize(float aspect, mat4 proj)
  29. CGLM_INLINE void glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest)
  30. CGLM_INLINE void glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest)
  31. CGLM_INLINE void glm_look_anyup(vec3 eye, vec3 dir, mat4 dest)
  32. CGLM_INLINE void glm_persp_decomp(mat4 proj,
  33. float *nearVal, float *farVal,
  34. float *top, float *bottom,
  35. float *left, float *right)
  36. CGLM_INLINE void glm_persp_decompv(mat4 proj, float dest[6])
  37. CGLM_INLINE void glm_persp_decomp_x(mat4 proj, float *left, float *right)
  38. CGLM_INLINE void glm_persp_decomp_y(mat4 proj, float *top, float *bottom)
  39. CGLM_INLINE void glm_persp_decomp_z(mat4 proj, float *nearv, float *farv)
  40. CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float *farVal)
  41. CGLM_INLINE void glm_persp_decomp_near(mat4 proj, float *nearVal)
  42. CGLM_INLINE float glm_persp_fovy(mat4 proj)
  43. CGLM_INLINE float glm_persp_aspect(mat4 proj)
  44. CGLM_INLINE void glm_persp_sizes(mat4 proj, float fovy, vec4 dest)
  45. */
  46. #ifndef cglm_vcam_h
  47. #define cglm_vcam_h
  48. #include "common.h"
  49. #include "plane.h"
  50. /*!
  51. * @brief set up perspective peprojection matrix
  52. *
  53. * @param[in] left viewport.left
  54. * @param[in] right viewport.right
  55. * @param[in] bottom viewport.bottom
  56. * @param[in] top viewport.top
  57. * @param[in] nearVal near clipping plane
  58. * @param[in] farVal far clipping plane
  59. * @param[out] dest result matrix
  60. */
  61. CGLM_INLINE
  62. void
  63. glm_frustum(float left, float right,
  64. float bottom, float top,
  65. float nearVal, float farVal,
  66. mat4 dest) {
  67. float rl, tb, fn, nv;
  68. glm_mat4_zero(dest);
  69. rl = 1.0f / (right - left);
  70. tb = 1.0f / (top - bottom);
  71. fn =-1.0f / (farVal - nearVal);
  72. nv = 2.0f * nearVal;
  73. dest[0][0] = nv * rl;
  74. dest[1][1] = nv * tb;
  75. dest[2][0] = (right + left) * rl;
  76. dest[2][1] = (top + bottom) * tb;
  77. dest[2][2] = (farVal + nearVal) * fn;
  78. dest[2][3] =-1.0f;
  79. dest[3][2] = farVal * nv * fn;
  80. }
  81. /*!
  82. * @brief set up orthographic projection matrix
  83. *
  84. * @param[in] left viewport.left
  85. * @param[in] right viewport.right
  86. * @param[in] bottom viewport.bottom
  87. * @param[in] top viewport.top
  88. * @param[in] nearVal near clipping plane
  89. * @param[in] farVal far clipping plane
  90. * @param[out] dest result matrix
  91. */
  92. CGLM_INLINE
  93. void
  94. glm_ortho(float left, float right,
  95. float bottom, float top,
  96. float nearVal, float farVal,
  97. mat4 dest) {
  98. float rl, tb, fn;
  99. glm_mat4_zero(dest);
  100. rl = 1.0f / (right - left);
  101. tb = 1.0f / (top - bottom);
  102. fn =-1.0f / (farVal - nearVal);
  103. dest[0][0] = 2.0f * rl;
  104. dest[1][1] = 2.0f * tb;
  105. dest[2][2] = 2.0f * fn;
  106. dest[3][0] =-(right + left) * rl;
  107. dest[3][1] =-(top + bottom) * tb;
  108. dest[3][2] = (farVal + nearVal) * fn;
  109. dest[3][3] = 1.0f;
  110. }
  111. /*!
  112. * @brief set up orthographic projection matrix using bounding box
  113. *
  114. * bounding box (AABB) must be in view space
  115. *
  116. * @param[in] box AABB
  117. * @param[out] dest result matrix
  118. */
  119. CGLM_INLINE
  120. void
  121. glm_ortho_aabb(vec3 box[2], mat4 dest) {
  122. glm_ortho(box[0][0], box[1][0],
  123. box[0][1], box[1][1],
  124. -box[1][2], -box[0][2],
  125. dest);
  126. }
  127. /*!
  128. * @brief set up orthographic projection matrix using bounding box
  129. *
  130. * bounding box (AABB) must be in view space
  131. *
  132. * @param[in] box AABB
  133. * @param[in] padding padding
  134. * @param[out] dest result matrix
  135. */
  136. CGLM_INLINE
  137. void
  138. glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest) {
  139. glm_ortho(box[0][0] - padding, box[1][0] + padding,
  140. box[0][1] - padding, box[1][1] + padding,
  141. -(box[1][2] + padding), -(box[0][2] - padding),
  142. dest);
  143. }
  144. /*!
  145. * @brief set up orthographic projection matrix using bounding box
  146. *
  147. * bounding box (AABB) must be in view space
  148. *
  149. * @param[in] box AABB
  150. * @param[in] padding padding for near and far
  151. * @param[out] dest result matrix
  152. */
  153. CGLM_INLINE
  154. void
  155. glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest) {
  156. glm_ortho(box[0][0], box[1][0],
  157. box[0][1], box[1][1],
  158. -(box[1][2] + padding), -(box[0][2] - padding),
  159. dest);
  160. }
  161. /*!
  162. * @brief set up unit orthographic projection matrix
  163. *
  164. * @param[in] aspect aspect ration ( width / height )
  165. * @param[out] dest result matrix
  166. */
  167. CGLM_INLINE
  168. void
  169. glm_ortho_default(float aspect, mat4 dest) {
  170. if (aspect >= 1.0f) {
  171. glm_ortho(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest);
  172. return;
  173. }
  174. aspect = 1.0f / aspect;
  175. glm_ortho(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest);
  176. }
  177. /*!
  178. * @brief set up orthographic projection matrix with given CUBE size
  179. *
  180. * @param[in] aspect aspect ratio ( width / height )
  181. * @param[in] size cube size
  182. * @param[out] dest result matrix
  183. */
  184. CGLM_INLINE
  185. void
  186. glm_ortho_default_s(float aspect, float size, mat4 dest) {
  187. if (aspect >= 1.0f) {
  188. glm_ortho(-size * aspect,
  189. size * aspect,
  190. -size,
  191. size,
  192. -size - 100.0f,
  193. size + 100.0f,
  194. dest);
  195. return;
  196. }
  197. glm_ortho(-size,
  198. size,
  199. -size / aspect,
  200. size / aspect,
  201. -size - 100.0f,
  202. size + 100.0f,
  203. dest);
  204. }
  205. /*!
  206. * @brief set up perspective projection matrix
  207. *
  208. * @param[in] fovy field of view angle
  209. * @param[in] aspect aspect ratio ( width / height )
  210. * @param[in] nearVal near clipping plane
  211. * @param[in] farVal far clipping planes
  212. * @param[out] dest result matrix
  213. */
  214. CGLM_INLINE
  215. void
  216. glm_perspective(float fovy,
  217. float aspect,
  218. float nearVal,
  219. float farVal,
  220. mat4 dest) {
  221. float f, fn;
  222. glm_mat4_zero(dest);
  223. f = 1.0f / tanf(fovy * 0.5f);
  224. fn = 1.0f / (nearVal - farVal);
  225. dest[0][0] = f / aspect;
  226. dest[1][1] = f;
  227. dest[2][2] = (nearVal + farVal) * fn;
  228. dest[2][3] =-1.0f;
  229. dest[3][2] = 2.0f * nearVal * farVal * fn;
  230. }
  231. /*!
  232. * @brief extend perspective projection matrix's far distance
  233. *
  234. * this function does not guarantee far >= near, be aware of that!
  235. *
  236. * @param[in, out] proj projection matrix to extend
  237. * @param[in] deltaFar distance from existing far (negative to shink)
  238. */
  239. CGLM_INLINE
  240. void
  241. glm_persp_move_far(mat4 proj, float deltaFar) {
  242. float fn, farVal, nearVal, p22, p32;
  243. p22 = proj[2][2];
  244. p32 = proj[3][2];
  245. nearVal = p32 / (p22 - 1.0f);
  246. farVal = p32 / (p22 + 1.0f) + deltaFar;
  247. fn = 1.0f / (nearVal - farVal);
  248. proj[2][2] = (nearVal + farVal) * fn;
  249. proj[3][2] = 2.0f * nearVal * farVal * fn;
  250. }
  251. /*!
  252. * @brief set up perspective projection matrix with default near/far
  253. * and angle values
  254. *
  255. * @param[in] aspect aspect ratio ( width / height )
  256. * @param[out] dest result matrix
  257. */
  258. CGLM_INLINE
  259. void
  260. glm_perspective_default(float aspect, mat4 dest) {
  261. glm_perspective(GLM_PI_4f, aspect, 0.01f, 100.0f, dest);
  262. }
  263. /*!
  264. * @brief resize perspective matrix by aspect ratio ( width / height )
  265. * this makes very easy to resize proj matrix when window /viewport
  266. * reized
  267. *
  268. * @param[in] aspect aspect ratio ( width / height )
  269. * @param[in, out] proj perspective projection matrix
  270. */
  271. CGLM_INLINE
  272. void
  273. glm_perspective_resize(float aspect, mat4 proj) {
  274. if (proj[0][0] == 0.0f)
  275. return;
  276. proj[0][0] = proj[1][1] / aspect;
  277. }
  278. /*!
  279. * @brief set up view matrix
  280. *
  281. * NOTE: The UP vector must not be parallel to the line of sight from
  282. * the eye point to the reference point
  283. *
  284. * @param[in] eye eye vector
  285. * @param[in] center center vector
  286. * @param[in] up up vector
  287. * @param[out] dest result matrix
  288. */
  289. CGLM_INLINE
  290. void
  291. glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest) {
  292. CGLM_ALIGN(8) vec3 f, u, s;
  293. glm_vec3_sub(center, eye, f);
  294. glm_vec3_normalize(f);
  295. glm_vec3_crossn(f, up, s);
  296. glm_vec3_cross(s, f, u);
  297. dest[0][0] = s[0];
  298. dest[0][1] = u[0];
  299. dest[0][2] =-f[0];
  300. dest[1][0] = s[1];
  301. dest[1][1] = u[1];
  302. dest[1][2] =-f[1];
  303. dest[2][0] = s[2];
  304. dest[2][1] = u[2];
  305. dest[2][2] =-f[2];
  306. dest[3][0] =-glm_vec3_dot(s, eye);
  307. dest[3][1] =-glm_vec3_dot(u, eye);
  308. dest[3][2] = glm_vec3_dot(f, eye);
  309. dest[0][3] = dest[1][3] = dest[2][3] = 0.0f;
  310. dest[3][3] = 1.0f;
  311. }
  312. /*!
  313. * @brief set up view matrix
  314. *
  315. * convenient wrapper for lookat: if you only have direction not target self
  316. * then this might be useful. Because you need to get target from direction.
  317. *
  318. * NOTE: The UP vector must not be parallel to the line of sight from
  319. * the eye point to the reference point
  320. *
  321. * @param[in] eye eye vector
  322. * @param[in] dir direction vector
  323. * @param[in] up up vector
  324. * @param[out] dest result matrix
  325. */
  326. CGLM_INLINE
  327. void
  328. glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest) {
  329. CGLM_ALIGN(8) vec3 target;
  330. glm_vec3_add(eye, dir, target);
  331. glm_lookat(eye, target, up, dest);
  332. }
  333. /*!
  334. * @brief set up view matrix
  335. *
  336. * convenient wrapper for look: if you only have direction and if you don't
  337. * care what UP vector is then this might be useful to create view matrix
  338. *
  339. * @param[in] eye eye vector
  340. * @param[in] dir direction vector
  341. * @param[out] dest result matrix
  342. */
  343. CGLM_INLINE
  344. void
  345. glm_look_anyup(vec3 eye, vec3 dir, mat4 dest) {
  346. CGLM_ALIGN(8) vec3 up;
  347. glm_vec3_ortho(dir, up);
  348. glm_look(eye, dir, up, dest);
  349. }
  350. /*!
  351. * @brief decomposes frustum values of perspective projection.
  352. *
  353. * @param[in] proj perspective projection matrix
  354. * @param[out] nearVal near
  355. * @param[out] farVal far
  356. * @param[out] top top
  357. * @param[out] bottom bottom
  358. * @param[out] left left
  359. * @param[out] right right
  360. */
  361. CGLM_INLINE
  362. void
  363. glm_persp_decomp(mat4 proj,
  364. float * __restrict nearVal, float * __restrict farVal,
  365. float * __restrict top, float * __restrict bottom,
  366. float * __restrict left, float * __restrict right) {
  367. float m00, m11, m20, m21, m22, m32, n, f;
  368. float n_m11, n_m00;
  369. m00 = proj[0][0];
  370. m11 = proj[1][1];
  371. m20 = proj[2][0];
  372. m21 = proj[2][1];
  373. m22 = proj[2][2];
  374. m32 = proj[3][2];
  375. n = m32 / (m22 - 1.0f);
  376. f = m32 / (m22 + 1.0f);
  377. n_m11 = n / m11;
  378. n_m00 = n / m00;
  379. *nearVal = n;
  380. *farVal = f;
  381. *bottom = n_m11 * (m21 - 1.0f);
  382. *top = n_m11 * (m21 + 1.0f);
  383. *left = n_m00 * (m20 - 1.0f);
  384. *right = n_m00 * (m20 + 1.0f);
  385. }
  386. /*!
  387. * @brief decomposes frustum values of perspective projection.
  388. * this makes easy to get all values at once
  389. *
  390. * @param[in] proj perspective projection matrix
  391. * @param[out] dest array
  392. */
  393. CGLM_INLINE
  394. void
  395. glm_persp_decompv(mat4 proj, float dest[6]) {
  396. glm_persp_decomp(proj, &dest[0], &dest[1], &dest[2],
  397. &dest[3], &dest[4], &dest[5]);
  398. }
  399. /*!
  400. * @brief decomposes left and right values of perspective projection.
  401. * x stands for x axis (left / right axis)
  402. *
  403. * @param[in] proj perspective projection matrix
  404. * @param[out] left left
  405. * @param[out] right right
  406. */
  407. CGLM_INLINE
  408. void
  409. glm_persp_decomp_x(mat4 proj,
  410. float * __restrict left,
  411. float * __restrict right) {
  412. float nearVal, m20, m00;
  413. m00 = proj[0][0];
  414. m20 = proj[2][0];
  415. nearVal = proj[3][2] / (proj[3][3] - 1.0f);
  416. *left = nearVal * (m20 - 1.0f) / m00;
  417. *right = nearVal * (m20 + 1.0f) / m00;
  418. }
  419. /*!
  420. * @brief decomposes top and bottom values of perspective projection.
  421. * y stands for y axis (top / botom axis)
  422. *
  423. * @param[in] proj perspective projection matrix
  424. * @param[out] top top
  425. * @param[out] bottom bottom
  426. */
  427. CGLM_INLINE
  428. void
  429. glm_persp_decomp_y(mat4 proj,
  430. float * __restrict top,
  431. float * __restrict bottom) {
  432. float nearVal, m21, m11;
  433. m21 = proj[2][1];
  434. m11 = proj[1][1];
  435. nearVal = proj[3][2] / (proj[3][3] - 1.0f);
  436. *bottom = nearVal * (m21 - 1) / m11;
  437. *top = nearVal * (m21 + 1) / m11;
  438. }
  439. /*!
  440. * @brief decomposes near and far values of perspective projection.
  441. * z stands for z axis (near / far axis)
  442. *
  443. * @param[in] proj perspective projection matrix
  444. * @param[out] nearVal near
  445. * @param[out] farVal far
  446. */
  447. CGLM_INLINE
  448. void
  449. glm_persp_decomp_z(mat4 proj,
  450. float * __restrict nearVal,
  451. float * __restrict farVal) {
  452. float m32, m22;
  453. m32 = proj[3][2];
  454. m22 = proj[2][2];
  455. *nearVal = m32 / (m22 - 1.0f);
  456. *farVal = m32 / (m22 + 1.0f);
  457. }
  458. /*!
  459. * @brief decomposes far value of perspective projection.
  460. *
  461. * @param[in] proj perspective projection matrix
  462. * @param[out] farVal far
  463. */
  464. CGLM_INLINE
  465. void
  466. glm_persp_decomp_far(mat4 proj, float * __restrict farVal) {
  467. *farVal = proj[3][2] / (proj[2][2] + 1.0f);
  468. }
  469. /*!
  470. * @brief decomposes near value of perspective projection.
  471. *
  472. * @param[in] proj perspective projection matrix
  473. * @param[out] nearVal near
  474. */
  475. CGLM_INLINE
  476. void
  477. glm_persp_decomp_near(mat4 proj, float * __restrict nearVal) {
  478. *nearVal = proj[3][2] / (proj[2][2] - 1.0f);
  479. }
  480. /*!
  481. * @brief returns field of view angle along the Y-axis (in radians)
  482. *
  483. * if you need to degrees, use glm_deg to convert it or use this:
  484. * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
  485. *
  486. * @param[in] proj perspective projection matrix
  487. */
  488. CGLM_INLINE
  489. float
  490. glm_persp_fovy(mat4 proj) {
  491. return 2.0f * atanf(1.0f / proj[1][1]);
  492. }
  493. /*!
  494. * @brief returns aspect ratio of perspective projection
  495. *
  496. * @param[in] proj perspective projection matrix
  497. */
  498. CGLM_INLINE
  499. float
  500. glm_persp_aspect(mat4 proj) {
  501. return proj[1][1] / proj[0][0];
  502. }
  503. /*!
  504. * @brief returns sizes of near and far planes of perspective projection
  505. *
  506. * @param[in] proj perspective projection matrix
  507. * @param[in] fovy fovy (see brief)
  508. * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar]
  509. */
  510. CGLM_INLINE
  511. void
  512. glm_persp_sizes(mat4 proj, float fovy, vec4 dest) {
  513. float t, a, nearVal, farVal;
  514. t = 2.0f * tanf(fovy * 0.5f);
  515. a = glm_persp_aspect(proj);
  516. glm_persp_decomp_z(proj, &nearVal, &farVal);
  517. dest[1] = t * nearVal;
  518. dest[3] = t * farVal;
  519. dest[0] = a * dest[1];
  520. dest[2] = a * dest[3];
  521. }
  522. #endif /* cglm_vcam_h */