Compare commits

..

4 Commits
ray ... v0.9.3

Author SHA1 Message Date
Recep Aslantas
1de373a9bd normalize: norm == 0.0f to norm < FLT_EPSILON, improving handling of very small vectors to prevent instability and overflow 2024-03-25 02:22:46 +03:00
Recep Aslantas
6a7d03bafb suppress warnings 2024-03-25 02:17:03 +03:00
Recep Aslantas
aad5223da0 change signature of refraction to let caller know if refraction occurs or not 2024-03-24 06:31:29 +03:00
Recep Aslantas
707bff021c Merge pull request #399 from recp/ray
Some missing ray functions
2024-03-23 11:26:17 +03:00
20 changed files with 172 additions and 121 deletions

View File

@@ -406,15 +406,19 @@ Functions documentation
| *[in]* **N** *❗️ normalized ❗️* normal vector | *[in]* **N** *❗️ normalized ❗️* normal vector
| *[out]* **dest** destination: reflection result | *[out]* **dest** destination: reflection result
.. c:function:: void glm_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest) .. c:function:: bool glm_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest)
Refraction vector using entering ray, surface normal and refraction index Computes refraction vector for an incident vector and a surface normal.
If the angle between the entering ray I and the surface normal N is too Calculates the refraction vector based on Snell's law. If total internal reflection
great for a given refraction index, the return value is zero occurs (angle too great given eta), dest is set to zero and returns false.
Otherwise, computes refraction vector, stores it in dest, and returns true.
Parameters: Parameters:
| *[in]* **I** *❗️ normalized ❗️* incident vector | *[in]* **I** *❗️ normalized ❗️* incident vector
| *[in]* **N** *❗️ normalized ❗️* normal vector | *[in]* **N** *❗️ normalized ❗️* normal vector
| *[in]* **eta** ratio of indices of refraction ( η ) | *[in]* **eta** ratio of indices of refraction (incident/transmitted)
| *[out]* **dest** destination: refraction result | *[out]* **dest** refraction vector if refraction occurs; zero vector otherwise
Returns:
returns true if refraction occurs; false if total internal reflection occurs.

View File

@@ -535,15 +535,20 @@ Functions documentation
| *[in]* **N** *❗️ normalized ❗️* normal vector | *[in]* **N** *❗️ normalized ❗️* normal vector
| *[out]* **dest** destination: reflection result | *[out]* **dest** destination: reflection result
.. c:function:: void glm_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest) .. c:function:: bool glm_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest)
Refraction vector using entering ray, surface normal and refraction index
Computes refraction vector for an incident vector and a surface 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 Calculates the refraction vector based on Snell's law. If total internal reflection
occurs (angle too great given eta), dest is set to zero and returns false.
Otherwise, computes refraction vector, stores it in dest, and returns true.
Parameters: Parameters:
| *[in]* **I** *❗️ normalized ❗️* incident vector | *[in]* **I** *❗️ normalized ❗️* incident vector
| *[in]* **N** *❗️ normalized ❗️* normal vector | *[in]* **N** *❗️ normalized ❗️* normal vector
| *[in]* **eta** ratio of indices of refraction ( η ) | *[in]* **eta** ratio of indices of refraction (incident/transmitted)
| *[out]* **dest** destination: refraction result | *[out]* **dest** refraction vector if refraction occurs; zero vector otherwise
Returns:
returns true if refraction occurs; false if total internal reflection occurs.

View File

