| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- /*
- * Copyright (c), Recep Aslantas.
- *
- * MIT License (MIT), http://opensource.org/licenses/MIT
- * Full license can be found in the LICENSE file
- */
- #ifndef cglm_frustum_h
- #define cglm_frustum_h
- #include "common.h"
- #include "plane.h"
- #include "vec3.h"
- #include "vec4.h"
- #include "mat4.h"
- #define GLM_LBN 0 /* left bottom near */
- #define GLM_LTN 1 /* left top near */
- #define GLM_RTN 2 /* right top near */
- #define GLM_RBN 3 /* right bottom near */
- #define GLM_LBF 4 /* left bottom far */
- #define GLM_LTF 5 /* left top far */
- #define GLM_RTF 6 /* right top far */
- #define GLM_RBF 7 /* right bottom far */
- #define GLM_LEFT 0
- #define GLM_RIGHT 1
- #define GLM_BOTTOM 2
- #define GLM_TOP 3
- #define GLM_NEAR 4
- #define GLM_FAR 5
- /* you can override clip space coords
- but you have to provide all with same name
- e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */
- #ifndef GLM_CUSTOM_CLIPSPACE
- /* near */
- #define GLM_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f}
- #define GLM_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f}
- #define GLM_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f}
- #define GLM_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f}
- /* far */
- #define GLM_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f}
- #define GLM_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f}
- #define GLM_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f}
- #define GLM_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f}
- #endif
- /*!
- * @brief extracts view frustum planes
- *
- * planes' space:
- * 1- if m = proj: View Space
- * 2- if m = viewProj: World Space
- * 3- if m = MVP: Object Space
- *
- * You probably want to extract planes in world space so use viewProj as m
- * Computing viewProj:
- * glm_mat4_mul(proj, view, viewProj);
- *
- * Exracted planes order: [left, right, bottom, top, near, far]
- *
- * @param[in] m matrix (see brief)
- * @param[out] dest extracted view frustum planes (see brief)
- */
- CGLM_INLINE
- void
- glm_frustum_planes(mat4 m, vec4 dest[6]) {
- mat4 t;
- glm_mat4_transpose_to(m, t);
- glm_vec4_add(t[3], t[0], dest[0]); /* left */
- glm_vec4_sub(t[3], t[0], dest[1]); /* right */
- glm_vec4_add(t[3], t[1], dest[2]); /* bottom */
- glm_vec4_sub(t[3], t[1], dest[3]); /* top */
- glm_vec4_add(t[3], t[2], dest[4]); /* near */
- glm_vec4_sub(t[3], t[2], dest[5]); /* far */
- glm_plane_normalize(dest[0]);
- glm_plane_normalize(dest[1]);
- glm_plane_normalize(dest[2]);
- glm_plane_normalize(dest[3]);
- glm_plane_normalize(dest[4]);
- glm_plane_normalize(dest[5]);
- }
- /*!
- * @brief extracts view frustum corners using clip-space coordinates
- *
- * corners' space:
- * 1- if m = invViewProj: World Space
- * 2- if m = invMVP: Object Space
- *
- * You probably want to extract corners in world space so use invViewProj
- * Computing invViewProj:
- * glm_mat4_mul(proj, view, viewProj);
- * ...
- * glm_mat4_inv(viewProj, invViewProj);
- *
- * if you have a near coord at i index, you can get it's far coord by i + 4
- *
- * Find center coordinates:
- * for (j = 0; j < 4; j++) {
- * glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]);
- * }
- *
- * @param[in] invMat matrix (see brief)
- * @param[out] dest exracted view frustum corners (see brief)
- */
- CGLM_INLINE
- void
- glm_frustum_corners(mat4 invMat, vec4 dest[8]) {
- vec4 c[8];
- /* indexOf(nearCoord) = indexOf(farCoord) + 4 */
- vec4 csCoords[8] = {
- GLM_CSCOORD_LBN,
- GLM_CSCOORD_LTN,
- GLM_CSCOORD_RTN,
- GLM_CSCOORD_RBN,
- GLM_CSCOORD_LBF,
- GLM_CSCOORD_LTF,
- GLM_CSCOORD_RTF,
- GLM_CSCOORD_RBF
- };
- glm_mat4_mulv(invMat, csCoords[0], c[0]);
- glm_mat4_mulv(invMat, csCoords[1], c[1]);
- glm_mat4_mulv(invMat, csCoords[2], c[2]);
- glm_mat4_mulv(invMat, csCoords[3], c[3]);
- glm_mat4_mulv(invMat, csCoords[4], c[4]);
- glm_mat4_mulv(invMat, csCoords[5], c[5]);
- glm_mat4_mulv(invMat, csCoords[6], c[6]);
- glm_mat4_mulv(invMat, csCoords[7], c[7]);
- glm_vec4_scale(c[0], 1.0f / c[0][3], dest[0]);
- glm_vec4_scale(c[1], 1.0f / c[1][3], dest[1]);
- glm_vec4_scale(c[2], 1.0f / c[2][3], dest[2]);
- glm_vec4_scale(c[3], 1.0f / c[3][3], dest[3]);
- glm_vec4_scale(c[4], 1.0f / c[4][3], dest[4]);
- glm_vec4_scale(c[5], 1.0f / c[5][3], dest[5]);
- glm_vec4_scale(c[6], 1.0f / c[6][3], dest[6]);
- glm_vec4_scale(c[7], 1.0f / c[7][3], dest[7]);
- }
- /*!
- * @brief finds center of view frustum
- *
- * @param[in] corners view frustum corners
- * @param[out] dest view frustum center
- */
- CGLM_INLINE
- void
- glm_frustum_center(vec4 corners[8], vec4 dest) {
- vec4 center;
- glm_vec4_copy(corners[0], center);
- glm_vec4_add(corners[1], center, center);
- glm_vec4_add(corners[2], center, center);
- glm_vec4_add(corners[3], center, center);
- glm_vec4_add(corners[4], center, center);
- glm_vec4_add(corners[5], center, center);
- glm_vec4_add(corners[6], center, center);
- glm_vec4_add(corners[7], center, center);
- glm_vec4_scale(center, 0.125f, dest);
- }
- /*!
- * @brief finds bounding box of frustum relative to given matrix e.g. view mat
- *
- * @param[in] corners view frustum corners
- * @param[in] m matrix to convert existing conners
- * @param[out] box bounding box as array [min, max]
- */
- CGLM_INLINE
- void
- glm_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]) {
- vec4 v;
- vec3 min, max;
- int i;
- glm_vec3_broadcast(FLT_MAX, min);
- glm_vec3_broadcast(-FLT_MAX, max);
- for (i = 0; i < 8; i++) {
- glm_mat4_mulv(m, corners[i], v);
- min[0] = glm_min(min[0], v[0]);
- min[1] = glm_min(min[1], v[1]);
- min[2] = glm_min(min[2], v[2]);
- max[0] = glm_max(max[0], v[0]);
- max[1] = glm_max(max[1], v[1]);
- max[2] = glm_max(max[2], v[2]);
- }
- glm_vec3_copy(min, box[0]);
- glm_vec3_copy(max, box[1]);
- }
- /*!
- * @brief finds planes corners which is between near and far planes (parallel)
- *
- * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will
- * find planes' corners but you will need to one more plane.
- * Actually you have it, it is near, far or created previously with this func ;)
- *
- * @param[in] corners view frustum corners
- * @param[in] splitDist split distance
- * @param[in] farDist far distance (zFar)
- * @param[out] planeCorners plane corners [LB, LT, RT, RB]
- */
- CGLM_INLINE
- void
- glm_frustum_corners_at(vec4 corners[8],
- float splitDist,
- float farDist,
- vec4 planeCorners[4]) {
- vec4 corner;
- float dist, sc;
- /* because distance and scale is same for all */
- dist = glm_vec3_distance(corners[GLM_RTF], corners[GLM_RTN]);
- sc = dist * (splitDist / farDist);
- /* left bottom */
- glm_vec4_sub(corners[GLM_LBF], corners[GLM_LBN], corner);
- glm_vec4_scale_as(corner, sc, corner);
- glm_vec4_add(corners[GLM_LBN], corner, planeCorners[0]);
- /* left top */
- glm_vec4_sub(corners[GLM_LTF], corners[GLM_LTN], corner);
- glm_vec4_scale_as(corner, sc, corner);
- glm_vec4_add(corners[GLM_LTN], corner, planeCorners[1]);
- /* right top */
- glm_vec4_sub(corners[GLM_RTF], corners[GLM_RTN], corner);
- glm_vec4_scale_as(corner, sc, corner);
- glm_vec4_add(corners[GLM_RTN], corner, planeCorners[2]);
- /* right bottom */
- glm_vec4_sub(corners[GLM_RBF], corners[GLM_RBN], corner);
- glm_vec4_scale_as(corner, sc, corner);
- glm_vec4_add(corners[GLM_RBN], corner, planeCorners[3]);
- }
- #endif /* cglm_frustum_h */
|