diff --git a/include/cglm/call/vec2.h b/include/cglm/call/vec2.h index 96f4bd6..bb6e629 100644 --- a/include/cglm/call/vec2.h +++ b/include/cglm/call/vec2.h @@ -201,6 +201,10 @@ CGLM_EXPORT void glmc_vec2_reflect(vec2 I, vec2 N, vec2 dest); +CGLM_EXPORT +void +glmc_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest); + #ifdef __cplusplus } #endif diff --git a/include/cglm/call/vec3.h b/include/cglm/call/vec3.h index 5fec1ed..b24529c 100644 --- a/include/cglm/call/vec3.h +++ b/include/cglm/call/vec3.h @@ -334,13 +334,17 @@ CGLM_EXPORT void glmc_vec3_make(const float * __restrict src, vec3 dest); +CGLM_EXPORT +void +glmc_vec3_faceforward(vec3 N, vec3 I, vec3 Nref, vec3 dest); + CGLM_EXPORT void glmc_vec3_reflect(vec3 I, vec3 N, vec3 dest); CGLM_EXPORT void -glmc_vec3_faceforward(vec3 N, vec3 I, vec3 Nref, vec3 dest); +glmc_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest); #ifdef __cplusplus } diff --git a/include/cglm/call/vec4.h b/include/cglm/call/vec4.h index 1e6639b..207bc79 100644 --- a/include/cglm/call/vec4.h +++ b/include/cglm/call/vec4.h @@ -315,6 +315,10 @@ CGLM_EXPORT void glmc_vec4_reflect(vec4 I, vec4 N, vec4 dest); +CGLM_EXPORT +void +glmc_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest); + #ifdef __cplusplus } #endif diff --git a/include/cglm/struct/vec2.h b/include/cglm/struct/vec2.h index ca31153..7a48bce 100644 --- a/include/cglm/struct/vec2.h +++ b/include/cglm/struct/vec2.h @@ -55,6 +55,7 @@ CGLM_INLINE vec2s glms_vec2_lerp(vec2s from, vec2s to, float t) CGLM_INLINE vec2s glms_vec2_make(float * restrict src) CGLM_INLINE vec2s glms_vec2_reflect(vec2s I, vec2s N) + CGLM_INLINE vec2s glms_vec2_refract(vec2s I, vec2s N, float eta) */ #ifndef cglms_vec2s_h @@ -707,4 +708,23 @@ glms_vec2_(reflect)(vec2s I, vec2s N) { return dest; } +/*! + * @brief refraction vector using entering ray, surface normal and refraction index + * + * if the angle between the entering ray I and the surface normal N is too great + * for a given refraction index, the return value is zero + * + * @param[in] I normalized incident vector + * @param[in] N normalized normal vector + * @param[in] eta ratio of indices of refraction + * @param[out] dest refraction result + */ +CGLM_INLINE +vec2s +glms_vec2_(refract)(vec2s I, vec2s N, float eta) { + vec2s dest; + glm_vec2_refract(I.raw, N.raw, eta, dest.raw); + return dest; +} + #endif /* cglms_vec2s_h */ diff --git a/include/cglm/struct/vec3.h b/include/cglm/struct/vec3.h index 95cbcc3..3be4099 100644 --- a/include/cglm/struct/vec3.h +++ b/include/cglm/struct/vec3.h @@ -76,8 +76,9 @@ CGLM_INLINE vec3s glms_vec3_smoothinterpc(vec3s from, vec3s to, float t); CGLM_INLINE vec3s glms_vec3_swizzle(vec3s v, int mask); CGLM_INLINE vec3s glms_vec3_make(float * restrict src); - CGLM_INLINE vec3s glms_vec3_reflect(vec3s I, vec3s N); CGLM_INLINE vec3s glms_vec3_faceforward(vec3s N, vec3s I, vec3s Nref); + CGLM_INLINE vec3s glms_vec3_reflect(vec3s I, vec3s N); + CGLM_INLINE vec3s glms_vec3_refract(vec3s I, vec3s N, float eta); Convenient: CGLM_INLINE vec3s glms_cross(vec3s a, vec3s b); @@ -1085,6 +1086,24 @@ glms_vec3_(make)(const float * __restrict src) { return dest; } +/*! + * @brief a vector pointing in the same direction as another + * + * orients a vector to point away from a surface as defined by its normal + * + * @param[in] N vector to orient. + * @param[in] I incident vector + * @param[in] Nref reference vector + * @returns oriented vector, pointing away from the surface. + */ +CGLM_INLINE +vec3s +glms_vec3_(faceforward)(vec3s N, vec3s I, vec3s Nref) { + vec3s dest; + glm_vec3_faceforward(N.raw, I.raw, Nref.raw, dest.raw); + return dest; +} + /*! * @brief reflection vector using an incident ray and a surface normal * @@ -1100,11 +1119,22 @@ glms_vec3_(reflect)(vec3s I, vec3s N) { return dest; } +/*! + * @brief refraction vector using entering ray, surface normal and refraction index + * + * if the angle between the entering ray I and the surface normal N is too great + * for a given refraction index, the return value is zero + * + * @param[in] I normalized incident vector + * @param[in] N normalized normal vector + * @param[in] eta ratio of indices of refraction + * @returns refraction result + */ CGLM_INLINE vec3s -glms_vec3_(faceforward)(vec3s N, vec3s I, vec3s Nref) { +glms_vec3_(refract)(vec3s I, vec3s N, float eta) { vec3s dest; - glm_vec3_faceforward(N.raw, I.raw, Nref.raw, dest.raw); + glm_vec3_refract(I.raw, N.raw, eta, dest.raw); return dest; } diff --git a/include/cglm/struct/vec4.h b/include/cglm/struct/vec4.h index 836454d..71e441f 100644 --- a/include/cglm/struct/vec4.h +++ b/include/cglm/struct/vec4.h @@ -68,6 +68,7 @@ CGLM_INLINE vec4s glms_vec4_swizzle(vec4s v, int mask); CGLM_INLINE vec4s glms_vec4_make(float * restrict src); CGLM_INLINE vec4s glms_vec4_reflect(vec4s I, vec4s N); + CGLM_INLINE vec4s glms_vec4_refract(vec4s I, vec4s N, float eta); */ #ifndef cglms_vec4s_h @@ -943,4 +944,27 @@ glms_vec4_(reflect)(vec4s I, vec4s N) { return dest; } +/*! + * @brief refraction vector using entering ray, surface normal and refraction index + * + * if the angle between the entering ray I and the surface normal N is too great + * for a given refraction index, the return value is zero + * + * this implementation does not explicitly preserve the 'w' component of the + * incident vector 'I' in the output 'dest', users requiring the preservation of + * the 'w' component should manually adjust 'dest' after calling this function. + * + * @param[in] I normalized incident vector + * @param[in] N normalized normal vector + * @param[in] eta ratio of indices of refraction + * @returns refraction result + */ +CGLM_INLINE +vec4s +glms_vec4_(refract)(vec4s I, vec4s N, float eta) { + vec4s dest; + glm_vec4_refract(I.raw, N.raw, eta, dest.raw); + return dest; +} + #endif /* cglms_vec4s_h */ diff --git a/include/cglm/vec2.h b/include/cglm/vec2.h index 98e540b..e595070 100644 --- a/include/cglm/vec2.h +++ b/include/cglm/vec2.h @@ -56,6 +56,7 @@ CGLM_INLINE void glm_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest) CGLM_INLINE void glm_vec2_make(float * restrict src, vec2 dest) CGLM_INLINE void glm_vec2_reflect(vec2 I, vec2 N, vec2 dest) + CGLM_INLINE void glm_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest) */ #ifndef cglm_vec2_h @@ -727,4 +728,33 @@ glm_vec2_reflect(vec2 I, vec2 N, vec2 dest) { glm_vec2_sub(I, temp, dest); } +/*! + * @brief refraction vector using entering ray, surface normal and refraction index + * + * if the angle between the entering ray I and the surface normal N is too great + * for a given refraction index, the return value is zero + * + * @param[in] I normalized incident vector + * @param[in] N normalized normal vector + * @param[in] eta ratio of indices of refraction + * @param[out] dest refraction result + */ +CGLM_INLINE +void +glm_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest) { + float ndi, eni, k; + + ndi = glm_vec2_dot(N, I); + eni = eta * ndi; + k = eta * eta + eni * eni; + + if (k > 1.0f) { + glm_vec2_zero(dest); + return; + } + + glm_vec2_scale(I, eta, dest); + glm_vec2_mulsubs(N, eni + sqrt(1.0f - k), dest); +} + #endif /* cglm_vec2_h */ diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h index 79318cf..6c8c455 100644 --- a/include/cglm/vec3.h +++ b/include/cglm/vec3.h @@ -80,9 +80,9 @@ CGLM_INLINE void glm_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest); CGLM_INLINE void glm_vec3_swizzle(vec3 v, int mask, vec3 dest); CGLM_INLINE void glm_vec3_make(float * restrict src, vec3 dest); - CGLM_INLINE void glm_vec3_reflect(vec3 I, vec3 N, vec3 dest); - CGLM_INLINE void glm_vec3_refract(vec3 I, vec3 N, float ior, vec3 dest); CGLM_INLINE void glm_vec3_faceforward(vec3 N, vec3 I, vec3 Nref, vec3 dest); + CGLM_INLINE void glm_vec3_reflect(vec3 I, vec3 N, vec3 dest); + CGLM_INLINE void glm_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest); Convenient: CGLM_INLINE void glm_cross(vec3 a, vec3 b, vec3 d); @@ -1205,6 +1205,28 @@ glm_vec3_make(const float * __restrict src, vec3 dest) { dest[2] = src[2]; } +/*! + * @brief a vector pointing in the same direction as another + * + * orients a vector to point away from a surface as defined by its normal + * + * @param[in] N vector to orient. + * @param[in] I incident vector + * @param[in] Nref reference vector + * @param[out] dest oriented vector, pointing away from the surface. + */ +CGLM_INLINE +void +glm_vec3_faceforward(vec3 N, vec3 I, vec3 Nref, vec3 dest) { + if (glm_vec3_dot(I, Nref) < 0.0f) { + /* N is facing away from I */ + glm_vec3_copy(N, dest); + } else { + /* N is facing towards I, negate it */ + glm_vec3_negate_to(N, dest); + } +} + /*! * @brief reflection vector using an incident ray and a surface normal * @@ -1221,25 +1243,32 @@ glm_vec3_reflect(vec3 I, vec3 N, vec3 dest) { } /*! - * @brief a vector pointing in the same direction as another + * @brief refraction vector using entering ray, surface normal and refraction index * - * orients a vector to point away from a surface as defined by its normal + * if the angle between the entering ray I and the surface normal N is too great + * for a given refraction index, the return value is zero * - * @param[in] N vector to orient. - * @param[in] I incident vector - * @param[in] Nref reference vector - * @param[out] dest oriented vector, pointing away from the surface. + * @param[in] I normalized incident vector + * @param[in] N normalized normal vector + * @param[in] eta ratio of indices of refraction + * @param[out] dest refraction result */ CGLM_INLINE -void -glm_vec3_faceforward(vec3 N, vec3 I, vec3 Nref, vec3 dest) { - if (glm_vec3_dot(I, Nref) < 0.0f) { - /* N is facing away from I */ - glm_vec3_copy(N, dest); - } else { - /* N is facing towards I, negate it */ - glm_vec3_negate_to(N, dest); +void +glm_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest) { + float ndi, eni, k; + + ndi = glm_vec3_dot(N, I); + eni = eta * ndi; + k = eta * eta + eni * eni; + + if (k > 1.0f) { + glm_vec3_zero(dest); + return; } + + glm_vec3_scale(I, eta, dest); + glm_vec3_mulsubs(N, eni + sqrt(1.0f - k), dest); } #endif /* cglm_vec3_h */ diff --git a/include/cglm/vec4.h b/include/cglm/vec4.h index db1bd9c..3c12069 100644 --- a/include/cglm/vec4.h +++ b/include/cglm/vec4.h @@ -66,6 +66,7 @@ CGLM_INLINE void glm_vec4_swizzle(vec4 v, int mask, vec4 dest); CGLM_INLINE void glm_vec4_make(float * restrict src, vec4 dest); CGLM_INLINE void glm_vec4_reflect(vec4 I, vec4 N, vec4 dest); + CGLM_INLINE void glm_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest); DEPRECATED: glm_vec4_dup @@ -1324,4 +1325,37 @@ glm_vec4_reflect(vec4 I, vec4 N, vec4 dest) { dest[3] = I[3]; } +/*! + * @brief refraction vector using entering ray, surface normal and refraction index + * + * if the angle between the entering ray I and the surface normal N is too great + * for a given refraction index, the return value is zero + * + * this implementation does not explicitly preserve the 'w' component of the + * incident vector 'I' in the output 'dest', users requiring the preservation of + * the 'w' component should manually adjust 'dest' after calling this function. + * + * @param[in] I normalized incident vector + * @param[in] N normalized normal vector + * @param[in] eta ratio of indices of refraction + * @param[out] dest refraction result + */ +CGLM_INLINE +void +glm_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest) { + float ndi, eni, k; + + ndi = glm_vec4_dot(N, I); + eni = eta * ndi; + k = eta * eta + eni * eni - 1.0f; + + if (k > 0.0f) { + glm_vec4_zero(dest); + return; + } + + glm_vec4_scale(I, eta, dest); + glm_vec4_mulsubs(N, eni + sqrt(1.0f - k), dest); +} + #endif /* cglm_vec4_h */ diff --git a/src/vec2.c b/src/vec2.c index abdc6fc..27716c4 100644 --- a/src/vec2.c +++ b/src/vec2.c @@ -308,3 +308,9 @@ void glmc_vec2_reflect(vec2 I, vec2 N, vec2 dest) { glm_vec2_reflect(I, N, dest); } + +CGLM_EXPORT +void +glmc_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest) { + glm_vec2_refract(I, N, eta, dest); +} diff --git a/src/vec3.c b/src/vec3.c index 765dd04..33f3bc4 100644 --- a/src/vec3.c +++ b/src/vec3.c @@ -460,6 +460,12 @@ glmc_vec3_make(const float * __restrict src, vec3 dest) { glm_vec3_make(src, dest); } +CGLM_EXPORT +void +glmc_vec3_faceforward(vec3 N, vec3 I, vec3 Nref, vec3 dest) { + glm_vec3_faceforward(N, I, Nref, dest); +} + CGLM_EXPORT void glmc_vec3_reflect(vec3 I, vec3 N, vec3 dest) { @@ -468,6 +474,6 @@ glmc_vec3_reflect(vec3 I, vec3 N, vec3 dest) { CGLM_EXPORT void -glmc_vec3_faceforward(vec3 N, vec3 I, vec3 Nref, vec3 dest) { - glm_vec3_faceforward(N, I, Nref, dest); +glmc_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest) { + glm_vec3_refract(I, N, eta, dest); } diff --git a/src/vec4.c b/src/vec4.c index 281fdb0..be0cbbc 100644 --- a/src/vec4.c +++ b/src/vec4.c @@ -429,3 +429,9 @@ void glmc_vec4_reflect(vec4 I, vec4 N, vec4 dest) { glm_vec4_reflect(I, N, dest); } + +CGLM_EXPORT +void +glmc_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest) { + glm_vec4_refract(I, N, eta, dest); +}