@@ -427,7 +427,7 @@ Functions documentation
| *[in]* **src** pointer to an array of floats | *[in]* **src** pointer to an array of floats
| *[out]* **dest** destination vector | *[out]* **dest** destination vector
.. c:function:: void glm_vec4_reflect(vec4 I, vec4 N, vec4 dest) .. c:function:: bool glm_vec4_reflect(vec4 I, vec4 N, vec4 dest)
Reflection vector using an incident ray and a surface normal Reflection vector using an incident ray and a surface normal
@@ -436,19 +436,23 @@ Functions documentation
| *[in]* **N** *❗️ normalized ❗️* normal vector | *[in]* **N** *❗️ normalized ❗️* normal vector
| *[out]* **dest** destination: reflection result | *[out]* **dest** destination: reflection result
.. c:function:: void glm_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest) .. c:function:: bool glm_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest)
Refraction vector using entering ray, surface normal and refraction index computes refraction vector for an incident vector and a surface normal.
If the angle between the entering ray I and the surface normal N is too Calculates the refraction vector based on Snell's law. If total internal reflection
great for a given refraction index, the return value is zero occurs (angle too great given eta), dest is set to zero and returns false.
Otherwise, computes refraction vector, stores it in dest, and returns true.
this implementation does not explicitly preserve the 'w' component of the
This implementation does not explicitly preserve the 'w' component of the
incident vector 'I' in the output 'dest', users requiring the preservation of incident vector 'I' in the output 'dest', users requiring the preservation of
the 'w' component should manually adjust 'dest' after calling this function. the 'w' component should manually adjust 'dest' after calling this function.
Parameters: Parameters:
| *[in]* **I** *❗️ normalized ❗️* incident vector | *[in]* **I** *❗️ normalized ❗️* incident vector
| *[in]* **N** *❗️ normalized ❗️* normal vector | *[in]* **N** *❗️ normalized ❗️* normal vector
| *[in]* **eta** ratio of indices of refraction ( η ) | *[in]* **eta** ratio of indices of refraction (incident/transmitted)
| *[out]* **dest** destination: refraction result | *[out]* **dest** refraction vector if refraction occurs; zero vector otherwise
Returns:
returns true if refraction occurs; false if total internal reflection occurs.

View File

@@ -202,7 +202,7 @@ void
glmc_vec2_reflect(vec2 I, vec2 N, vec2 dest); glmc_vec2_reflect(vec2 I, vec2 N, vec2 dest);
CGLM_EXPORT CGLM_EXPORT
void bool
glmc_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest); glmc_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -343,7 +343,7 @@ void
glmc_vec3_reflect(vec3 I, vec3 N, vec3 dest); glmc_vec3_reflect(vec3 I, vec3 N, vec3 dest);
CGLM_EXPORT CGLM_EXPORT
void bool
glmc_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest); glmc_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -316,7 +316,7 @@ void
glmc_vec4_reflect(vec4 I, vec4 N, vec4 dest); glmc_vec4_reflect(vec4 I, vec4 N, vec4 dest);
CGLM_EXPORT CGLM_EXPORT
void bool
glmc_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest); glmc_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -37,6 +37,14 @@
# define CGLM_INLINE static inline __attribute((always_inline)) # define CGLM_INLINE static inline __attribute((always_inline))
#endif #endif
#if defined(__GNUC__) || defined(__clang__)
# define CGLM_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
# define CGLM_LIKELY(expr) __builtin_expect(!!(expr), 1)
#else
# define CGLM_UNLIKELY(expr) (expr)
# define CGLM_LIKELY(expr) (expr)
#endif
#define GLM_SHUFFLE4(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) #define GLM_SHUFFLE4(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w))
#define GLM_SHUFFLE3(z, y, x) (((z) << 4) | ((y) << 2) | (x)) #define GLM_SHUFFLE3(z, y, x) (((z) << 4) | ((y) << 2) | (x))

View File

