diff --git a/LICENSE b/LICENSE index f22658b..2367e77 100644 --- a/LICENSE +++ b/LICENSE @@ -52,3 +52,9 @@ LICENSE: Computing Euler angles from a rotation matrix (euler.pdf) Gregory G. Slabaugh + +4. Extracting Planes +Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix +Authors: + Gil Gribb (ggribb@ravensoft.com) + Klaus Hartmann (k_hartmann@osnabrueck.netsurf.de) diff --git a/README.md b/README.md index c90f6ea..3e6964a 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ https://github.com/g-truc/glm - euler angles / yaw-pitch-roll to matrix - extract euler angles - inline or pre-compiled function call +- extract view frustum planes
diff --git a/include/cglm/call.h b/include/cglm/call.h index 2b8025a..c306ab9 100644 --- a/include/cglm/call.h +++ b/include/cglm/call.h @@ -20,6 +20,7 @@ extern "C" { #include "call/cam.h" #include "call/quat.h" #include "call/euler.h" +#include "call/plane.h" #include "call/io.h" #ifdef __cplusplus diff --git a/include/cglm/call/cam.h b/include/cglm/call/cam.h index 03e066a..7b2c409 100644 --- a/include/cglm/call/cam.h +++ b/include/cglm/call/cam.h @@ -48,6 +48,18 @@ glmc_lookat(vec3 eye, vec3 up, mat4 dest); +CGLM_EXPORT +void +glmc_frustum_planes(mat4 m, vec4 dest[6]); + +CGLM_EXPORT +void +glmc_frustum_corners(mat4 invMat, vec4 dest[8]); + +CGLM_EXPORT +void +glmc_frustum_center(vec4 corners[8], vec4 dest); + #ifdef __cplusplus } #endif diff --git a/include/cglm/call/plane.h b/include/cglm/call/plane.h new file mode 100644 index 0000000..f991121 --- /dev/null +++ b/include/cglm/call/plane.h @@ -0,0 +1,23 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_plane_h +#define cglmc_plane_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_plane_normalize(vec4 plane); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_plane_h */ diff --git a/include/cglm/cam.h b/include/cglm/cam.h index a78ba4b..5d39ef2 100644 --- a/include/cglm/cam.h +++ b/include/cglm/cam.h @@ -50,12 +50,15 @@ float * __restrict farVal); CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float * __restrict farVal); CGLM_INLINE void glm_persp_decomp_near(mat4 proj, float *__restrict nearVal); + CGLM_INLINE void glm_frustum_planes(mat4 m, vec4 dest[6]); + CGLM_INLINE void glm_frustum_corners(mat4 invMat, vec4 dest[8]); */ #ifndef cglm_vcam_h #define cglm_vcam_h #include "common.h" +#include "plane.h" /*! * @brief set up perspective peprojection matrix @@ -422,4 +425,117 @@ void glm_persp_decomp_near(mat4 proj, float * __restrict nearVal) { *nearVal = proj[3][2] / (proj[2][2] - 1); } + +/*! + * @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 exracted 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); + * + * @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]; + vec4 ndcCorners[8] = { + {-1.0f, -1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, -1.0f, 1.0f}, + { 1.0f, -1.0f, -1.0f, 1.0f}, + { 1.0f, 1.0f, -1.0f, 1.0f}, + {-1.0f, -1.0f, 1.0f, 1.0f}, + {-1.0f, 1.0f, 1.0f, 1.0f}, + { 1.0f, -1.0f, 1.0f, 1.0f}, + { 1.0f, 1.0f, 1.0f, 1.0f} + }; + + glm_mat4_mulv(invMat, ndcCorners[0], c[0]); + glm_mat4_mulv(invMat, ndcCorners[1], c[1]); + glm_mat4_mulv(invMat, ndcCorners[2], c[2]); + glm_mat4_mulv(invMat, ndcCorners[3], c[3]); + glm_mat4_mulv(invMat, ndcCorners[4], c[4]); + glm_mat4_mulv(invMat, ndcCorners[5], c[5]); + glm_mat4_mulv(invMat, ndcCorners[6], c[6]); + glm_mat4_mulv(invMat, ndcCorners[7], c[7]); + + 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); +} + #endif /* cglm_vcam_h */ diff --git a/include/cglm/cglm.h b/include/cglm/cglm.h index 1dabb70..24544d1 100644 --- a/include/cglm/cglm.h +++ b/include/cglm/cglm.h @@ -17,6 +17,7 @@ #include "cam.h" #include "quat.h" #include "euler.h" +#include "plane.h" #include "util.h" #include "io.h" diff --git a/include/cglm/plane.h b/include/cglm/plane.h new file mode 100644 index 0000000..9faac9c --- /dev/null +++ b/include/cglm/plane.h @@ -0,0 +1,38 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_plane_h +#define cglm_plane_h + +#include "common.h" +#include "mat4.h" +#include "vec4.h" +#include "vec3.h" + +/* + Plane equation: Ax + By + Cz + D = 0; + + It stored in vec4 as [A, B, C, D]. (A, B, C) is normal and D is distance +*/ + +/* + Functions: + CGLM_INLINE void glm_plane_normalize(vec4 plane); + */ + +/*! + * @brief normalizes a plane + * + * @param[in, out] plane pnale to normalize + */ +CGLM_INLINE +void +glm_plane_normalize(vec4 plane) { + glm_vec4_scale(plane, 1.0f / glm_vec_norm(plane), plane); +} + +#endif /* cglm_plane_h */ diff --git a/include/cglm/util.h b/include/cglm/util.h index d1b62a2..6b97648 100644 --- a/include/cglm/util.h +++ b/include/cglm/util.h @@ -61,4 +61,20 @@ glm_pow2(float x) { return x * x; } +CGLM_INLINE +float +glm_min(float a, float b) { + if (a < b) + return a; + return b; +} + +CGLM_INLINE +float +glm_max(float a, float b) { + if (a > b) + return a; + return b; +} + #endif /* cglm_util_h */ diff --git a/include/cglm/vec4-ext.h b/include/cglm/vec4-ext.h index 6410e41..ca697af 100644 --- a/include/cglm/vec4-ext.h +++ b/include/cglm/vec4-ext.h @@ -17,7 +17,7 @@ CGLM_INLINE bool glm_vec4_eq_eps(vec4 v, float val); CGLM_INLINE bool glm_vec4_eq_all(vec4 v); CGLM_INLINE bool glm_vec4_eqv(vec4 v1, vec4 v2); - CGLM_INLINE bool glm_vec4_eqv_eps(vec3 v1, vec3 v2); + CGLM_INLINE bool glm_vec4_eqv_eps(vec4 v1, vec4 v2); CGLM_INLINE float glm_vec4_max(vec4 v); CGLM_INLINE float glm_vec4_min(vec4 v); */ @@ -133,7 +133,7 @@ glm_vec4_eqv(vec4 v1, vec4 v2) { */ CGLM_INLINE bool -glm_vec4_eqv_eps(vec3 v1, vec3 v2) { +glm_vec4_eqv_eps(vec4 v1, vec4 v2) { return fabsf(v1[0] - v2[0]) <= FLT_EPSILON && fabsf(v1[1] - v2[1]) <= FLT_EPSILON && fabsf(v1[2] - v2[2]) <= FLT_EPSILON diff --git a/src/cam.c b/src/cam.c index 0dcdc4b..602b1fc 100644 --- a/src/cam.c +++ b/src/cam.c @@ -66,3 +66,21 @@ glmc_lookat(vec3 eye, mat4 dest) { glm_lookat(eye, center, up, dest); } + +CGLM_EXPORT +void +glmc_frustum_planes(mat4 m, vec4 dest[6]) { + glm_frustum_planes(m, dest); +} + +CGLM_EXPORT +void +glmc_frustum_corners(mat4 invMat, vec4 dest[8]) { + glm_frustum_corners(invMat, dest); +} + +CGLM_EXPORT +void +glmc_frustum_center(vec4 corners[8], vec4 dest) { + glm_frustum_center(corners, dest); +} diff --git a/src/plane.c b/src/plane.c new file mode 100644 index 0000000..7ee0c0f --- /dev/null +++ b/src/plane.c @@ -0,0 +1,15 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#include "../include/cglm/cglm.h" +#include "../include/cglm/call.h" + +CGLM_EXPORT +void +glmc_plane_normalize(vec4 plane) { + glm_plane_normalize(plane); +}