Implement g-truc#1370 (reflection matrix calculation)

- add reflect2D
- rewrite functions to accept an input matrix
- add tests
This commit is contained in:
mariob92
2025-12-07 23:42:06 +01:00
committed by Christophe
parent 5f9187f0f2
commit e282990dc0
4 changed files with 170 additions and 27 deletions

View File

@@ -57,10 +57,15 @@ namespace glm
// Identity + tan(angle) * cross(Normal, OnPlaneVector) 0
// - dot(PointOnPlane, normal) * OnPlaneVector 1
//! Build a reflection matrix.
//! Reflects a matrix on an arbitrary plane.
//! From GLM_GTX_transform2 extension.
template<typename T, qualifier Q>
GLM_FUNC_DECL mat<4, 4, T, Q> reflect3D(vec<3, T, Q> const& normal, T distance);
GLM_FUNC_DECL mat<3, 3, T, Q> reflect2D(mat<3, 3, T, Q> const& m, vec<2, T, Q> const& normal, T distance);
//! Reflects a matrix on an arbitrary plane.
//! From GLM_GTX_transform2 extension.
template<typename T, qualifier Q>
GLM_FUNC_DECL mat<4, 4, T, Q> reflect3D(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& normal, T distance);
//! Build planar projection matrix along normal axis.
//! From GLM_GTX_transform2 extension.

View File

@@ -45,34 +45,36 @@ namespace glm
return m * r;
}
// template<typename T, qualifier Q>
// GLM_FUNC_QUALIFIER mat<3, 3, T, Q> reflect2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal)
// {
// mat<3, 3, T, Q> r(static_cast<T>(1));
// r[0][0] = static_cast<T>(1) - static_cast<T>(2) * normal.x * normal.x;
// r[0][1] = -static_cast<T>(2) * normal.x * normal.y;
// r[1][0] = -static_cast<T>(2) * normal.x * normal.y;
// r[1][1] = static_cast<T>(1) - static_cast<T>(2) * normal.y * normal.y;
// return m * r;
// }
template<typename T, qualifier Q>
GLM_FUNC_QUALIFIER mat<3, 3, T, Q> reflect2D(mat<3, 3, T, Q> const& m, vec<2, T, Q> const& normal, T distance)
{
mat<3, 3, T, Q> r(static_cast<T>(1));
r[0][0] = static_cast<T>(1) - static_cast<T>(2) * normal.x * normal.x;
r[0][1] = -static_cast<T>(2) * normal.y * normal.x;
r[1][0] = -static_cast<T>(2) * normal.x * normal.y;
r[1][1] = static_cast<T>(1) - static_cast<T>(2) * normal.y * normal.y;
r[2][0] = -static_cast<T>(2) * normal.x * distance;
r[2][1] = -static_cast<T>(2) * normal.y * distance;
return m * r;
}
template<typename T, qualifier Q>
GLM_FUNC_DECL mat<4, 4, T, Q> reflect3D(vec<3, T, Q> const& normal, T distance)
GLM_FUNC_QUALIFIER mat<4, 4, T, Q> reflect3D(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& normal, T distance)
{
mat<4, 4, T, Q> result(static_cast<T>(1));
result[0][0] = static_cast<T>(1) - static_cast<T>(2) * normal.x * normal.x;
result[0][1] = -static_cast<T>(2) * normal.y * normal.x;
result[0][2] = -static_cast<T>(2) * normal.z * normal.x;
result[1][0] = -static_cast<T>(2) * normal.x * normal.y;
result[1][1] = static_cast<T>(1) - static_cast<T>(2) * normal.y * normal.y;
result[1][2] = -static_cast<T>(2) * normal.z * normal.y;
result[2][0] = -static_cast<T>(2) * normal.x * normal.z;
result[2][1] = -static_cast<T>(2) * normal.y * normal.z;
result[2][2] = static_cast<T>(1) - static_cast<T>(2) * normal.z * normal.z;
result[3][0] = -static_cast<T>(2) * normal.x * distance;
result[3][1] = -static_cast<T>(2) * normal.y * distance;
result[3][2] = -static_cast<T>(2) * normal.z * distance;
return result;
mat<4, 4, T, Q> r(static_cast<T>(1));
r[0][0] = static_cast<T>(1) - static_cast<T>(2) * normal.x * normal.x;
r[0][1] = -static_cast<T>(2) * normal.y * normal.x;
r[0][2] = -static_cast<T>(2) * normal.z * normal.x;
r[1][0] = -static_cast<T>(2) * normal.x * normal.y;
r[1][1] = static_cast<T>(1) - static_cast<T>(2) * normal.y * normal.y;
r[1][2] = -static_cast<T>(2) * normal.z * normal.y;
r[2][0] = -static_cast<T>(2) * normal.x * normal.z;
r[2][1] = -static_cast<T>(2) * normal.y * normal.z;
r[2][2] = static_cast<T>(1) - static_cast<T>(2) * normal.z * normal.z;
r[3][0] = -static_cast<T>(2) * normal.x * distance;
r[3][1] = -static_cast<T>(2) * normal.y * distance;
r[3][2] = -static_cast<T>(2) * normal.z * distance;
return m * r;
}
template<typename T, qualifier Q>