@@ -33,7 +33,7 @@ void
glm_plane_normalize(vec4 plane) { glm_plane_normalize(vec4 plane) {
float norm; float norm;
if ((norm = glm_vec3_norm(plane)) == 0.0f) { if (CGLM_UNLIKELY((norm = glm_vec3_norm(plane)) < FLT_EPSILON)) {
glm_vec4_zero(plane); glm_vec4_zero(plane);
return; return;
} }

View File

@@ -55,7 +55,7 @@
CGLM_INLINE vec2s glms_vec2_lerp(vec2s from, vec2s to, float t) 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_make(float * restrict src)
CGLM_INLINE vec2s glms_vec2_reflect(vec2s I, vec2s N) CGLM_INLINE vec2s glms_vec2_reflect(vec2s I, vec2s N)
CGLM_INLINE vec2s glms_vec2_refract(vec2s I, vec2s N, float eta) CGLM_INLINE bool glms_vec2_refract(vec2s I, vec2s N, float eta, vec2s *dest)
*/ */
#ifndef cglms_vec2s_h #ifndef cglms_vec2s_h
@@ -709,22 +709,23 @@ glms_vec2_(reflect)(vec2s I, vec2s N) {
} }
/*! /*!
* @brief refraction vector using entering ray, surface normal and refraction index * @brief computes refraction vector for an incident vector and a surface normal.
* *
* if the angle between the entering ray I and the surface normal N is too great * calculates the refraction vector based on Snell's law. If total internal reflection
* for a given refraction index, the return value is zero * occurs (angle too great given eta), dest is set to zero and returns false.
* Otherwise, computes refraction vector, stores it in dest, and returns true.
* *
* @param[in] I normalized incident vector * @param[in] I normalized incident vector
* @param[in] N normalized normal vector * @param[in] N normalized normal vector
* @param[in] eta ratio of indices of refraction * @param[in] eta ratio of indices of refraction (incident/transmitted)
* @param[out] dest refraction result * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
*
* @returns true if refraction occurs; false if total internal reflection occurs.
*/ */
CGLM_INLINE CGLM_INLINE
vec2s bool
glms_vec2_(refract)(vec2s I, vec2s N, float eta) { glms_vec2_(refract)(vec2s I, vec2s N, float eta, vec2s * __restrict dest) {
vec2s dest; return glm_vec2_refract(I.raw, N.raw, eta, dest->raw);
glm_vec2_refract(I.raw, N.raw, eta, dest.raw);
return dest;
} }
#endif /* cglms_vec2s_h */ #endif /* cglms_vec2s_h */

View File

@@ -78,7 +78,7 @@
CGLM_INLINE vec3s glms_vec3_make(float * restrict src); CGLM_INLINE vec3s glms_vec3_make(float * restrict src);
CGLM_INLINE vec3s glms_vec3_faceforward(vec3s N, vec3s I, vec3s Nref); 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_reflect(vec3s I, vec3s N);
CGLM_INLINE vec3s glms_vec3_refract(vec3s I, vec3s N, float eta); CGLM_INLINE bool glms_vec3_refract(vec3s I, vec3s N, float eta, vec3s *dest)
Convenient: Convenient:
CGLM_INLINE vec3s glms_cross(vec3s a, vec3s b); CGLM_INLINE vec3s glms_cross(vec3s a, vec3s b);
@@ -1120,22 +1120,23 @@ glms_vec3_(reflect)(vec3s I, vec3s N) {
} }
/*! /*!
* @brief refraction vector using entering ray, surface normal and refraction index * @brief computes refraction vector for an incident vector and a surface normal.
* *
* if the angle between the entering ray I and the surface normal N is too great * calculates the refraction vector based on Snell's law. If total internal reflection
* for a given refraction index, the return value is zero * occurs (angle too great given eta), dest is set to zero and returns false.
* Otherwise, computes refraction vector, stores it in dest, and returns true.
* *
* @param[in] I normalized incident vector * @param[in] I normalized incident vector
* @param[in] N normalized normal vector * @param[in] N normalized normal vector
* @param[in] eta ratio of indices of refraction * @param[in] eta ratio of indices of refraction (incident/transmitted)
* @returns refraction result * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
*
* @returns true if refraction occurs; false if total internal reflection occurs.
*/ */
CGLM_INLINE CGLM_INLINE
vec3s bool
glms_vec3_(refract)(vec3s I, vec3s N, float eta) { glms_vec3_(refract)(vec3s I, vec3s N, float eta, vec3s * __restrict dest) {
vec3s dest; return glm_vec3_refract(I.raw, N.raw, eta, dest->raw);
glm_vec3_refract(I.raw, N.raw, eta, dest.raw);
return dest;
} }
#endif /* cglms_vec3s_h */ #endif /* cglms_vec3s_h */

View File

@@ -68,7 +68,7 @@
CGLM_INLINE vec4s glms_vec4_swizzle(vec4s v, int mask); CGLM_INLINE vec4s glms_vec4_swizzle(vec4s v, int mask);
CGLM_INLINE vec4s glms_vec4_make(float * restrict src); CGLM_INLINE vec4s glms_vec4_make(float * restrict src);
CGLM_INLINE vec4s glms_vec4_reflect(vec4s I, vec4s N); CGLM_INLINE vec4s glms_vec4_reflect(vec4s I, vec4s N);
CGLM_INLINE vec4s glms_vec4_refract(vec4s I, vec4s N, float eta); CGLM_INLINE bool glms_vec4_refract(vec4s I, vec4s N, float eta, vec4s *dest)
*/ */
#ifndef cglms_vec4s_h #ifndef cglms_vec4s_h
@@ -945,10 +945,11 @@ glms_vec4_(reflect)(vec4s I, vec4s N) {
} }
/*! /*!
* @brief refraction vector using entering ray, surface normal and refraction index * @brief computes refraction vector for an incident vector and a surface normal.
* *
* if the angle between the entering ray I and the surface normal N is too great * calculates the refraction vector based on Snell's law. If total internal reflection
* for a given refraction index, the return value is zero * occurs (angle too great given eta), dest is set to zero and returns false.
* Otherwise, computes refraction vector, stores it in dest, and returns true.
* *
* this implementation does not explicitly preserve the 'w' component of the * this implementation does not explicitly preserve the 'w' component of the
* incident vector 'I' in the output 'dest', users requiring the preservation of * incident vector 'I' in the output 'dest', users requiring the preservation of
@@ -956,15 +957,15 @@ glms_vec4_(reflect)(vec4s I, vec4s N) {
* *
* @param[in] I normalized incident vector * @param[in] I normalized incident vector
* @param[in] N normalized normal vector * @param[in] N normalized normal vector
* @param[in] eta ratio of indices of refraction * @param[in] eta ratio of indices of refraction (incident/transmitted)
* @returns refraction result * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
*
* @returns true if refraction occurs; false if total internal reflection occurs.
*/ */
CGLM_INLINE CGLM_INLINE
vec4s bool
glms_vec4_(refract)(vec4s I, vec4s N, float eta) { glms_vec4_(refract)(vec4s I, vec4s N, float eta, vec4s * __restrict dest) {
vec4s dest; return glm_vec4_refract(I.raw, N.raw, eta, dest->raw);
glm_vec4_refract(I.raw, N.raw, eta, dest.raw);
return dest;
} }
#endif /* cglms_vec4s_h */ #endif /* cglms_vec4s_h */

