diff --git a/headers/vmath.hpp/vmath_ext.hpp b/headers/vmath.hpp/vmath_ext.hpp index e23b103..156f01f 100644 --- a/headers/vmath.hpp/vmath_ext.hpp +++ b/headers/vmath.hpp/vmath_ext.hpp @@ -205,6 +205,9 @@ namespace vmath_hpp template < typename T > [[nodiscard]] constexpr mat translate(T x, T y, T z) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Translation_(geometry) + return { {1, 0, 0, 0}, {0, 1, 0, 0}, @@ -293,12 +296,18 @@ namespace vmath_hpp return m * rotate(angle, axis); } + template < typename T > + [[nodiscard]] mat rotate(const mat& m, const qua& q) { + return m * rotate(q); + } + template < typename T > [[nodiscard]] mat rotate_x(T angle) { /// REFERENCE: /// http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/ const auto [s, c] = sincos(angle); + return { 1, 0, 0, 0, 0, c, s, 0, @@ -317,6 +326,7 @@ namespace vmath_hpp /// http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/ const auto [s, c] = sincos(angle); + return { c, 0, -s, 0, 0, 1, 0, 0, @@ -335,6 +345,7 @@ namespace vmath_hpp /// http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/ const auto [s, c] = sincos(angle); + return { c, s, 0, 0, -s, c, 0, 0, @@ -351,6 +362,9 @@ namespace vmath_hpp template < typename T > [[nodiscard]] constexpr mat scale(T x, T y, T z) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Scaling_(geometry) + return { {x, 0, 0, 0}, {0, y, 0, 0}, @@ -377,6 +391,9 @@ namespace vmath_hpp template < typename T > [[nodiscard]] mat look_at_lh(const vec& eye, const vec& at, const vec& up) { + /// REFERENCE: + /// https://www.euclideanspace.com/maths/algebra/vectors/lookat/ + const vec az = normalize(at - eye); const vec ax = normalize(cross(up, az)); const vec ay = cross(az, ax); @@ -394,6 +411,9 @@ namespace vmath_hpp template < typename T > [[nodiscard]] mat look_at_rh(const vec& eye, const vec& at, const vec& up) { + /// REFERENCE: + /// https://www.euclideanspace.com/maths/algebra/vectors/lookat/ + const vec az = normalize(eye - at); const vec ax = normalize(cross(up, az)); const vec ay = cross(az, ax); @@ -420,6 +440,9 @@ namespace vmath_hpp template < typename T > [[nodiscard]] constexpr mat translate(T x, T y) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Translation_(geometry) + return { {1, 0, 0}, {0, 1, 0}, @@ -445,7 +468,11 @@ namespace vmath_hpp template < typename T > [[nodiscard]] mat rotate(T angle) { + /// REFERENCE: + /// http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/ + const auto [s, c] = sincos(angle); + return { c, s, 0, -s, c, 0, @@ -461,6 +488,9 @@ namespace vmath_hpp template < typename T > [[nodiscard]] constexpr mat scale(T x, T y) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Scaling_(geometry) + return { {x, 0, 0}, {0, y, 0}, @@ -486,6 +516,9 @@ namespace vmath_hpp template < typename T > [[nodiscard]] constexpr mat shear(T x, T y) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Shear_matrix + return { {1, y, 0}, {x, 1, 0}, @@ -508,29 +541,35 @@ namespace vmath_hpp } template < typename T > - [[nodiscard]] constexpr mat shear_x(T y) { + [[nodiscard]] constexpr mat shear_x(T x) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Shear_matrix + return { {1, 0, 0}, - {y, 1, 0}, + {x, 1, 0}, {0, 0, 1}}; } template < typename T > - [[nodiscard]] constexpr mat shear_x(const mat& m, T y) { - return m * shear_x(y); + [[nodiscard]] constexpr mat shear_x(const mat& m, T x) { + return m * shear_x(x); } template < typename T > - [[nodiscard]] constexpr mat shear_y(T x) { + [[nodiscard]] constexpr mat shear_y(T y) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Shear_matrix + return { - {1, x, 0}, + {1, y, 0}, {0, 1, 0}, {0, 0, 1}}; } template < typename T > - [[nodiscard]] constexpr mat shear_y(const mat& m, T x) { - return m * shear_y(x); + [[nodiscard]] constexpr mat shear_y(const mat& m, T y) { + return m * shear_y(y); } } @@ -544,13 +583,16 @@ namespace vmath_hpp template < typename T > [[nodiscard]] mat orthographic_lh_zo(T left, T right, T bottom, T top, T znear, T zfar) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Orthographic_projection + const T sx = T(2) * rcp(right - left); const T sy = T(2) * rcp(top - bottom); const T sz = T(1) * rcp(zfar - znear); - const T tx = - (right + left) / (right - left); - const T ty = - (top + bottom) / (top - bottom); - const T tz = - znear / (zfar - znear); + const T tx = - (right + left) * rcp(right - left); + const T ty = - (top + bottom) * rcp(top - bottom); + const T tz = - znear * rcp(zfar - znear); return { sx, 0, 0, 0, @@ -561,13 +603,16 @@ namespace vmath_hpp template < typename T > [[nodiscard]] mat orthographic_lh_no(T left, T right, T bottom, T top, T znear, T zfar) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Orthographic_projection + const T sx = T(2) * rcp(right - left); const T sy = T(2) * rcp(top - bottom); const T sz = T(2) * rcp(zfar - znear); - const T tx = - (right + left) / (right - left); - const T ty = - (top + bottom) / (top - bottom); - const T tz = - (zfar + znear) / (zfar - znear); + const T tx = - (right + left) * rcp(right - left); + const T ty = - (top + bottom) * rcp(top - bottom); + const T tz = - (zfar + znear) * rcp(zfar - znear); return { sx, 0, 0, 0, @@ -578,13 +623,16 @@ namespace vmath_hpp template < typename T > [[nodiscard]] mat orthographic_rh_zo(T left, T right, T bottom, T top, T znear, T zfar) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Orthographic_projection + const T sx = T(2) * rcp(right - left); const T sy = T(2) * rcp(top - bottom); const T sz = -T(1) * rcp(zfar - znear); - const T tx = - (right + left) / (right - left); - const T ty = - (top + bottom) / (top - bottom); - const T tz = - znear / (zfar - znear); + const T tx = - (right + left) * rcp(right - left); + const T ty = - (top + bottom) * rcp(top - bottom); + const T tz = - znear * rcp(zfar - znear); return { sx, 0, 0, 0, @@ -595,13 +643,16 @@ namespace vmath_hpp template < typename T > [[nodiscard]] mat orthographic_rh_no(T left, T right, T bottom, T top, T znear, T zfar) { + /// REFERENCE: + /// https://en.wikipedia.org/wiki/Orthographic_projection + const T sx = T(2) * rcp(right - left); const T sy = T(2) * rcp(top - bottom); const T sz = -T(2) * rcp(zfar - znear); - const T tx = - (right + left) / (right - left); - const T ty = - (top + bottom) / (top - bottom); - const T tz = - (zfar + znear) / (zfar - znear); + const T tx = - (right + left) * rcp(right - left); + const T ty = - (top + bottom) * rcp(top - bottom); + const T tz = - (zfar + znear) * rcp(zfar - znear); return { sx, 0, 0, 0, @@ -824,6 +875,7 @@ namespace vmath_hpp const auto [s, c] = sincos(angle * T(0.5)); const auto [x, y, z] = normalize(axis); + return {vec{x,y,z} * s, c}; } @@ -834,7 +886,11 @@ namespace vmath_hpp template < typename T > [[nodiscard]] qua qrotate_x(T angle) { + /// REFERENCE: + /// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/ + const auto [s, c] = sincos(angle * T(0.5)); + return {s, T(0), T(0), c}; } @@ -845,7 +901,11 @@ namespace vmath_hpp template < typename T > [[nodiscard]] qua qrotate_y(T angle) { + /// REFERENCE: + /// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/ + const auto [s, c] = sincos(angle * T(0.5)); + return {T(0), s, T(0), c}; } @@ -856,7 +916,11 @@ namespace vmath_hpp template < typename T > [[nodiscard]] qua qrotate_z(T angle) { + /// REFERENCE: + /// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/ + const auto [s, c] = sincos(angle * T(0.5)); + return {T(0), T(0), s, c}; } @@ -869,6 +933,9 @@ namespace vmath_hpp template < typename T > [[nodiscard]] qua qlook_at_lh(const vec& dir, const vec& up) { + /// REFERENCE: + /// https://www.euclideanspace.com/maths/algebra/vectors/lookat/ + const vec az = normalize(dir); const vec ax = normalize(cross(up, az)); const vec ay = cross(az, ax); @@ -881,6 +948,9 @@ namespace vmath_hpp template < typename T > [[nodiscard]] qua qlook_at_rh(const vec& dir, const vec& up) { + /// REFERENCE: + /// https://www.euclideanspace.com/maths/algebra/vectors/lookat/ + const vec az = normalize(-dir); const vec ax = normalize(cross(up, az)); const vec ay = cross(az, ax); diff --git a/untests/vmath_ext_tests.cpp b/untests/vmath_ext_tests.cpp index f76d74f..31667b0 100644 --- a/untests/vmath_ext_tests.cpp +++ b/untests/vmath_ext_tests.cpp @@ -225,10 +225,12 @@ TEST_CASE("vmath/ext") { REQUIRE(float3(2.f,3.f,1.f) * rotate(pi) == uapprox3(-2.f,-3.f,1.f)); REQUIRE(float4(2.f,3.f,4.f,1.f) * rotate(pi,{0.f,0.f,1.f}) == uapprox4(-2.f,-3.f,4.f,1.f)); REQUIRE(float4(2.f,3.f,4.f,1.f) * rotate(pi,float3{0.f,0.f,1.f}) == uapprox4(-2.f,-3.f,4.f,1.f)); + REQUIRE(float4(2.f,3.f,4.f,1.f) * rotate(qrotate(pi,float3{0.f,0.f,1.f})) == uapprox4(-2.f,-3.f,4.f,1.f)); REQUIRE(float3(2.f,3.f,1.f) * rotate(rotate(pi_2),pi_2) == uapprox3(-2.f,-3.f,1.f)); REQUIRE(float4(2.f,3.f,4.f,1.f) * rotate(rotate(pi_2,{0.f,0.f,1.f}),pi_2,{0.f,0.f,1.f}) == uapprox4(-2.f,-3.f,4.f,1.f)); REQUIRE(float4(2.f,3.f,4.f,1.f) * rotate(rotate(pi_2,float3{0.f,0.f,1.f}),pi_2,float3{0.f,0.f,1.f}) == uapprox4(-2.f,-3.f,4.f,1.f)); + REQUIRE(float4(2.f,3.f,4.f,1.f) * rotate(rotate(qrotate(pi_2,float3{0.f,0.f,1.f})),qrotate(pi_2,float3{0.f,0.f,1.f})) == uapprox4(-2.f,-3.f,4.f,1.f)); } SECTION("matrix scale") { @@ -244,32 +246,60 @@ TEST_CASE("vmath/ext") { SECTION("matrix shear") { STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_x(0.f) == uapprox3(2.f,3.f,1.f)); STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_x(1.f) == uapprox3(5.f,3.f,1.f)); + STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_x(2.f) == uapprox3(8.f,3.f,1.f)); STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_x(shear_x(1.f),1.f) == uapprox3(8.f,3.f,1.f)); STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_y(0.f) == uapprox3(2.f,3.f,1.f)); STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_y(1.f) == uapprox3(2.f,5.f,1.f)); + STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_y(2.f) == uapprox3(2.f,7.f,1.f)); STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_y(shear_y(1.f),1.f) == uapprox3(2.f,7.f,1.f)); STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(float2(0.f,0.f)) == uapprox3(2.f,3.f,1.f)); - STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(float2(1.f,0.f)) == uapprox3(5.f,3.f,1.f)); - STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(float2(0.f,1.f)) == uapprox3(2.f,5.f,1.f)); + STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(float2(2.f,0.f)) == uapprox3(8.f,3.f,1.f)); + STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(float2(0.f,2.f)) == uapprox3(2.f,7.f,1.f)); STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(shear(float2(1.f,0.f)),float2(1.f,0.f)) == uapprox3(8.f,3.f,1.f)); STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(shear(float2(0.f,1.f)),float2(0.f,1.f)) == uapprox3(2.f,7.f,1.f)); } + SECTION("matrix orthographic") { + REQUIRE(all(approx( + orthographic_lh_no(100.f, 800.f, 50.f, 640.f, 5.f, 10.f), + orthographic_lh_zo(100.f, 800.f, 50.f, 640.f, 5.f, 10.f) * scale(1.f,1.f,2.f) * translate(0.f,0.f,-1.f)))); + + REQUIRE(all(approx( + orthographic_rh_no(100.f, 800.f, 50.f, 640.f, 5.f, 10.f), + orthographic_rh_zo(100.f, 800.f, 50.f, 640.f, 5.f, 10.f) * scale(1.f,1.f,2.f) * translate(0.f,0.f,-1.f)))); + + REQUIRE(all(approx( + orthographic_lh_no(100.f, 800.f, 50.f, 640.f, 5.f, 10.f), + scale(1.f,1.f,-1.f) * orthographic_rh_no(100.f, 800.f, 50.f, 640.f, 5.f, 10.f)))); + + REQUIRE(all(approx( + orthographic_lh_zo(100.f, 800.f, 50.f, 640.f, 5.f, 10.f), + scale(1.f,1.f,-1.f) * orthographic_rh_zo(100.f, 800.f, 50.f, 640.f, 5.f, 10.f)))); + } + + SECTION("matrix perspective") { + REQUIRE(all(approx( + perspective_lh_no(1.5f, 1.3f, 0.f, 10.f), + perspective_lh_zo(1.5f, 1.3f, 0.f, 10.f) * scale(1.f,1.f,2.f) * translate(0.f,0.f,-1.f)))); + + REQUIRE(all(approx( + perspective_rh_no(1.5f, 1.3f, 0.f, 10.f), + perspective_rh_zo(1.5f, 1.3f, 0.f, 10.f) * scale(1.f,1.f,2.f) * translate(0.f,0.f,-1.f)))); + + REQUIRE(all(approx( + perspective_lh_no(1.5f, 1.3f, 0.f, 10.f), + scale(1.f,1.f,-1.f) * perspective_rh_no(1.5f, 1.3f, 0.f, 10.f)))); + + REQUIRE(all(approx( + perspective_lh_zo(1.5f, 1.3f, 0.f, 10.f), + scale(1.f,1.f,-1.f) * perspective_rh_zo(1.5f, 1.3f, 0.f, 10.f)))); + } + SECTION("matrix look_at") { - (void)look_at_lh(float3(-10.f), float3(0.f), float3(0,-1,0)); - (void)look_at_rh(float3(-10.f), float3(0.f), float3(0,-1,0)); - - (void)orthographic_lh_zo(0.f, 800.f, 0.f, 640.f, 0.f, 10.f); - (void)orthographic_lh_no(0.f, 800.f, 0.f, 640.f, 0.f, 10.f); - (void)orthographic_rh_zo(0.f, 800.f, 0.f, 640.f, 0.f, 10.f); - (void)orthographic_rh_no(0.f, 800.f, 0.f, 640.f, 0.f, 10.f); - - (void)perspective_lh_zo(1.f, 1.3f, 0.f, 10.f); - (void)perspective_lh_no(1.f, 1.3f, 0.f, 10.f); - (void)perspective_rh_zo(1.f, 1.3f, 0.f, 10.f); - (void)perspective_rh_no(1.f, 1.3f, 0.f, 10.f); + (void)look_at_lh(float3(1,2,3), float3(0,0,0), float3(0,2,0)); + (void)look_at_rh(float3(1,2,3), float3(0,0,0), float3(0,2,0)); } SECTION("vector angle") {