View File

@@ -53,6 +53,7 @@ glmCreateTestGTC(gtx_spline)
glmCreateTestGTC(gtx_string_cast)
glmCreateTestGTC(gtx_structured_bindings)
glmCreateTestGTC(gtx_texture)
glmCreateTestGTC(gtx_transform2)
glmCreateTestGTC(gtx_type_aligned)
glmCreateTestGTC(gtx_type_trait)
glmCreateTestGTC(gtx_vec_swizzle)

135
test/gtx/gtx_transform2.cpp Normal file
View File

@@ -0,0 +1,135 @@
#include <glm/glm.hpp>
#include <glm/gtc/epsilon.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/transform2.hpp>
static int test_reflect2D()
{
int Error = 0;
{
const glm::mat3 m3(
1, 0, 0,
0, 1, 0,
1, 2, 1
);
const glm::mat3 eam3(
1, 0, 0,
0, -1, 0,
1, 2, 1
);
const glm::mat3 am3 = glm::reflect2D(
m3,
glm::vec2(0, 1),
static_cast<glm::mat3::row_type::value_type>(0)
);
Error += glm::all(glm::bvec3(
glm::all(glm::epsilonEqual(eam3[0], am3[0], glm::epsilon<float>())),
glm::all(glm::epsilonEqual(eam3[1], am3[1], glm::epsilon<float>())),
glm::all(glm::epsilonEqual(eam3[2], am3[2], glm::epsilon<float>())))) ? 0 : 1;
}
{
const glm::mat3 m3(
1, 0, 0,
0, 1, 0,
1, 2, 1
);
const glm::mat3 eam3(
0, 1, 0,
1, 0, 0,
1, 2, 1
);
const glm::mat3 am3 = glm::reflect2D(
m3,
glm::vec2(-0.70710678, 0.70710678),
static_cast<glm::mat3::row_type::value_type>(0)
);
Error += glm::all(glm::bvec3(
glm::all(glm::epsilonEqual(eam3[0], am3[0], glm::epsilon<float>())),
glm::all(glm::epsilonEqual(eam3[1], am3[1], glm::epsilon<float>())),
glm::all(glm::epsilonEqual(eam3[2], am3[2], glm::epsilon<float>())))) ? 0 : 1;
}
return Error;
}
static int test_reflect3D()
{
int Error = 0;
{
const glm::mat4 m4(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
const glm::mat4 eam4(
1, 0, 0, 0,
0, -1, 0, 0,
0, 0, 1, 0,
0, -2, 0, 1
);
const glm::mat4 am4 = glm::reflect3D(
m4,
glm::vec3(0, 1, 0),
static_cast<glm::mat4::row_type::value_type>(1)
);
Error += glm::all(glm::bvec4(
glm::all(glm::epsilonEqual(eam4[0], am4[0], glm::epsilon<float>())),
glm::all(glm::epsilonEqual(eam4[1], am4[1], glm::epsilon<float>())),
glm::all(glm::epsilonEqual(eam4[2], am4[2], glm::epsilon<float>())),
glm::all(glm::epsilonEqual(eam4[3], am4[3], glm::epsilon<float>())))) ? 0 : 1;
}
{
const glm::mat4 m4(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
const glm::mat4 eam4(
0, 1, 0, 0,
1, 0, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
const glm::mat4 am4 = glm::reflect3D(
m4,
glm::vec3(-0.70710678, 0.70710678, 0.0),
static_cast<glm::mat4::row_type::value_type>(0)
);
Error += glm::all(glm::bvec4(
glm::all(glm::epsilonEqual(eam4[0], am4[0], glm::epsilon<float>())),
glm::all(glm::epsilonEqual(eam4[1], am4[1], glm::epsilon<float>())),
glm::all(glm::epsilonEqual(eam4[2], am4[2], glm::epsilon<float>())),
glm::all(glm::epsilonEqual(eam4[3], am4[3], glm::epsilon<float>())))) ? 0 : 1;
}
return Error;
}
int main()
{
int Error = 0;
Error += test_reflect2D();
Error += test_reflect3D();
return Error;
}