View File

@@ -278,7 +278,7 @@ glm_vec2_scale_as(vec2 v, float s, vec2 dest) {
float norm; float norm;
norm = glm_vec2_norm(v); norm = glm_vec2_norm(v);
if (norm == 0.0f) { if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
glm_vec2_zero(dest); glm_vec2_zero(dest);
return; return;
} }
@@ -542,7 +542,7 @@ glm_vec2_normalize(vec2 v) {
norm = glm_vec2_norm(v); norm = glm_vec2_norm(v);
if (norm == 0.0f) { if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
v[0] = v[1] = 0.0f; v[0] = v[1] = 0.0f;
return; return;
} }
@@ -563,7 +563,7 @@ glm_vec2_normalize_to(vec2 v, vec2 dest) {
norm = glm_vec2_norm(v); norm = glm_vec2_norm(v);
if (norm == 0.0f) { if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
glm_vec2_zero(dest); glm_vec2_zero(dest);
return; return;
} }
@@ -729,18 +729,21 @@ glm_vec2_reflect(vec2 I, vec2 N, vec2 dest) {
} }
/*! /*!
* @brief refraction vector using entering ray, surface normal and refraction index * @brief computes refraction vector for an incident vector and a surface normal.
* *
* if the angle between the entering ray I and the surface normal N is too great * calculates the refraction vector based on Snell's law. If total internal reflection
* for a given refraction index, the return value is zero * occurs (angle too great given eta), dest is set to zero and returns false.
* Otherwise, computes refraction vector, stores it in dest, and returns true.
* *
* @param[in] I normalized incident vector * @param[in] I normalized incident vector
* @param[in] N normalized normal vector * @param[in] N normalized normal vector
* @param[in] eta ratio of indices of refraction * @param[in] eta ratio of indices of refraction (incident/transmitted)
* @param[out] dest refraction result * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
*
* @returns true if refraction occurs; false if total internal reflection occurs.
*/ */
CGLM_INLINE CGLM_INLINE
void bool
glm_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest) { glm_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest) {
float ndi, eni, k; float ndi, eni, k;
@@ -750,11 +753,12 @@ glm_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest) {
if (k < 0.0f) { if (k < 0.0f) {
glm_vec2_zero(dest); glm_vec2_zero(dest);
return; return false;
} }
glm_vec2_scale(I, eta, dest); glm_vec2_scale(I, eta, dest);
glm_vec2_mulsubs(N, eni + sqrtf(k), dest); glm_vec2_mulsubs(N, eni + sqrtf(k), dest);
return true;
} }
#endif /* cglm_vec2_h */ #endif /* cglm_vec2_h */

View File

