diff --git a/CREDITS b/CREDITS index 00cc83235..f875d1a5b 100644 --- a/CREDITS +++ b/CREDITS @@ -82,3 +82,17 @@ http://github.com/microsoft/DirectXMath 17. Pick Matrix glu project -> project.c + +18. Ray sphere intersection + +RAY TRACING GEMS +HIGH-QUALITY AND REAL-TIME RENDERING WITH DXR AND OTHER APIS + +CHAPTER 7 +Precision Improvements for Ray/Sphere Intersection +Eric Haines (1), Johannes Günther (2), and Tomas Akenine-Möller (1) + (1) NVIDIA + (2) Intel + +Wyman, C., and Haines, E. Getting Started with RTX Ray Tracing. +https://github.com/NVIDIAGameWorks/GettingStartedWithRTXRayTracing diff --git a/Makefile.am b/Makefile.am index 474569943..2a8ce0eca 100644 --- a/Makefile.am +++ b/Makefile.am @@ -216,7 +216,8 @@ cglm_struct_HEADERS = include/cglm/struct/mat4.h \ include/cglm/struct/project.h \ include/cglm/struct/sphere.h \ include/cglm/struct/color.h \ - include/cglm/struct/curve.h + include/cglm/struct/curve.h \ + include/cglm/struct/ray.h cglm_struct_clipspacedir=$(includedir)/cglm/struct/clipspace cglm_struct_clipspace_HEADERS = include/cglm/struct/clipspace/persp_lh_no.h \ diff --git a/docs/source/ray.rst b/docs/source/ray.rst index c5faf336b..ab89b7af6 100644 --- a/docs/source/ray.rst +++ b/docs/source/ray.rst @@ -13,6 +13,8 @@ Table of contents (click to go): Functions: 1. :c:func:`glm_ray_triangle` +#. :c:func:`glm_ray_sphere` +#. :c:func:`glm_ray_at` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -29,3 +31,37 @@ Functions documentation | *[in]* **v2** third vertex of triangle | *[in, out]* **d** float pointer to save distance to intersection | *[out]* **intersection** whether there is intersection + +.. c:function:: bool glm_ray_sphere(vec3 origin, vec3 dir, vec4 s, float * __restrict t1, float * __restrict t2) + + ray sphere intersection + + - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin + - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2 + - t1 < 0, t2 < 0: no intersection ahead of the ray + - the caller can check if the intersection points (t1 and t2) fall within a + specific range (for example, tmin < t1, t2 < tmax) to determine if the + intersections are within a desired segment of the ray + + Parameters: + | *[in]* **origin** ray origin + | *[in]* **dir** normalized ray direction + | *[in]* **s** sphere [center.x, center.y, center.z, radii] + | *[out]* **t1** near point1 (closer to origin) + | *[out]* **t2** far point2 (farther from origin) + + Return: + | whether there is intersection + +.. c:function:: bool glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point) + + point using t by 𝐏(𝑡)=𝐀+𝑡𝐛 + + Parameters: + | *[in]* **origin** ray origin + | *[in]* **dir** ray direction + | *[out]* **t** parameter + | *[out]* **point** point at t + + Return: + | point at t diff --git a/docs/source/vec2.rst b/docs/source/vec2.rst index 102f4fa69..8b1bdf02e 100644 --- a/docs/source/vec2.rst +++ b/docs/source/vec2.rst @@ -53,6 +53,8 @@ Functions: #. :c:func:`glm_vec2_clamp` #. :c:func:`glm_vec2_lerp` #. :c:func:`glm_vec2_make` +#. :c:func:`glm_vec2_reflect` +#. :c:func:`glm_vec2_refract` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -394,3 +396,25 @@ Functions documentation Parameters: | *[in]* **src** pointer to an array of floats | *[out]* **dest** destination vector + +.. c:function:: void glm_vec2_reflect(vec2 I, vec2 N, vec2 dest) + + Reflection vector using an incident ray and a surface normal + + Parameters: + | *[in]* **I** incident vector + | *[in]* **N** *❗️ normalized ❗️* normal vector + | *[out]* **dest** destination: reflection result + +.. c:function:: void glm_vec2_refract(vec2 I, vec2 N, float eta, vec2 dest) + + 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 + + Parameters: + | *[in]* **I** *❗️ normalized ❗️* incident vector + | *[in]* **N** *❗️ normalized ❗️* normal vector + | *[in]* **eta** ratio of indices of refraction ( η ) + | *[out]* **dest** destination: refraction result diff --git a/docs/source/vec3.rst b/docs/source/vec3.rst index c7d92c815..07412c603 100644 --- a/docs/source/vec3.rst +++ b/docs/source/vec3.rst @@ -80,6 +80,9 @@ Functions: #. :c:func:`glm_vec3_clamp` #. :c:func:`glm_vec3_lerp` #. :c:func:`glm_vec3_make` +#. :c:func:`glm_vec3_faceforward` +#. :c:func:`glm_vec3_reflect` +#. :c:func:`glm_vec3_refract` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -512,3 +515,35 @@ Functions documentation Parameters: | *[in]* **src** pointer to an array of floats | *[out]* **dest** destination vector + +.. c:function:: void glm_vec3_faceforward(vec3 N, vec3 I, vec3 Nref, vec3 dest) + + A vector pointing in the same direction as another + + Parameters: + | *[in]* **N** vector to orient + | *[in]* **I** incident vector + | *[in]* **Nref** reference vector + | *[out]* **dest** destination: oriented vector, pointing away from the surface. + +.. c:function:: void glm_vec3_reflect(vec3 I, vec3 N, vec3 dest) + + Reflection vector using an incident ray and a surface normal + + Parameters: + | *[in]* **I** incident vector + | *[in]* **N** *❗️ normalized ❗️* normal vector + | *[out]* **dest** destination: reflection result + +.. c:function:: void glm_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest) + + 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 + + Parameters: + | *[in]* **I** *❗️ normalized ❗️* incident vector + | *[in]* **N** *❗️ normalized ❗️* normal vector + | *[in]* **eta** ratio of indices of refraction ( η ) + | *[out]* **dest** destination: refraction result diff --git a/docs/source/vec4.rst b/docs/source/vec4.rst index 4281816f3..df270e75e 100644 --- a/docs/source/vec4.rst +++ b/docs/source/vec4.rst @@ -60,6 +60,8 @@ Functions: #. :c:func:`glm_vec4_lerp` #. :c:func:`glm_vec4_cubic` #. :c:func:`glm_vec4_make` +#. :c:func:`glm_vec4_reflect` +#. :c:func:`glm_vec4_refract` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -424,3 +426,29 @@ Functions documentation Parameters: | *[in]* **src** pointer to an array of floats | *[out]* **dest** destination vector + +.. c:function:: void glm_vec4_reflect(vec4 I, vec4 N, vec4 dest) + + Reflection vector using an incident ray and a surface normal + + Parameters: + | *[in]* **I** incident vector + | *[in]* **N** *❗️ normalized ❗️* normal vector + | *[out]* **dest** destination: reflection result + +.. c:function:: void glm_vec4_refract(vec4 I, vec4 N, float eta, vec4 dest) + + 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. + + Parameters: + | *[in]* **I** *❗️ normalized ❗️* incident vector + | *[in]* **N** *❗️ normalized ❗️* normal vector + | *[in]* **eta** ratio of indices of refraction ( η ) + | *[out]* **dest** destination: refraction result diff --git a/include/cglm/call/ray.h b/include/cglm/call/ray.h index 1fff0554c..e529fdf91 100644 --- a/include/cglm/call/ray.h +++ b/include/cglm/call/ray.h @@ -20,7 +20,19 @@ glmc_ray_triangle(vec3 origin, vec3 v1, vec3 v2, float *d); - + +CGLM_EXPORT +bool +glmc_ray_sphere(vec3 origin, + vec3 dir, + vec4 s, + float * __restrict t1, + float * __restrict t2); + +CGLM_EXPORT +void +glmc_ray_at(vec3 orig, vec3 dir, float t, vec3 point); + #ifdef __cplusplus } #endif diff --git a/include/cglm/call/vec2.h b/include/cglm/call/vec2.h index f95166394..bb6e629dc 100644 --- a/include/cglm/call/vec2.h +++ b/include/cglm/call/vec2.h @@ -197,6 +197,14 @@ CGLM_EXPORT void glmc_vec2_make(const float * __restrict src, vec2 dest); +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 f3ab653fd..b24529c73 100644 --- a/include/cglm/call/vec3.h +++ b/include/cglm/call/vec3.h @@ -334,6 +334,18 @@ 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_refract(vec3 I, vec3 N, float eta, vec3 dest); + #ifdef __cplusplus } #endif diff --git a/include/cglm/call/vec4.h b/include/cglm/call/vec4.h index 644facfaf..207bc794e 100644 --- a/include/cglm/call/vec4.h +++ b/include/cglm/call/vec4.h @@ -311,6 +311,14 @@ CGLM_EXPORT void glmc_vec4_make(const float * __restrict src, vec4 dest); +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/ray.h b/include/cglm/ray.h index ced1ad6af..38e171a41 100644 --- a/include/cglm/ray.h +++ b/include/cglm/ray.h @@ -7,12 +7,18 @@ /* Functions: - CGLM_INLINE bool glm_line_triangle_intersect(vec3 origin, - vec3 direction, - vec3 v0, - vec3 v1, - vec3 v2, - float *d); + CGLM_INLINE bool glm_ray_triangle(vec3 origin, + vec3 direction, + vec3 v0, + vec3 v1, + vec3 v2, + float *d); + CGLM_INLINE bool glm_ray_sphere(vec3 origin, + vec3 dir, + vec4 s, + float * __restrict t1, + float * __restrict t2) + CGLM_INLINE void glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point); */ #ifndef cglm_ray_h @@ -31,7 +37,6 @@ * @param[in, out] d distance to intersection * @return whether there is intersection */ - CGLM_INLINE bool glm_ray_triangle(vec3 origin, @@ -74,4 +79,93 @@ glm_ray_triangle(vec3 origin, return dist > epsilon; } +/*! + * @brief ray sphere intersection + * + * - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin + * - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2 + * - t1 < 0, t2 < 0: no intersection ahead of the ray + * - the caller can check if the intersection points (t1 and t2) fall within a + * specific range (for example, tmin < t1, t2 < tmax) to determine if the + * intersections are within a desired segment of the ray + * + * @param[in] origin ray origin + * @param[out] dir normalized ray direction + * @param[in] s sphere [center.x, center.y, center.z, radii] + * @param[in] t1 near point1 (closer to origin) + * @param[in] t2 far point2 (farther from origin) + */ +CGLM_INLINE +bool +glm_ray_sphere(vec3 origin, + vec3 dir, + vec4 s, + float * __restrict t1, + float * __restrict t2) { + vec3 dp; + float r2, ddp, dpp, dscr, q, tmp, _t1, _t2; + + /* ensure dir is normalized */ + glm_vec3_sub(s, origin, dp); + + ddp = glm_vec3_dot(dir, dp); + dpp = glm_vec3_norm2(dp); + + /* compute the remedy term for numerical stability */ + glm_vec3_mulsubs(dir, ddp, dp); /* dp: remedy term */ + + r2 = s[3] * s[3]; + dscr = r2 - glm_vec3_norm2(dp); + + if (dscr < 0.0f) { + /* no intersection */ + return false; + } + + dscr = sqrtf(dscr); + q = (ddp >= 0.0f) ? (ddp + dscr) : (ddp - dscr); + + /* + include Press, William H., Saul A. Teukolsky, + William T. Vetterling, and Brian P. Flannery, + "Numerical Recipes in C," Cambridge University Press, 1992. + */ + _t1 = q; + _t2 = (dpp - r2) / q; + + /* adjust t1 and t2 to ensure t1 is the closer intersection */ + if (_t1 > _t2) { + tmp = _t1; + _t1 = _t2; + _t2 = tmp; + } + + *t1 = _t1; + *t2 = _t2; + + /* check if the closest intersection (t1) is behind the ray's origin */ + if (_t1 < 0.0f && _t2 < 0.0f) { + /* both intersections are behind the ray, no visible intersection */ + return false; + } + + return true; +} + +/*! + * @brief point using t by 𝐏(𝑡)=𝐀+𝑡𝐛 + * + * @param[in] orig origin of ray + * @param[in] dir direction of ray + * @param[in] t parameter + * @param[out] point point at t + */ +CGLM_INLINE +void +glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point) { + vec3 dst; + glm_vec3_scale(dir, t, dst); + glm_vec3_add(orig, dst, point); +} + #endif diff --git a/include/cglm/struct.h b/include/cglm/struct.h index 030f45a5b..1426589da 100644 --- a/include/cglm/struct.h +++ b/include/cglm/struct.h @@ -41,6 +41,7 @@ extern "C" { #include "struct/sphere.h" #include "struct/curve.h" #include "struct/affine2d.h" +#include "struct/ray.h" #ifdef __cplusplus } diff --git a/include/cglm/struct/ray.h b/include/cglm/struct/ray.h new file mode 100644 index 000000000..1341fe97a --- /dev/null +++ b/include/cglm/struct/ray.h @@ -0,0 +1,82 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglms_ray_h +#define cglms_ray_h + +#include "../common.h" +#include "../types-struct.h" +#include "../ray.h" + +/* api definition */ +#define glms_ray_(NAME) CGLM_STRUCTAPI(ray, NAME) + +/*! + * @brief Möller–Trumbore ray-triangle intersection algorithm + * + * @param[in] origin origin of ray + * @param[in] direction direction of ray + * @param[in] v0 first vertex of triangle + * @param[in] v1 second vertex of triangle + * @param[in] v2 third vertex of triangle + * @param[in, out] d distance to intersection + * @return whether there is intersection + */ +CGLM_INLINE +bool +glms_ray_(triangle)(vec3s origin, + vec3s direction, + vec3s v0, + vec3s v1, + vec3s v2, + float *d) { + return glm_ray_triangle(origin.raw, direction.raw, v0.raw, v1.raw, v2.raw, d); +} + +/*! + * @brief ray sphere intersection + * + * - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin + * - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2 + * - t1 < 0, t2 < 0: no intersection ahead of the ray + * - the caller can check if the intersection points (t1 and t2) fall within a + * specific range (for example, tmin < t1, t2 < tmax) to determine if the + * intersections are within a desired segment of the ray + * + * @param[in] origin ray origin + * @param[out] dir normalized ray direction + * @param[in] s sphere [center.x, center.y, center.z, radii] + * @param[in] t1 near point1 (closer to origin) + * @param[in] t2 far point2 (farther from origin) + */ +CGLM_INLINE +bool +glms_ray_(sphere)(vec3s origin, + vec3s dir, + vec4s s, + float * __restrict t1, + float * __restrict t2) { + return glm_ray_sphere(origin.raw, dir.raw, s.raw, t1, t2); +} + +/*! + * @brief point using t by 𝐏(𝑡)=𝐀+𝑡𝐛 + * + * @param[in] orig origin of ray + * @param[in] dir direction of ray + * @param[in] t parameter + * @returns point point at t + */ +CGLM_INLINE +vec3s +glms_ray_(at)(vec3s orig, vec3s dir, float t) { + vec3s r; + glm_ray_at(orig.raw, orig.raw, t, r.raw); + return r; +} + +#endif /* cglms_ray_h */ diff --git a/include/cglm/struct/vec2.h b/include/cglm/struct/vec2.h index 99db56a64..7a48bce76 100644 --- a/include/cglm/struct/vec2.h +++ b/include/cglm/struct/vec2.h @@ -54,6 +54,8 @@ CGLM_INLINE vec2s glms_vec2_clamp(vec2s v, float minVal, float maxVal) 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 @@ -691,4 +693,38 @@ glms_vec2_(make)(const float * __restrict src) { return dest; } +/*! + * @brief reflection vector using an incident ray and a surface normal + * + * @param[in] I incident vector + * @param[in] N normalized normal vector + * @returns reflection result + */ +CGLM_INLINE +vec2s +glms_vec2_(reflect)(vec2s I, vec2s N) { + vec2s dest; + glm_vec2_reflect(I.raw, N.raw, dest.raw); + 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 2cd208f9a..3be409919 100644 --- a/include/cglm/struct/vec3.h +++ b/include/cglm/struct/vec3.h @@ -76,6 +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_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); @@ -1083,4 +1086,56 @@ 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 + * + * @param[in] I incident vector + * @param[in] N normalized normal vector + * @returns reflection result + */ +CGLM_INLINE +vec3s +glms_vec3_(reflect)(vec3s I, vec3s N) { + vec3s dest; + glm_vec3_reflect(I.raw, N.raw, dest.raw); + 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_(refract)(vec3s I, vec3s N, float eta) { + vec3s dest; + glm_vec3_refract(I.raw, N.raw, eta, dest.raw); + return dest; +} + #endif /* cglms_vec3s_h */ diff --git a/include/cglm/struct/vec4.h b/include/cglm/struct/vec4.h index c4f200dfd..71e441fb0 100644 --- a/include/cglm/struct/vec4.h +++ b/include/cglm/struct/vec4.h @@ -67,6 +67,8 @@ CGLM_INLINE vec4s glms_vec4_cubic(float s); 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 @@ -927,4 +929,42 @@ glms_vec4_(make)(const float * __restrict src) { return dest; } +/*! + * @brief reflection vector using an incident ray and a surface normal + * + * @param[in] I incident vector + * @param[in] N normalized normal vector + * @returns reflection result + */ +CGLM_INLINE +vec4s +glms_vec4_(reflect)(vec4s I, vec4s N) { + vec4s dest; + glm_vec4_reflect(I.raw, N.raw, dest.raw); + 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 5abf61672..58878f551 100644 --- a/include/cglm/vec2.h +++ b/include/cglm/vec2.h @@ -55,7 +55,8 @@ CGLM_INLINE void glm_vec2_clamp(vec2 v, float minVal, float maxVal) 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 @@ -712,4 +713,48 @@ glm_vec2_make(const float * __restrict src, vec2 dest) { dest[0] = src[0]; dest[1] = src[1]; } +/*! + * @brief reflection vector using an incident ray and a surface normal + * + * @param[in] I incident vector + * @param[in] N normalized normal vector + * @param[out] dest destination vector for the reflection result + */ +CGLM_INLINE +void +glm_vec2_reflect(vec2 I, vec2 N, vec2 dest) { + vec2 temp; + glm_vec2_scale(N, 2.0f * glm_vec2_dot(I, N), temp); + 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 = 1.0f + eta * eta - eni * eni; + + if (k < 0.0f) { + glm_vec2_zero(dest); + return; + } + + glm_vec2_scale(I, eta, dest); + glm_vec2_mulsubs(N, eni + sqrtf(k), dest); +} + #endif /* cglm_vec2_h */ diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h index a53cd2850..b3dcfeab4 100644 --- a/include/cglm/vec3.h +++ b/include/cglm/vec3.h @@ -80,6 +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_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); @@ -1202,4 +1205,70 @@ 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 + * + * @param[in] I incident vector + * @param[in] N normalized normal vector + * @param[out] dest reflection result + */ +CGLM_INLINE +void +glm_vec3_reflect(vec3 I, vec3 N, vec3 dest) { + vec3 temp; + glm_vec3_scale(N, 2.0f * glm_vec3_dot(I, N), temp); + glm_vec3_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_vec3_refract(vec3 I, vec3 N, float eta, vec3 dest) { + float ndi, eni, k; + + ndi = glm_vec3_dot(N, I); + eni = eta * ndi; + k = 1.0f + eta * eta - eni * eni; + + if (k < 0.0f) { + glm_vec3_zero(dest); + return; + } + + glm_vec3_scale(I, eta, dest); + glm_vec3_mulsubs(N, eni + sqrtf(k), dest); +} + #endif /* cglm_vec3_h */ diff --git a/include/cglm/vec4.h b/include/cglm/vec4.h index 8dd5b8578..d8c2ea07e 100644 --- a/include/cglm/vec4.h +++ b/include/cglm/vec4.h @@ -65,6 +65,8 @@ CGLM_INLINE void glm_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest); 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 @@ -1304,4 +1306,56 @@ glm_vec4_make(const float * __restrict src, vec4 dest) { dest[2] = src[2]; dest[3] = src[3]; } +/*! + * @brief reflection vector using an incident ray and a surface normal + * + * @param[in] I incident vector + * @param[in] N normalized normal vector + * @param[out] dest destination vector for the reflection result + */ +CGLM_INLINE +void +glm_vec4_reflect(vec4 I, vec4 N, vec4 dest) { + vec4 temp; + + /* TODO: direct simd touch */ + glm_vec4_scale(N, 2.0f * glm_vec4_dot(I, N), temp); + glm_vec4_sub(I, temp, 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 = 1.0f + eta * eta - eni * eni; + + if (k < 0.0f) { + glm_vec4_zero(dest); + return; + } + + glm_vec4_scale(I, eta, dest); + glm_vec4_mulsubs(N, eni + sqrtf(k), dest); +} + #endif /* cglm_vec4_h */ diff --git a/src/ray.c b/src/ray.c index 973c05992..9592b83a5 100644 --- a/src/ray.c +++ b/src/ray.c @@ -9,5 +9,21 @@ glmc_ray_triangle(vec3 origin, vec3 v1, vec3 v2, float *d) { - return glm_ray_triangle(origin, direction, v0, v1, v2, d); + return glm_ray_triangle(origin, direction, v0, v1, v2, d); +} + +CGLM_EXPORT +bool +glmc_ray_sphere(vec3 origin, + vec3 dir, + vec4 s, + float * __restrict t1, + float * __restrict t2) { + return glm_ray_sphere(origin, dir, s, t1, t2); +} + +CGLM_EXPORT +void +glmc_ray_at(vec3 orig, vec3 dir, float t, vec3 point) { + glm_ray_at(orig, dir, t, point); } diff --git a/src/vec2.c b/src/vec2.c index 5a23ff57b..27716c4af 100644 --- a/src/vec2.c +++ b/src/vec2.c @@ -302,3 +302,15 @@ void glmc_vec2_make(const float * __restrict src, vec2 dest) { glm_vec2_make(src, dest); } + +CGLM_EXPORT +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 86660c83f..33f3bc477 100644 --- a/src/vec3.c +++ b/src/vec3.c @@ -459,3 +459,21 @@ void 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) { + glm_vec3_reflect(I, N, dest); +} + +CGLM_EXPORT +void +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 2fcd4ca37..be0cbbce0 100644 --- a/src/vec4.c +++ b/src/vec4.c @@ -423,3 +423,15 @@ void glmc_vec4_make(const float * __restrict src, vec4 dest) { glm_vec4_make(src, dest); } + +CGLM_EXPORT +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); +} diff --git a/test/src/test_ray.h b/test/src/test_ray.h index c1b0281bd..6f2bec508 100644 --- a/test/src/test_ray.h +++ b/test/src/test_ray.h @@ -32,3 +32,43 @@ TEST_IMPL(GLM_PREFIX, ray_triangle) { TEST_SUCCESS } + +TEST_IMPL(GLM_PREFIX, ray_sphere) { + vec4 sphere = {5.0f, 0.0f, 0.0f, 1.0f}; /* Sphere: center at (5, 0, 0) with radius 1 */ + float t1, t2; + bool hit; + + /* Case 1: Ray misses the sphere */ + hit = GLM(ray_sphere)((vec3){10.0f, 3.0f, 0.0f}, (vec3){1.0f, 0.0f, 0.0f}, sphere, &t1, &t2); + ASSERT(!hit); /* Expect no intersection */ + + /* Case 2: Ray starts inside the sphere */ + hit = GLM(ray_sphere)((vec3){5.0f, 0.5f, 0.0f}, (vec3){1.0f, 0.0f, 0.0f}, sphere, &t1, &t2); + ASSERT(hit); /* Expect an intersection */ + ASSERT(t1 < 0 && t2 > 0); /* Ray exits at t2 */ + + /* Case 3: Ray intersects the sphere from outside */ + hit = GLM(ray_sphere)((vec3){0.0f, 0.0f, 0.0f}, (vec3){1.0f, 0.0f, 0.0f}, sphere, &t1, &t2); + ASSERT(hit); /* Expect an intersection */ + ASSERT(t1 > 0 && t2 > 0); /* Intersections at t1 and t2 */ + + TEST_SUCCESS +} + +TEST_IMPL(GLM_PREFIX, ray_at) { + vec3 origin = {0.0f, 0.0f, 0.0f}; + vec3 direction = {1.0f, 1.0f, 1.0f}; /* Diagonal direction */ + float distance = sqrtf(3.0f); /* Distance along the ray; sqrt(3) for unit length due to direction normalization */ + vec3 result; + + /* Normalize the direction to ensure accurate distance measurement */ + glm_vec3_normalize(direction); + + GLM(ray_at)(origin, direction, distance, result); + ASSERT(fabsf(result[0] - 1.0f) <= 0.0000009); /* Expecting to be 1 unit along the x-axis */ + ASSERT(fabsf(result[1] - 1.0f) <= 0.0000009); /* Expecting to be 1 unit along the y-axis */ + ASSERT(fabsf(result[2] - 1.0f) <= 0.0000009); /* Expecting to be 1 unit along the z-axis */ + + TEST_SUCCESS +} + diff --git a/test/src/test_vec2.h b/test/src/test_vec2.h index aa75b1c0d..322316532 100644 --- a/test/src/test_vec2.h +++ b/test/src/test_vec2.h @@ -752,3 +752,70 @@ TEST_IMPL(GLM_PREFIX, vec2_make) { TEST_SUCCESS } + +TEST_IMPL(GLM_PREFIX, vec2_reflect) { + vec2 dest; + + /* Reflecting off a "horizontal" surface in 2D */ + vec2 I1 = {1.0f, -1.0f}; /* Incoming vector */ + vec2 N1 = {0.0f, 1.0f}; /* Normal vector */ + GLM(vec2_reflect)(I1, N1, dest); + ASSERT(fabsf(dest[0] - 1.0f) < 0.00001f && + fabsf(dest[1] - 1.0f) < 0.00001f); /* Expect reflection upwards */ + + /* Reflecting at an angle in 2D */ + vec2 I2 = {sqrtf(2)/2, -sqrtf(2)/2}; /* Incoming vector at 45 degrees */ + vec2 N2 = {0.0f, 1.0f}; /* Upwards normal vector */ + GLM(vec2_reflect)(I2, N2, dest); + ASSERT(fabsf(dest[0] - sqrtf(2)/2) < 0.00001f && + fabsf(dest[1] - sqrtf(2)/2) < 0.00001f); /* Expect reflection upwards */ + + /* Reflecting off a line in 2D representing a "vertical" surface analogy */ + vec2 I3 = {1.0f, 0.0f}; /* Incoming vector */ + vec2 N3 = {-1.0f, 0.0f}; /* Normal vector representing a "vertical" line */ + GLM(vec2_reflect)(I3, N3, dest); + ASSERT(fabsf(dest[0] + 1.0f) < 0.00001f && + fabsf(dest[1]) < 0.00001f); /* Expect reflection to the left */ + + TEST_SUCCESS +} + +TEST_IMPL(GLM_PREFIX, vec2_refract) { + vec2 I = {sqrtf(0.5f), -sqrtf(0.5f)}; /* Incoming vector at 45 degrees to normal */ + vec2 N = {0.0f, 1.0f}; /* Surface normal */ + vec2 dest; + float eta; + + /* Water to Air (eta = 1.33/1.0) */ + eta = 1.33f / 1.0f; + GLM(vec2_refract)(I, N, eta, dest); + // 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)) { + ASSERT(dest[1] < -sqrtf(0.5f)); // Refracted ray bends away from the normal + } else { + ASSERT(dest[0] == 0.0f && dest[1] == 0.0f); // Total internal reflection + } + + /* Air to Glass (eta = 1.0 / 1.5) */ + eta = 1.0f / 1.5f; + GLM(vec2_refract)(I, N, eta, dest); + ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal + + /* Glass to Water (eta = 1.5 / 1.33) */ + eta = 1.5f / 1.33f; + GLM(vec2_refract)(I, N, eta, dest); + 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) */ + eta = 2.42f / 1.0f; + GLM(vec2_refract)(I, N, eta, dest); + if (!(dest[0] == 0.0f && dest[1] == 0.0f)) { + /* High potential for total internal reflection, but if it occurs, expect significant bending */ + ASSERT(dest[1] < -sqrtf(0.5f)); + } else { + ASSERT(dest[0] == 0.0f && dest[1] == 0.0f); // Total internal reflection + } + + TEST_SUCCESS +} + diff --git a/test/src/test_vec3.h b/test/src/test_vec3.h index 65570c02f..6fe4df974 100644 --- a/test/src/test_vec3.h +++ b/test/src/test_vec3.h @@ -1840,3 +1840,89 @@ TEST_IMPL(GLM_PREFIX, vec3_make) { TEST_SUCCESS } + +TEST_IMPL(GLM_PREFIX, vec3_faceforward) { + vec3 N = {0.0f, 1.0f, 0.0f}; + vec3 I = {1.0f, -1.0f, 0.0f}; + vec3 Nref = {0.0f, -1.0f, 0.0f}; + vec3 dest; + + GLM(vec3_faceforward)(N, I, Nref, dest); + ASSERT(dest[0] == 0.0f + && dest[1] == -1.0f + && dest[2] == 0.0f); /* Expect N flipped */ + + TEST_SUCCESS +} + +TEST_IMPL(GLM_PREFIX, vec3_reflect) { + vec3 dest; + + /* Original test: Reflecting off a horizontal surface */ + vec3 I1 = {1.0f, -1.0f, 0.0f}; /* Incoming vector */ + vec3 N1 = {0.0f, 1.0f, 0.0f}; /* Normal vector */ + GLM(vec3_reflect)(I1, N1, dest); + ASSERT(fabsf(dest[0] - 1.0f) < 0.00001f + && fabsf(dest[1] - 1.0f) < 0.00001f + && fabsf(dest[2] - 0.0f) < 0.00001f); /* Expect reflection */ + + /* Scenario 2: Reflecting off a vertical surface */ + vec3 I2 = {1.0f, 0.0f, 0.0f}; /* Incoming vector */ + vec3 N2 = {-1.0f, 0.0f, 0.0f}; /* Normal vector */ + GLM(vec3_reflect)(I2, N2, dest); + ASSERT(fabsf(dest[0] + 1.0f) < 0.00001f + && fabsf(dest[1]) < 0.00001f + && fabsf(dest[2]) < 0.00001f); /* Expect reflection to the left */ + + /* Scenario 3: Reflecting at an angle */ + vec3 I3 = {sqrtf(2)/2, -sqrtf(2)/2, 0.0f}; /* Incoming vector at 45 degrees */ + vec3 N3 = {0.0f, 1.0f, 0.0f}; /* Upwards normal vector */ + GLM(vec3_reflect)(I3, N3, dest); + ASSERT(fabsf(dest[0] - sqrtf(2)/2) < 0.00001f + && fabsf(dest[1] - sqrtf(2)/2) < 0.00001f + && fabsf(dest[2]) < 0.00001f); /* Expect reflection upwards */ + + TEST_SUCCESS +} + +TEST_IMPL(GLM_PREFIX, vec3_refract) { + vec3 I = {sqrtf(0.5f), -sqrtf(0.5f), 0.0f}; /* Incoming vector at 45 degrees to normal */ + vec3 N = {0.0f, 1.0f, 0.0f}; /* Surface normal */ + vec3 dest; + float eta; + + /* Water to Air (eta = 1.33/1.0) */ + eta = 1.33f / 1.0f; + GLM(vec3_refract)(I, N, eta, dest); + if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f)) { + ASSERT(dest[1] < -sqrtf(0.5f)); + } else { + ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f); + } + + /* Air to Glass (eta = 1.0 / 1.5) */ + eta = 1.0f / 1.5f; + GLM(vec3_refract)(I, N, eta, dest); + + /* Expect bending towards the normal */ + ASSERT(dest[1] < -sqrtf(0.5f)); + + /* Glass to Water (eta = 1.5 / 1.33) */ + eta = 1.5f / 1.33f; + GLM(vec3_refract)(I, N, eta, dest); + + /* Expect bending towards the normal, less bending than air to glass */ + ASSERT(dest[1] < -sqrtf(0.5f)); + + /* Diamond to Air (eta = 2.42 / 1.0) */ + eta = 2.42f / 1.0f; + GLM(vec3_refract)(I, N, eta, dest); + 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 */ + ASSERT(dest[1] < -sqrtf(0.5f)); + } else { + ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f); + } + + TEST_SUCCESS +} diff --git a/test/src/test_vec4.h b/test/src/test_vec4.h index cf73b67d3..4df471c6a 100644 --- a/test/src/test_vec4.h +++ b/test/src/test_vec4.h @@ -1536,3 +1536,75 @@ TEST_IMPL(GLM_PREFIX, vec4_make) { TEST_SUCCESS } + +TEST_IMPL(GLM_PREFIX, vec4_reflect) { + vec4 dest; + + /* Original test: Reflecting off a horizontal surface */ + vec4 I1 = {1.0f, -1.0f, 0.0f, 0.0f}; /* Incoming vector */ + vec4 N1 = {0.0f, 1.0f, 0.0f, 0.0f}; /* Normal vector */ + GLM(vec4_reflect)(I1, N1, dest); + ASSERT(fabsf(dest[0] - 1.0f) < 0.00001f && + fabsf(dest[1] - 1.0f) < 0.00001f && + fabsf(dest[2] - 0.0f) < 0.00001f && + fabsf(dest[3] - 0.0f) < 0.00001f); /* Expect reflection */ + + /* Scenario 2: Reflecting off a vertical surface */ + vec4 I2 = {1.0f, 0.0f, 0.0f, 0.0f}; /* Incoming vector */ + vec4 N2 = {-1.0f, 0.0f, 0.0f, 0.0f}; /* Normal vector */ + GLM(vec4_reflect)(I2, N2, dest); + ASSERT(fabsf(dest[0] + 1.0f) < 0.00001f && + fabsf(dest[1]) < 0.00001f && + fabsf(dest[2]) < 0.00001f && + fabsf(dest[3] - 0.0f) < 0.00001f); /* Expect reflection to the left */ + + /* Scenario 3: Reflecting at an angle */ + vec4 I3 = {sqrtf(2)/2, -sqrtf(2)/2, 0.0f, 0.0f}; /* Incoming vector at 45 degrees */ + vec4 N3 = {0.0f, 1.0f, 0.0f, 0.0f}; /* Upwards normal vector */ + GLM(vec4_reflect)(I3, N3, dest); + ASSERT(fabsf(dest[0] - sqrtf(2)/2) < 0.00001f && + fabsf(dest[1] - sqrtf(2)/2) < 0.00001f && + fabsf(dest[2]) < 0.00001f && + fabsf(dest[3] - 0.0f) < 0.00001f); /* Expect reflection upwards */ + + TEST_SUCCESS +} + +TEST_IMPL(GLM_PREFIX, vec4_refract) { + vec4 I = {sqrtf(0.5f), -sqrtf(0.5f), 0.0f, 0.0f}; /* Incoming vector */ + vec4 N = {0.0f, 1.0f, 0.0f, 0.0f}; /* Surface normal */ + vec4 dest; + float eta; + + /* Water to Air (eta = 1.33/1.0) */ + eta = 1.33f / 1.0f; + GLM(vec4_refract)(I, N, eta, dest); + if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f)) { + ASSERT(dest[1] < -sqrtf(0.5f)); + } else { + ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f); + } + + /* Air to Glass (eta = 1.0 / 1.5) */ + eta = 1.0f / 1.5f; + GLM(vec4_refract)(I, N, eta, dest); + ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal + + /* Glass to Water (eta = 1.5 / 1.33) */ + eta = 1.5f / 1.33f; + GLM(vec4_refract)(I, N, eta, dest); + 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) */ + eta = 2.42f / 1.0f; + GLM(vec4_refract)(I, N, eta, dest); + 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 */ + ASSERT(dest[1] < -sqrtf(0.5f)); + } else { + ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f); + } + + TEST_SUCCESS +} + diff --git a/test/tests.h b/test/tests.h index e9509bdef..d85a15596 100644 --- a/test/tests.h +++ b/test/tests.h @@ -392,7 +392,12 @@ TEST_DECLARE(euler) /* ray */ TEST_DECLARE(glm_ray_triangle) +TEST_DECLARE(glm_ray_sphere) +TEST_DECLARE(glm_ray_at) + TEST_DECLARE(glmc_ray_triangle) +TEST_DECLARE(glmc_ray_sphere) +TEST_DECLARE(glmc_ray_at) /* quat */ TEST_DECLARE(MACRO_GLM_QUAT_IDENTITY_INIT) @@ -530,6 +535,8 @@ TEST_DECLARE(glm_vec2_lerp) TEST_DECLARE(glm_vec2_complex_mul) TEST_DECLARE(glm_vec2_complex_div) TEST_DECLARE(glm_vec2_make) +TEST_DECLARE(glm_vec2_reflect) +TEST_DECLARE(glm_vec2_refract) TEST_DECLARE(glmc_vec2) TEST_DECLARE(glmc_vec2_copy) @@ -576,6 +583,8 @@ TEST_DECLARE(glmc_vec2_lerp) TEST_DECLARE(glmc_vec2_complex_mul) TEST_DECLARE(glmc_vec2_complex_div) TEST_DECLARE(glmc_vec2_make) +TEST_DECLARE(glmc_vec2_reflect) +TEST_DECLARE(glmc_vec2_refract) /* vec3 */ TEST_DECLARE(MACRO_GLM_VEC3_ONE_INIT) @@ -678,6 +687,9 @@ TEST_DECLARE(glm_vec3_fract) TEST_DECLARE(glm_vec3_hadd) TEST_DECLARE(glm_vec3_sqrt) TEST_DECLARE(glm_vec3_make) +TEST_DECLARE(glm_vec3_faceforward) +TEST_DECLARE(glm_vec3_reflect) +TEST_DECLARE(glm_vec3_refract) TEST_DECLARE(glmc_vec3) TEST_DECLARE(glmc_vec3_copy) @@ -754,6 +766,9 @@ TEST_DECLARE(glmc_vec3_fract) TEST_DECLARE(glmc_vec3_hadd) TEST_DECLARE(glmc_vec3_sqrt) TEST_DECLARE(glmc_vec3_make) +TEST_DECLARE(glmc_vec3_faceforward) +TEST_DECLARE(glmc_vec3_reflect) +TEST_DECLARE(glmc_vec3_refract) /* vec4 */ TEST_DECLARE(MACRO_GLM_VEC4_ONE_INIT) @@ -842,6 +857,8 @@ TEST_DECLARE(glm_vec4_fract) TEST_DECLARE(glm_vec4_hadd) TEST_DECLARE(glm_vec4_sqrt) TEST_DECLARE(glm_vec4_make) +TEST_DECLARE(glm_vec4_reflect) +TEST_DECLARE(glm_vec4_refract) TEST_DECLARE(glmc_vec4) TEST_DECLARE(glmc_vec4_copy3) @@ -914,6 +931,8 @@ TEST_DECLARE(glmc_vec4_fract) TEST_DECLARE(glmc_vec4_hadd) TEST_DECLARE(glmc_vec4_sqrt) TEST_DECLARE(glmc_vec4_make) +TEST_DECLARE(glmc_vec4_reflect) +TEST_DECLARE(glmc_vec4_refract) /* ivec2 */ TEST_DECLARE(glm_ivec2) @@ -1548,10 +1567,15 @@ TEST_LIST { TEST_ENTRY(glmc_euler_zyx_quat_lh) TEST_ENTRY(euler) - + /* ray */ TEST_ENTRY(glm_ray_triangle) + TEST_ENTRY(glm_ray_sphere) + TEST_ENTRY(glm_ray_at) + TEST_ENTRY(glmc_ray_triangle) + TEST_ENTRY(glmc_ray_sphere) + TEST_ENTRY(glmc_ray_at) /* quat */ TEST_ENTRY(MACRO_GLM_QUAT_IDENTITY_INIT) @@ -1688,6 +1712,8 @@ TEST_LIST { TEST_ENTRY(glm_vec2_complex_mul) TEST_ENTRY(glm_vec2_complex_div) TEST_ENTRY(glm_vec2_make) + TEST_ENTRY(glm_vec2_reflect) + TEST_ENTRY(glm_vec2_refract) TEST_ENTRY(glmc_vec2) TEST_ENTRY(glmc_vec2_copy) @@ -1734,6 +1760,8 @@ TEST_LIST { TEST_ENTRY(glmc_vec2_complex_mul) TEST_ENTRY(glmc_vec2_complex_div) TEST_ENTRY(glmc_vec2_make) + TEST_ENTRY(glmc_vec2_reflect) + TEST_ENTRY(glmc_vec2_refract) /* vec3 */ TEST_ENTRY(MACRO_GLM_VEC3_ONE_INIT) @@ -1835,6 +1863,9 @@ TEST_LIST { TEST_ENTRY(glm_vec3_hadd) TEST_ENTRY(glm_vec3_sqrt) TEST_ENTRY(glm_vec3_make) + TEST_ENTRY(glm_vec3_faceforward) + TEST_ENTRY(glm_vec3_reflect) + TEST_ENTRY(glm_vec3_refract) TEST_ENTRY(glmc_vec3) TEST_ENTRY(glmc_vec3_copy) @@ -1911,6 +1942,9 @@ TEST_LIST { TEST_ENTRY(glmc_vec3_hadd) TEST_ENTRY(glmc_vec3_sqrt) TEST_ENTRY(glmc_vec3_make) + TEST_ENTRY(glmc_vec3_faceforward) + TEST_ENTRY(glmc_vec3_reflect) + TEST_ENTRY(glmc_vec3_refract) /* vec4 */ TEST_ENTRY(MACRO_GLM_VEC4_ONE_INIT) @@ -1999,6 +2033,8 @@ TEST_LIST { TEST_ENTRY(glm_vec4_hadd) TEST_ENTRY(glm_vec4_sqrt) TEST_ENTRY(glm_vec4_make) + TEST_ENTRY(glm_vec4_reflect) + TEST_ENTRY(glm_vec4_refract) TEST_ENTRY(glmc_vec4) TEST_ENTRY(glmc_vec4_copy3) @@ -2071,6 +2107,8 @@ TEST_LIST { TEST_ENTRY(glmc_vec4_hadd) TEST_ENTRY(glmc_vec4_sqrt) TEST_ENTRY(glmc_vec4_make) + TEST_ENTRY(glmc_vec4_reflect) + TEST_ENTRY(glmc_vec4_refract) /* ivec2 */ TEST_ENTRY(glm_ivec2) diff --git a/win/cglm.vcxproj b/win/cglm.vcxproj index 949c994f6..dcca926af 100644 --- a/win/cglm.vcxproj +++ b/win/cglm.vcxproj @@ -253,6 +253,7 @@ + diff --git a/win/cglm.vcxproj.filters b/win/cglm.vcxproj.filters index 71143f5f7..f200fb29b 100644 --- a/win/cglm.vcxproj.filters +++ b/win/cglm.vcxproj.filters @@ -729,5 +729,8 @@ include\cglm\struct + + include\cglm\struct + \ No newline at end of file