1
0

frustum.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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. #ifndef cglm_frustum_h
  8. #define cglm_frustum_h
  9. #include "common.h"
  10. #include "plane.h"
  11. #include "vec3.h"
  12. #include "vec4.h"
  13. #include "mat4.h"
  14. #define GLM_LBN 0 /* left bottom near */
  15. #define GLM_LTN 1 /* left top near */
  16. #define GLM_RTN 2 /* right top near */
  17. #define GLM_RBN 3 /* right bottom near */
  18. #define GLM_LBF 4 /* left bottom far */
  19. #define GLM_LTF 5 /* left top far */
  20. #define GLM_RTF 6 /* right top far */
  21. #define GLM_RBF 7 /* right bottom far */
  22. #define GLM_LEFT 0
  23. #define GLM_RIGHT 1
  24. #define GLM_BOTTOM 2
  25. #define GLM_TOP 3
  26. #define GLM_NEAR 4
  27. #define GLM_FAR 5
  28. /* you can override clip space coords
  29. but you have to provide all with same name
  30. e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */
  31. #ifndef GLM_CUSTOM_CLIPSPACE
  32. /* near */
  33. #define GLM_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f}
  34. #define GLM_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f}
  35. #define GLM_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f}
  36. #define GLM_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f}
  37. /* far */
  38. #define GLM_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f}
  39. #define GLM_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f}
  40. #define GLM_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f}
  41. #define GLM_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f}
  42. #endif
  43. /*!
  44. * @brief extracts view frustum planes
  45. *
  46. * planes' space:
  47. * 1- if m = proj: View Space
  48. * 2- if m = viewProj: World Space
  49. * 3- if m = MVP: Object Space
  50. *
  51. * You probably want to extract planes in world space so use viewProj as m
  52. * Computing viewProj:
  53. * glm_mat4_mul(proj, view, viewProj);
  54. *
  55. * Exracted planes order: [left, right, bottom, top, near, far]
  56. *
  57. * @param[in] m matrix (see brief)
  58. * @param[out] dest extracted view frustum planes (see brief)
  59. */
  60. CGLM_INLINE
  61. void
  62. glm_frustum_planes(mat4 m, vec4 dest[6]) {
  63. mat4 t;
  64. glm_mat4_transpose_to(m, t);
  65. glm_vec4_add(t[3], t[0], dest[0]); /* left */
  66. glm_vec4_sub(t[3], t[0], dest[1]); /* right */
  67. glm_vec4_add(t[3], t[1], dest[2]); /* bottom */
  68. glm_vec4_sub(t[3], t[1], dest[3]); /* top */
  69. glm_vec4_add(t[3], t[2], dest[4]); /* near */
  70. glm_vec4_sub(t[3], t[2], dest[5]); /* far */
  71. glm_plane_normalize(dest[0]);
  72. glm_plane_normalize(dest[1]);
  73. glm_plane_normalize(dest[2]);
  74. glm_plane_normalize(dest[3]);
  75. glm_plane_normalize(dest[4]);
  76. glm_plane_normalize(dest[5]);
  77. }
  78. /*!
  79. * @brief extracts view frustum corners using clip-space coordinates
  80. *
  81. * corners' space:
  82. * 1- if m = invViewProj: World Space
  83. * 2- if m = invMVP: Object Space
  84. *
  85. * You probably want to extract corners in world space so use invViewProj
  86. * Computing invViewProj:
  87. * glm_mat4_mul(proj, view, viewProj);
  88. * ...
  89. * glm_mat4_inv(viewProj, invViewProj);
  90. *
  91. * if you have a near coord at i index, you can get it's far coord by i + 4
  92. *
  93. * Find center coordinates:
  94. * for (j = 0; j < 4; j++) {
  95. * glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]);
  96. * }
  97. *
  98. * @param[in] invMat matrix (see brief)
  99. * @param[out] dest exracted view frustum corners (see brief)
  100. */
  101. CGLM_INLINE
  102. void
  103. glm_frustum_corners(mat4 invMat, vec4 dest[8]) {
  104. vec4 c[8];
  105. /* indexOf(nearCoord) = indexOf(farCoord) + 4 */
  106. vec4 csCoords[8] = {
  107. GLM_CSCOORD_LBN,
  108. GLM_CSCOORD_LTN,
  109. GLM_CSCOORD_RTN,
  110. GLM_CSCOORD_RBN,
  111. GLM_CSCOORD_LBF,
  112. GLM_CSCOORD_LTF,
  113. GLM_CSCOORD_RTF,
  114. GLM_CSCOORD_RBF
  115. };
  116. glm_mat4_mulv(invMat, csCoords[0], c[0]);
  117. glm_mat4_mulv(invMat, csCoords[1], c[1]);
  118. glm_mat4_mulv(invMat, csCoords[2], c[2]);
  119. glm_mat4_mulv(invMat, csCoords[3], c[3]);
  120. glm_mat4_mulv(invMat, csCoords[4], c[4]);
  121. glm_mat4_mulv(invMat, csCoords[5], c[5]);
  122. glm_mat4_mulv(invMat, csCoords[6], c[6]);
  123. glm_mat4_mulv(invMat, csCoords[7], c[7]);
  124. glm_vec4_scale(c[0], 1.0f / c[0][3], dest[0]);
  125. glm_vec4_scale(c[1], 1.0f / c[1][3], dest[1]);
  126. glm_vec4_scale(c[2], 1.0f / c[2][3], dest[2]);
  127. glm_vec4_scale(c[3], 1.0f / c[3][3], dest[3]);
  128. glm_vec4_scale(c[4], 1.0f / c[4][3], dest[4]);
  129. glm_vec4_scale(c[5], 1.0f / c[5][3], dest[5]);
  130. glm_vec4_scale(c[6], 1.0f / c[6][3], dest[6]);
  131. glm_vec4_scale(c[7], 1.0f / c[7][3], dest[7]);
  132. }
  133. /*!
  134. * @brief finds center of view frustum
  135. *
  136. * @param[in] corners view frustum corners
  137. * @param[out] dest view frustum center
  138. */
  139. CGLM_INLINE
  140. void
  141. glm_frustum_center(vec4 corners[8], vec4 dest) {
  142. vec4 center;
  143. glm_vec4_copy(corners[0], center);
  144. glm_vec4_add(corners[1], center, center);
  145. glm_vec4_add(corners[2], center, center);
  146. glm_vec4_add(corners[3], center, center);
  147. glm_vec4_add(corners[4], center, center);
  148. glm_vec4_add(corners[5], center, center);
  149. glm_vec4_add(corners[6], center, center);
  150. glm_vec4_add(corners[7], center, center);
  151. glm_vec4_scale(center, 0.125f, dest);
  152. }
  153. /*!
  154. * @brief finds bounding box of frustum relative to given matrix e.g. view mat
  155. *
  156. * @param[in] corners view frustum corners
  157. * @param[in] m matrix to convert existing conners
  158. * @param[out] box bounding box as array [min, max]
  159. */
  160. CGLM_INLINE
  161. void
  162. glm_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]) {
  163. vec4 v;
  164. vec3 min, max;
  165. int i;
  166. glm_vec3_broadcast(FLT_MAX, min);
  167. glm_vec3_broadcast(-FLT_MAX, max);
  168. for (i = 0; i < 8; i++) {
  169. glm_mat4_mulv(m, corners[i], v);
  170. min[0] = glm_min(min[0], v[0]);
  171. min[1] = glm_min(min[1], v[1]);
  172. min[2] = glm_min(min[2], v[2]);
  173. max[0] = glm_max(max[0], v[0]);
  174. max[1] = glm_max(max[1], v[1]);
  175. max[2] = glm_max(max[2], v[2]);
  176. }
  177. glm_vec3_copy(min, box[0]);
  178. glm_vec3_copy(max, box[1]);
  179. }
  180. /*!
  181. * @brief finds planes corners which is between near and far planes (parallel)
  182. *
  183. * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will
  184. * find planes' corners but you will need to one more plane.
  185. * Actually you have it, it is near, far or created previously with this func ;)
  186. *
  187. * @param[in] corners view frustum corners
  188. * @param[in] splitDist split distance
  189. * @param[in] farDist far distance (zFar)
  190. * @param[out] planeCorners plane corners [LB, LT, RT, RB]
  191. */
  192. CGLM_INLINE
  193. void
  194. glm_frustum_corners_at(vec4 corners[8],
  195. float splitDist,
  196. float farDist,
  197. vec4 planeCorners[4]) {
  198. vec4 corner;
  199. float dist, sc;
  200. /* because distance and scale is same for all */
  201. dist = glm_vec3_distance(corners[GLM_RTF], corners[GLM_RTN]);
  202. sc = dist * (splitDist / farDist);
  203. /* left bottom */
  204. glm_vec4_sub(corners[GLM_LBF], corners[GLM_LBN], corner);
  205. glm_vec4_scale_as(corner, sc, corner);
  206. glm_vec4_add(corners[GLM_LBN], corner, planeCorners[0]);
  207. /* left top */
  208. glm_vec4_sub(corners[GLM_LTF], corners[GLM_LTN], corner);
  209. glm_vec4_scale_as(corner, sc, corner);
  210. glm_vec4_add(corners[GLM_LTN], corner, planeCorners[1]);
  211. /* right top */
  212. glm_vec4_sub(corners[GLM_RTF], corners[GLM_RTN], corner);
  213. glm_vec4_scale_as(corner, sc, corner);
  214. glm_vec4_add(corners[GLM_RTN], corner, planeCorners[2]);
  215. /* right bottom */
  216. glm_vec4_sub(corners[GLM_RBF], corners[GLM_RBN], corner);
  217. glm_vec4_scale_as(corner, sc, corner);
  218. glm_vec4_add(corners[GLM_RBN], corner, planeCorners[3]);
  219. }
  220. #endif /* cglm_frustum_h */