@@ -372,7 +372,7 @@ glm_vec3_scale_as(vec3 v, float s, vec3 dest) {
float norm; float norm;
norm = glm_vec3_norm(v); norm = glm_vec3_norm(v);
if (norm == 0.0f) { if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
glm_vec3_zero(dest); glm_vec3_zero(dest);
return; return;
} }
@@ -651,7 +651,7 @@ glm_vec3_normalize(vec3 v) {
norm = glm_vec3_norm(v); norm = glm_vec3_norm(v);
if (norm == 0.0f) { if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
v[0] = v[1] = v[2] = 0.0f; v[0] = v[1] = v[2] = 0.0f;
return; return;
} }
@@ -672,7 +672,7 @@ glm_vec3_normalize_to(vec3 v, vec3 dest) {
norm = glm_vec3_norm(v); norm = glm_vec3_norm(v);
if (norm == 0.0f) { if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
glm_vec3_zero(dest); glm_vec3_zero(dest);
return; return;
} }
@@ -1243,18 +1243,21 @@ glm_vec3_reflect(vec3 I, vec3 N, vec3 dest) {
} }
/*! /*!
* @brief refraction vector using entering ray, surface normal and refraction index * @brief computes refraction vector for an incident vector and a surface normal.
* *
* if the angle between the entering ray I and the surface normal N is too great * calculates the refraction vector based on Snell's law. If total internal reflection
* for a given refraction index, the return value is zero * occurs (angle too great given eta), dest is set to zero and returns false.
* Otherwise, computes refraction vector, stores it in dest, and returns true.
* *
* @param[in] I normalized incident vector * @param[in] I normalized incident vector
* @param[in] N normalized normal vector * @param[in] N normalized normal vector
* @param[in] eta ratio of indices of refraction * @param[in] eta ratio of indices of refraction (incident/transmitted)
* @param[out] dest refraction result * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
*
* @returns true if refraction occurs; false if total internal reflection occurs.
*/ */
CGLM_INLINE CGLM_INLINE
void bool
glm_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest) { glm_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest) {
float ndi, eni, k; float ndi, eni, k;
@@ -1264,11 +1267,12 @@ glm_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest) {
if (k < 0.0f) { if (k < 0.0f) {
glm_vec3_zero(dest); glm_vec3_zero(dest);
return; return false;
} }
glm_vec3_scale(I, eta, dest); glm_vec3_scale(I, eta, dest);
glm_vec3_mulsubs(N, eni + sqrtf(k), dest); glm_vec3_mulsubs(N, eni + sqrtf(k), dest);
return true;
} }
#endif /* cglm_vec3_h */ #endif /* cglm_vec3_h */

View File

@@ -487,7 +487,7 @@ glm_vec4_scale_as(vec4 v, float s, vec4 dest) {
float norm; float norm;
norm = glm_vec4_norm(v); norm = glm_vec4_norm(v);
if (norm == 0.0f) { if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
glm_vec4_zero(dest); glm_vec4_zero(dest);
return; return;
} }
@@ -918,7 +918,7 @@ glm_vec4_normalize_to(vec4 v, vec4 dest) {
/* dot = _mm_cvtss_f32(xdot); */ /* dot = _mm_cvtss_f32(xdot); */
dot = wasm_f32x4_extract_lane(xdot, 0); dot = wasm_f32x4_extract_lane(xdot, 0);
if (dot == 0.0f) { if (CGLM_UNLIKELY(dot < FLT_EPSILON)) {
glmm_store(dest, wasm_f32x4_const_splat(0.f)); glmm_store(dest, wasm_f32x4_const_splat(0.f));
return; return;
} }
@@ -932,7 +932,7 @@ glm_vec4_normalize_to(vec4 v, vec4 dest) {
xdot = glmm_vdot(x0, x0); xdot = glmm_vdot(x0, x0);
dot = _mm_cvtss_f32(xdot); dot = _mm_cvtss_f32(xdot);
if (dot == 0.0f) { if (CGLM_UNLIKELY(dot < FLT_EPSILON)) {
glmm_store(dest, _mm_setzero_ps()); glmm_store(dest, _mm_setzero_ps());
return; return;
} }
@@ -943,7 +943,7 @@ glm_vec4_normalize_to(vec4 v, vec4 dest) {
norm = glm_vec4_norm(v); norm = glm_vec4_norm(v);
if (norm == 0.0f) { if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
glm_vec4_zero(dest); glm_vec4_zero(dest);
return; return;
} }
@@ -1326,10 +1326,11 @@ glm_vec4_reflect(vec4 I, vec4 N, vec4 dest) {
} }
/*! /*!
* @brief refraction vector using entering ray, surface normal and refraction index * @brief computes refraction vector for an incident vector and a surface normal.
* *
* if the angle between the entering ray I and the surface normal N is too great * calculates the refraction vector based on Snell's law. If total internal reflection
* for a given refraction index, the return value is zero * occurs (angle too great given eta), dest is set to zero and returns false.
* Otherwise, computes refraction vector, stores it in dest, and returns true.
* *
* this implementation does not explicitly preserve the 'w' component of the * this implementation does not explicitly preserve the 'w' component of the
* incident vector 'I' in the output 'dest', users requiring the preservation of * incident vector 'I' in the output 'dest', users requiring the preservation of
@@ -1337,11 +1338,13 @@ glm_vec4_reflect(vec4 I, vec4 N, vec4 dest) {
* *
* @param[in] I normalized incident vector * @param[in] I normalized incident vector
* @param[in] N normalized normal vector * @param[in] N normalized normal vector
* @param[in] eta ratio of indices of refraction * @param[in] eta ratio of indices of refraction (incident/transmitted)
* @param[out] dest refraction result * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
*
* @returns true if refraction occurs; false if total internal reflection occurs.
*/ */
CGLM_INLINE CGLM_INLINE
void bool
glm_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest) { glm_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest) {
float ndi, eni, k; float ndi, eni, k;
@@ -1351,11 +1354,12 @@ glm_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest) {
if (k < 0.0f) { if (k < 0.0f) {
glm_vec4_zero(dest); glm_vec4_zero(dest);
return; return false;
} }
glm_vec4_scale(I, eta, dest); glm_vec4_scale(I, eta, dest);
glm_vec4_mulsubs(N, eni + sqrtf(k), dest); glm_vec4_mulsubs(N, eni + sqrtf(k), dest);
return true;
} }
#endif /* cglm_vec4_h */ #endif /* cglm_vec4_h */

View File

@@ -310,7 +310,7 @@ glmc_vec2_reflect(vec2 I, vec2 N, vec2 dest) {
} }
CGLM_EXPORT CGLM_EXPORT
void bool
glmc_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest) { glmc_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest) {
glm_vec2_refract(I, N, eta, dest); return glm_vec2_refract(I, N, eta, dest);
} }

View File

@@ -473,7 +473,7 @@ glmc_vec3_reflect(vec3 I, vec3 N, vec3 dest) {
} }
CGLM_EXPORT CGLM_EXPORT
void bool
glmc_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest) { glmc_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest) {
glm_vec3_refract(I, N, eta, dest); return glm_vec3_refract(I, N, eta, dest);
} }

View File

@@ -431,7 +431,7 @@ glmc_vec4_reflect(vec4 I, vec4 N, vec4 dest) {
} }
CGLM_EXPORT CGLM_EXPORT
void bool
glmc_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest) { glmc_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest) {
glm_vec4_refract(I, N, eta, dest); return glm_vec4_refract(I, N, eta, dest);
} }

View File

@@ -241,7 +241,7 @@ TEST_IMPL(GLM_PREFIX, vec2_scale_as) {
GLM(vec2_scale_as)(v1, s, v2); GLM(vec2_scale_as)(v1, s, v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
@@ -492,7 +492,7 @@ TEST_IMPL(GLM_PREFIX, vec2_normalize) {
GLM(vec2_normalize)(v2); GLM(vec2_normalize)(v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
@@ -519,7 +519,7 @@ TEST_IMPL(GLM_PREFIX, vec2_normalize_to) {
GLM(vec2_normalize_to)(v1, v2); GLM(vec2_normalize_to)(v1, v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
@@ -785,35 +785,40 @@ TEST_IMPL(GLM_PREFIX, vec2_refract) {
vec2 N = {0.0f, 1.0f}; /* Surface normal */ vec2 N = {0.0f, 1.0f}; /* Surface normal */
vec2 dest; vec2 dest;
float eta; float eta;
float r;
/* Water to Air (eta = 1.33/1.0) */ /* Water to Air (eta = 1.33/1.0) */
eta = 1.33f / 1.0f; eta = 1.33f / 1.0f;
GLM(vec2_refract)(I, N, eta, dest); r = GLM(vec2_refract)(I, N, eta, dest);
// In 2D, we expect a similar bending behavior as in 3D, so we check dest[1] // In 2D, we expect a similar bending behavior as in 3D, so we check dest[1]
if (!(dest[0] == 0.0f && dest[1] == 0.0f)) { if (!(dest[0] == 0.0f && dest[1] == 0.0f)) {
ASSERT(dest[1] < -sqrtf(0.5f)); // Refracted ray bends away from the normal ASSERT(dest[1] < -sqrtf(0.5f)); // Refracted ray bends away from the normal
ASSERT(r == true);
} else { } else {
ASSERT(dest[0] == 0.0f && dest[1] == 0.0f); // Total internal reflection ASSERT(dest[0] == 0.0f && dest[1] == 0.0f); // Total internal reflection
ASSERT(r == false);
} }
/* Air to Glass (eta = 1.0 / 1.5) */ /* Air to Glass (eta = 1.0 / 1.5) */
eta = 1.0f / 1.5f; eta = 1.0f / 1.5f;
GLM(vec2_refract)(I, N, eta, dest); r = GLM(vec2_refract)(I, N, eta, dest);
ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal
/* Glass to Water (eta = 1.5 / 1.33) */ /* Glass to Water (eta = 1.5 / 1.33) */
eta = 1.5f / 1.33f; eta = 1.5f / 1.33f;
GLM(vec2_refract)(I, N, eta, dest); r = GLM(vec2_refract)(I, N, eta, dest);
ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal, less bending than air to glass ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal, less bending than air to glass
/* Diamond to Air (eta = 2.42 / 1.0) */ /* Diamond to Air (eta = 2.42 / 1.0) */
eta = 2.42f / 1.0f; eta = 2.42f / 1.0f;
GLM(vec2_refract)(I, N, eta, dest); r = GLM(vec2_refract)(I, N, eta, dest);
if (!(dest[0] == 0.0f && dest[1] == 0.0f)) { if (!(dest[0] == 0.0f && dest[1] == 0.0f)) {
/* High potential for total internal reflection, but if it occurs, expect significant bending */ /* High potential for total internal reflection, but if it occurs, expect significant bending */
ASSERT(dest[1] < -sqrtf(0.5f)); ASSERT(dest[1] < -sqrtf(0.5f));
ASSERT(r == true);
} else { } else {
ASSERT(dest[0] == 0.0f && dest[1] == 0.0f); // Total internal reflection ASSERT(dest[0] == 0.0f && dest[1] == 0.0f); // Total internal reflection
ASSERT(r == false);
} }
TEST_SUCCESS TEST_SUCCESS

View File

@@ -433,7 +433,7 @@ TEST_IMPL(GLM_PREFIX, vec3_scale_as) {
GLM(vec3_scale_as)(v1, s, v2); GLM(vec3_scale_as)(v1, s, v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[2], 0.0f))
@@ -704,7 +704,7 @@ TEST_IMPL(GLM_PREFIX, vec3_normalize) {
GLM(vec3_normalize)(v2); GLM(vec3_normalize)(v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[2], 0.0f))
@@ -733,7 +733,7 @@ TEST_IMPL(GLM_PREFIX, vec3_normalize_to) {
GLM(vec3_normalize_to)(v1, v2); GLM(vec3_normalize_to)(v1, v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[2], 0.0f))
@@ -764,7 +764,7 @@ TEST_IMPL(GLM_PREFIX, normalize) {
GLM(vec3_normalize)(v2); GLM(vec3_normalize)(v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[2], 0.0f))
@@ -795,7 +795,7 @@ TEST_IMPL(GLM_PREFIX, normalize_to) {
GLM(vec3_normalize_to)(v1, v2); GLM(vec3_normalize_to)(v1, v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[2], 0.0f))
@@ -1890,38 +1890,43 @@ TEST_IMPL(GLM_PREFIX, vec3_refract) {
vec3 N = {0.0f, 1.0f, 0.0f}; /* Surface normal */ vec3 N = {0.0f, 1.0f, 0.0f}; /* Surface normal */
vec3 dest; vec3 dest;
float eta; float eta;
bool r;
/* Water to Air (eta = 1.33/1.0) */ /* Water to Air (eta = 1.33/1.0) */
eta = 1.33f / 1.0f; eta = 1.33f / 1.0f;
GLM(vec3_refract)(I, N, eta, dest); r = GLM(vec3_refract)(I, N, eta, dest);
if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f)) { if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f)) {
ASSERT(dest[1] < -sqrtf(0.5f)); ASSERT(dest[1] < -sqrtf(0.5f));
ASSERT(r == true);
} else { } else {
ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f); ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f);
ASSERT(r == false);
} }
/* Air to Glass (eta = 1.0 / 1.5) */ /* Air to Glass (eta = 1.0 / 1.5) */
eta = 1.0f / 1.5f; eta = 1.0f / 1.5f;
GLM(vec3_refract)(I, N, eta, dest); r = GLM(vec3_refract)(I, N, eta, dest);
/* Expect bending towards the normal */ /* Expect bending towards the normal */
ASSERT(dest[1] < -sqrtf(0.5f)); ASSERT(dest[1] < -sqrtf(0.5f));
/* Glass to Water (eta = 1.5 / 1.33) */ /* Glass to Water (eta = 1.5 / 1.33) */
eta = 1.5f / 1.33f; eta = 1.5f / 1.33f;
GLM(vec3_refract)(I, N, eta, dest); r = GLM(vec3_refract)(I, N, eta, dest);
/* Expect bending towards the normal, less bending than air to glass */ /* Expect bending towards the normal, less bending than air to glass */
ASSERT(dest[1] < -sqrtf(0.5f)); ASSERT(dest[1] < -sqrtf(0.5f));
/* Diamond to Air (eta = 2.42 / 1.0) */ /* Diamond to Air (eta = 2.42 / 1.0) */
eta = 2.42f / 1.0f; eta = 2.42f / 1.0f;
GLM(vec3_refract)(I, N, eta, dest); r = GLM(vec3_refract)(I, N, eta, dest);
if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f)) { if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f)) {
/* High potential for total internal reflection, but if it occurs, expect significant bending */ /* High potential for total internal reflection, but if it occurs, expect significant bending */
ASSERT(dest[1] < -sqrtf(0.5f)); ASSERT(dest[1] < -sqrtf(0.5f));
ASSERT(r == true);
} else { } else {
ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f); ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f);
ASSERT(r == false);
} }
TEST_SUCCESS TEST_SUCCESS

View File

@@ -410,7 +410,7 @@ TEST_IMPL(GLM_PREFIX, vec4_scale_as) {
GLM(vec4_scale_as)(v1, s, v2); GLM(vec4_scale_as)(v1, s, v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[2], 0.0f))
@@ -701,7 +701,7 @@ TEST_IMPL(GLM_PREFIX, vec4_normalize) {
GLM(vec4_normalize)(v2); GLM(vec4_normalize)(v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[2], 0.0f))
@@ -732,7 +732,7 @@ TEST_IMPL(GLM_PREFIX, vec4_normalize_to) {
GLM(vec4_normalize_to)(v1, v2); GLM(vec4_normalize_to)(v1, v2);
norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]);
if (norm == 0.0f) { if (norm < FLT_EPSILON) {
ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[0], 0.0f))
ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[1], 0.0f))
ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[2], 0.0f))
@@ -1575,34 +1575,39 @@ TEST_IMPL(GLM_PREFIX, vec4_refract) {
vec4 N = {0.0f, 1.0f, 0.0f, 0.0f}; /* Surface normal */ vec4 N = {0.0f, 1.0f, 0.0f, 0.0f}; /* Surface normal */
vec4 dest; vec4 dest;
float eta; float eta;
float r;
/* Water to Air (eta = 1.33/1.0) */ /* Water to Air (eta = 1.33/1.0) */
eta = 1.33f / 1.0f; eta = 1.33f / 1.0f;
GLM(vec4_refract)(I, N, eta, dest); r = GLM(vec4_refract)(I, N, eta, dest);
if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f)) { if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f)) {
ASSERT(dest[1] < -sqrtf(0.5f)); ASSERT(dest[1] < -sqrtf(0.5f));
ASSERT(r == true);
} else { } else {
ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f); ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f);
ASSERT(r == false);
} }
/* Air to Glass (eta = 1.0 / 1.5) */ /* Air to Glass (eta = 1.0 / 1.5) */
eta = 1.0f / 1.5f; eta = 1.0f / 1.5f;
GLM(vec4_refract)(I, N, eta, dest); r = GLM(vec4_refract)(I, N, eta, dest);
ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal
/* Glass to Water (eta = 1.5 / 1.33) */ /* Glass to Water (eta = 1.5 / 1.33) */
eta = 1.5f / 1.33f; eta = 1.5f / 1.33f;
GLM(vec4_refract)(I, N, eta, dest); r = GLM(vec4_refract)(I, N, eta, dest);
ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal, less bending than air to glass ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal, less bending than air to glass
/* Diamond to Air (eta = 2.42 / 1.0) */ /* Diamond to Air (eta = 2.42 / 1.0) */
eta = 2.42f / 1.0f; eta = 2.42f / 1.0f;
GLM(vec4_refract)(I, N, eta, dest); r = GLM(vec4_refract)(I, N, eta, dest);
if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f)) { if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f)) {
/* High potential for total internal reflection, but if it occurs, expect significant bending */ /* High potential for total internal reflection, but if it occurs, expect significant bending */
ASSERT(dest[1] < -sqrtf(0.5f)); ASSERT(dest[1] < -sqrtf(0.5f));
ASSERT(r == true);
} else { } else {
ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f); ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f);
ASSERT(r == false);
} }
TEST_SUCCESS TEST_SUCCESS