mirror of
https://github.com/BlackMATov/vmath.hpp.git
synced 2025-12-16 14:11:28 +07:00
1081 lines
33 KiB
C++
1081 lines
33 KiB
C++
/*******************************************************************************
|
|
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
|
|
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
|
* Copyright (C) 2020-2021, by Matvey Cherevko (blackmatov@gmail.com)
|
|
******************************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include "vmath_fwd.hpp"
|
|
|
|
#include "vmath_fun.hpp"
|
|
#include "vmath_vec_fun.hpp"
|
|
#include "vmath_mat_fun.hpp"
|
|
#include "vmath_qua_fun.hpp"
|
|
|
|
//
|
|
// Units
|
|
//
|
|
|
|
namespace vmath_hpp
|
|
{
|
|
template < typename T > inline constexpr vec<T, 2> zero2{zero_init};
|
|
template < typename T > inline constexpr vec<T, 3> zero3{zero_init};
|
|
template < typename T > inline constexpr vec<T, 4> zero4{zero_init};
|
|
|
|
template < typename T > inline constexpr vec<T, 2> unit2{unit_init};
|
|
template < typename T > inline constexpr vec<T, 3> unit3{unit_init};
|
|
template < typename T > inline constexpr vec<T, 4> unit4{unit_init};
|
|
|
|
template < typename T > inline constexpr vec<T, 2> unit2_x{T{1}, T{0}};
|
|
template < typename T > inline constexpr vec<T, 2> unit2_y{T{0}, T{1}};
|
|
|
|
template < typename T > inline constexpr vec<T, 3> unit3_x{T{1}, T{0}, T{0}};
|
|
template < typename T > inline constexpr vec<T, 3> unit3_y{T{0}, T{1}, T{0}};
|
|
template < typename T > inline constexpr vec<T, 3> unit3_z{T{0}, T{0}, T{1}};
|
|
|
|
template < typename T > inline constexpr vec<T, 4> unit4_x{T{1}, T{0}, T{0}, T{0}};
|
|
template < typename T > inline constexpr vec<T, 4> unit4_y{T{0}, T{1}, T{0}, T{0}};
|
|
template < typename T > inline constexpr vec<T, 4> unit4_z{T{0}, T{0}, T{1}, T{0}};
|
|
template < typename T > inline constexpr vec<T, 4> unit4_w{T{0}, T{0}, T{0}, T{1}};
|
|
|
|
template < typename T > inline constexpr mat<T, 2> mzero2{zero_init};
|
|
template < typename T > inline constexpr mat<T, 3> mzero3{zero_init};
|
|
template < typename T > inline constexpr mat<T, 4> mzero4{zero_init};
|
|
|
|
template < typename T > inline constexpr mat<T, 2> munit2{unit_init};
|
|
template < typename T > inline constexpr mat<T, 3> munit3{unit_init};
|
|
template < typename T > inline constexpr mat<T, 4> munit4{unit_init};
|
|
|
|
template < typename T > inline constexpr mat<T, 2> midentity2{identity_init};
|
|
template < typename T > inline constexpr mat<T, 3> midentity3{identity_init};
|
|
template < typename T > inline constexpr mat<T, 4> midentity4{identity_init};
|
|
|
|
template < typename T > inline constexpr qua<T> qzero{zero_init};
|
|
template < typename T > inline constexpr qua<T> qidentity{identity_init};
|
|
}
|
|
|
|
//
|
|
// Hash
|
|
//
|
|
|
|
namespace vmath_hpp::detail
|
|
{
|
|
struct hash_combiner {
|
|
template < typename T >
|
|
[[nodiscard]] std::size_t operator()(std::size_t seed, const T& x) noexcept {
|
|
return (seed ^= std::hash<T>{}(x) + 0x9e3779b9 + (seed << 6) + ( seed >> 2));
|
|
}
|
|
};
|
|
|
|
template < typename T, size_t Size >
|
|
[[nodiscard]] std::size_t hash(const vec<T, Size>& v) noexcept {
|
|
return fold_join(hash_combiner{}, std::size_t{}, v);
|
|
}
|
|
|
|
template < typename T, size_t Size >
|
|
[[nodiscard]] std::size_t hash(const mat<T, Size>& m) noexcept {
|
|
return fold_join(hash_combiner{}, std::size_t{}, m);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] std::size_t hash(const qua<T>& q) noexcept {
|
|
return fold_join(hash_combiner{}, std::size_t{}, q);
|
|
}
|
|
}
|
|
|
|
namespace std
|
|
{
|
|
template < typename T, size_t Size >
|
|
struct hash<vmath_hpp::vec<T, Size>> {
|
|
size_t operator()(const vmath_hpp::vec<T, Size>& v) const noexcept {
|
|
return vmath_hpp::detail::hash(v);
|
|
}
|
|
};
|
|
|
|
template < typename T, size_t Size >
|
|
struct hash<vmath_hpp::mat<T, Size>> {
|
|
size_t operator()(const vmath_hpp::mat<T, Size>& m) const noexcept {
|
|
return vmath_hpp::detail::hash(m);
|
|
}
|
|
};
|
|
|
|
template < typename T >
|
|
struct hash<vmath_hpp::qua<T>> {
|
|
size_t operator()(const vmath_hpp::qua<T>& q) const noexcept {
|
|
return vmath_hpp::detail::hash(q);
|
|
}
|
|
};
|
|
}
|
|
|
|
//
|
|
// Cast
|
|
//
|
|
|
|
namespace vmath_hpp
|
|
{
|
|
template < typename To, typename From >
|
|
[[nodiscard]] std::enable_if_t<
|
|
std::is_arithmetic_v<To> && std::is_arithmetic_v<From>
|
|
, To>
|
|
constexpr cast_to(From x) noexcept {
|
|
return static_cast<To>(x);
|
|
}
|
|
|
|
template < typename To, typename From, std::size_t Size >
|
|
[[nodiscard]] constexpr vec<To, Size> cast_to(const vec<From, Size>& v) {
|
|
return map_join([](From x){ return cast_to<To>(x); }, v);
|
|
}
|
|
|
|
template < typename To, typename From, std::size_t Size >
|
|
[[nodiscard]] constexpr mat<To, Size> cast_to(const mat<From, Size>& m) {
|
|
return map_join([](const vec<From, Size>& v){ return cast_to<To>(v); }, m);
|
|
}
|
|
|
|
template < typename To, typename From >
|
|
[[nodiscard]] constexpr qua<To> cast_to(const qua<From>& q) {
|
|
return map_join([](From x){ return cast_to<To>(x); }, q);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Access
|
|
//
|
|
|
|
namespace vmath_hpp
|
|
{
|
|
// component
|
|
|
|
template < typename T, std::size_t Size >
|
|
[[nodiscard]] constexpr T component(const vec<T, Size>& v, std::size_t index) {
|
|
return v[index];
|
|
}
|
|
|
|
template < typename T, std::size_t Size >
|
|
[[nodiscard]] constexpr vec<T, Size> component(vec<T, Size> v, std::size_t index, T component) {
|
|
v[index] = component;
|
|
return v;
|
|
}
|
|
|
|
// row
|
|
|
|
template < typename T, std::size_t Size >
|
|
[[nodiscard]] constexpr vec<T, Size> row(const mat<T, Size>& m, std::size_t index) {
|
|
return m.rows[index];
|
|
}
|
|
|
|
template < typename T, std::size_t Size >
|
|
[[nodiscard]] constexpr mat<T, Size> row(mat<T, Size> m, std::size_t index, const vec<T, Size>& row) {
|
|
m.rows[index] = row;
|
|
return m;
|
|
}
|
|
|
|
// column
|
|
|
|
namespace impl
|
|
{
|
|
template < typename T, std::size_t Size, std::size_t... Is >
|
|
[[nodiscard]] constexpr VMATH_HPP_FORCE_INLINE
|
|
vec<T, Size> column_impl(const mat<T, Size>& m, std::size_t index, std::index_sequence<Is...>) {
|
|
return { m[Is][index]... };
|
|
}
|
|
|
|
template < typename T, std::size_t Size, std::size_t... Is >
|
|
[[nodiscard]] constexpr VMATH_HPP_FORCE_INLINE
|
|
mat<T, Size> column_impl(const mat<T, Size>& m, std::size_t index, const vec<T, Size>& column, std::index_sequence<Is...>) {
|
|
return { component(m[Is], index, column[Is])... };
|
|
}
|
|
}
|
|
|
|
template < typename T, std::size_t Size >
|
|
[[nodiscard]] constexpr vec<T, Size> column(const mat<T, Size>& m, std::size_t index) {
|
|
return impl::column_impl(m, index, std::make_index_sequence<Size>{});
|
|
}
|
|
|
|
template < typename T, std::size_t Size >
|
|
[[nodiscard]] constexpr mat<T, Size> column(const mat<T, Size>& m, std::size_t index, const vec<T, Size>& column) {
|
|
return impl::column_impl(m, index, column, std::make_index_sequence<Size>{});
|
|
}
|
|
|
|
// real
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr T real(const qua<T>& q) {
|
|
return q.s;
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> real(qua<T> q, T real) {
|
|
q.s = real;
|
|
return q;
|
|
}
|
|
|
|
// imag
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr vec<T, 3> imag(const qua<T>& q) {
|
|
return q.v;
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> imag(qua<T> q, const vec<T, 3>& imag) {
|
|
q.v = imag;
|
|
return q;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Matrix Transform 3D
|
|
//
|
|
|
|
namespace vmath_hpp
|
|
{
|
|
// trs
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> trs(const vec<T, 3>& t, const mat<T, 3>& r) {
|
|
return {
|
|
{ r[0], T{0} },
|
|
{ r[1], T{0} },
|
|
{ r[2], T{0} },
|
|
{ t, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> trs(const vec<T, 3>& t, const mat<T, 3>& r, const vec<T, 3>& s) {
|
|
return {
|
|
{ r[0] * s[0], T{0} },
|
|
{ r[1] * s[1], T{0} },
|
|
{ r[2] * s[2], T{0} },
|
|
{ t, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> trs(const vec<T, 3>& t, const qua<T>& r) {
|
|
return trs(t, rotate(r));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> trs(const vec<T, 3>& t, const qua<T>& r, const vec<T, 3>& s) {
|
|
return trs(t, rotate(r), s);
|
|
}
|
|
|
|
// translate
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> translate(const vec<T, 3>& v) {
|
|
/// REFERENCE:
|
|
/// https://en.wikipedia.org/wiki/Translation_(geometry)
|
|
|
|
return {
|
|
{ T{1}, T{0}, T{0}, T{0} },
|
|
{ T{0}, T{1}, T{0}, T{0} },
|
|
{ T{0}, T{0}, T{1}, T{0} },
|
|
{ v.x, v.y, v.z, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> translate(const mat<T, 4>& m, const vec<T, 3>& v) {
|
|
return m * translate(v);
|
|
}
|
|
|
|
// rotate
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate(const qua<T>& q) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/
|
|
|
|
const auto [qv, qs] = normalize(q);
|
|
|
|
const T x2 = qv.x * T{2};
|
|
const T y2 = qv.y * T{2};
|
|
const T z2 = qv.z * T{2};
|
|
|
|
const T sx2 = qs * x2;
|
|
const T sy2 = qs * y2;
|
|
const T sz2 = qs * z2;
|
|
|
|
const T xx2 = qv.x * x2;
|
|
const T xy2 = qv.x * y2;
|
|
const T xz2 = qv.x * z2;
|
|
|
|
const T yy2 = qv.y * y2;
|
|
const T yz2 = qv.y * z2;
|
|
const T zz2 = qv.z * z2;
|
|
|
|
return {
|
|
{ T{1} - (yy2 + zz2), (xy2 + sz2), (xz2 - sy2) },
|
|
{ (xy2 - sz2), T{1} - (xx2 + zz2), (yz2 + sx2) },
|
|
{ (xz2 + sy2), (yz2 - sx2), T{1} - (xx2 + yy2) }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate(const mat<T, 3>& m, const qua<T>& q) {
|
|
return m * rotate(q);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> rotate4(const qua<T>& q) {
|
|
return mat<T, 4>(rotate(q));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> rotate4(const mat<T, 4>& m, const qua<T>& q) {
|
|
return m * rotate4(q);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate(T angle, const vec<T, 3>& axis) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/
|
|
|
|
const auto [s, c] = sincos(angle);
|
|
const auto [x, y, z] = normalize(axis);
|
|
|
|
const T xx = x * x;
|
|
const T yy = y * y;
|
|
const T zz = z * z;
|
|
|
|
const T xs = x * s;
|
|
const T ys = y * s;
|
|
const T zs = z * s;
|
|
|
|
const T ic = T{1} - c;
|
|
|
|
const T xxm = xx * ic;
|
|
const T yym = yy * ic;
|
|
const T zzm = zz * ic;
|
|
|
|
const T xym = x * y * ic;
|
|
const T xzm = x * z * ic;
|
|
const T yzm = y * z * ic;
|
|
|
|
return {
|
|
{ xxm + c, xym + zs, xzm - ys },
|
|
{ xym - zs, yym + c, yzm + xs },
|
|
{ xzm + ys, yzm - xs, zzm + c }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate(const mat<T, 3>& m, T angle, const vec<T, 3>& axis) {
|
|
return m * rotate(angle, axis);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> rotate4(T angle, const vec<T, 3>& axis) {
|
|
return mat<T, 4>(rotate(angle, axis));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> rotate4(const mat<T, 4>& m, T angle, const vec<T, 3>& axis) {
|
|
return m * rotate4(angle, axis);
|
|
}
|
|
|
|
// rotate_x
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate_x(T angle) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/
|
|
|
|
const auto [s, c] = sincos(angle);
|
|
|
|
return {
|
|
{ T{1}, T{0}, T{0} },
|
|
{ T{0}, c, s },
|
|
{ T{0}, -s, c }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate_x(const mat<T, 3>& m, T angle) {
|
|
return m * rotate_x(angle);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> rotate4_x(T angle) {
|
|
return mat<T, 4>(rotate_x(angle));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> rotate4_x(const mat<T, 4>& m, T angle) {
|
|
return m * rotate4_x(angle);
|
|
}
|
|
|
|
// rotate_y
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate_y(T angle) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/
|
|
|
|
const auto [s, c] = sincos(angle);
|
|
|
|
return {
|
|
{ c, T{0}, -s },
|
|
{ T{0}, T{1}, T{0} },
|
|
{ s, T{0}, c }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate_y(const mat<T, 3>& m, T angle) {
|
|
return m * rotate_y(angle);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> rotate4_y(T angle) {
|
|
return mat<T, 4>(rotate_y(angle));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> rotate4_y(const mat<T, 4>& m, T angle) {
|
|
return m * rotate4_y(angle);
|
|
}
|
|
|
|
// rotate_z
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate_z(T angle) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/
|
|
|
|
const auto [s, c] = sincos(angle);
|
|
|
|
return {
|
|
{ c, s, T{0} },
|
|
{ -s, c, T{0} },
|
|
{ T{0}, T{0}, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate_z(const mat<T, 3>& m, T angle) {
|
|
return m * rotate_z(angle);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> rotate4_z(T angle) {
|
|
return mat<T, 4>(rotate_z(angle));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> rotate4_z(const mat<T, 4>& m, T angle) {
|
|
return m * rotate4_z(angle);
|
|
}
|
|
|
|
// scale
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> scale(const vec<T, 3>& v) {
|
|
/// REFERENCE:
|
|
/// https://en.wikipedia.org/wiki/Scaling_(geometry)
|
|
|
|
return {
|
|
{ v.x, T{0}, T{0} },
|
|
{ T{0}, v.y, T{0} },
|
|
{ T{0}, T{0}, v.z }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> scale(const mat<T, 3>& m, const vec<T, 3>& v) {
|
|
return m * scale(v);
|
|
}
|
|
|
|
// scale4
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> scale4(const vec<T, 3>& v) {
|
|
return mat<T, 4>(scale(v));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> scale4(const mat<T, 4>& m, const vec<T, 3>& v) {
|
|
return m * scale4(v);
|
|
}
|
|
|
|
// look_at
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> look_at_lh(
|
|
const vec<T, 3>& dir,
|
|
const vec<T, 3>& 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);
|
|
|
|
return {
|
|
{ ax.x, ay.x, az.x },
|
|
{ ax.y, ay.y, az.y },
|
|
{ ax.z, ay.z, az.z }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> look_at_lh(
|
|
const vec<T, 3>& eye,
|
|
const vec<T, 3>& at,
|
|
const vec<T, 3>& 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);
|
|
|
|
const T dx = dot(ax, eye);
|
|
const T dy = dot(ay, eye);
|
|
const T dz = dot(az, eye);
|
|
|
|
return {
|
|
{ ax.x, ay.x, az.x, T{0} },
|
|
{ ax.y, ay.y, az.y, T{0} },
|
|
{ ax.z, ay.z, az.z, T{0} },
|
|
{ -dx, -dy, -dz, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> look_at_rh(
|
|
const vec<T, 3>& dir,
|
|
const vec<T, 3>& 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);
|
|
|
|
return {
|
|
{ ax.x, ay.x, az.x },
|
|
{ ax.y, ay.y, az.y },
|
|
{ ax.z, ay.z, az.z }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> look_at_rh(
|
|
const vec<T, 3>& eye,
|
|
const vec<T, 3>& at,
|
|
const vec<T, 3>& 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);
|
|
|
|
const T dx = dot(ax, eye);
|
|
const T dy = dot(ay, eye);
|
|
const T dz = dot(az, eye);
|
|
|
|
return {
|
|
{ ax.x, ay.x, az.x, T{0} },
|
|
{ ax.y, ay.y, az.y, T{0} },
|
|
{ ax.z, ay.z, az.z, T{0} },
|
|
{ -dx, -dy, -dz, T{1} }};
|
|
}
|
|
}
|
|
|
|
//
|
|
// Matrix Transform 2D
|
|
//
|
|
|
|
namespace vmath_hpp
|
|
{
|
|
// trs
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> trs(const vec<T, 2>& t, const mat<T, 2>& r) {
|
|
return {
|
|
{ r[0], T{0} },
|
|
{ r[1], T{0} },
|
|
{ t, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> trs(const vec<T, 2>& t, const mat<T, 2>& r, const vec<T, 2>& s) {
|
|
return {
|
|
{ r[0] * s[0], T{0} },
|
|
{ r[1] * s[1], T{0} },
|
|
{ t, T{1} }};
|
|
}
|
|
|
|
// translate
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> translate(const vec<T, 2>& v) {
|
|
/// REFERENCE:
|
|
/// https://en.wikipedia.org/wiki/Translation_(geometry)
|
|
|
|
return {
|
|
{ T{1}, T{0}, T{0} },
|
|
{ T{0}, T{1}, T{0} },
|
|
{ v.x, v.y, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> translate(const mat<T, 3>& m, const vec<T, 2>& v) {
|
|
return m * translate(v);
|
|
}
|
|
|
|
// rotate
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 2> rotate(T angle) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/
|
|
|
|
const auto [s, c] = sincos(angle);
|
|
|
|
return {
|
|
{ c, s },
|
|
{ -s, c }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 2> rotate(const mat<T, 2>& m, T angle) {
|
|
return m * rotate(angle);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate3(T angle) {
|
|
return mat<T, 3>(rotate(angle));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> rotate3(const mat<T, 3>& m, T angle) {
|
|
return m * rotate3(angle);
|
|
}
|
|
|
|
// scale
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 2> scale(const vec<T, 2>& v) {
|
|
/// REFERENCE:
|
|
/// https://en.wikipedia.org/wiki/Scaling_(geometry)
|
|
|
|
return {
|
|
{ v.x, T{0} },
|
|
{ T{0}, v.y }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 2> scale(const mat<T, 2>& m, const vec<T, 2>& v) {
|
|
return m * scale(v);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> scale3(const vec<T, 2>& v) {
|
|
return mat<T, 3>(scale(v));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> scale3(const mat<T, 3>& m, const vec<T, 2>& v) {
|
|
return m * scale3(v);
|
|
}
|
|
|
|
// shear
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 2> shear(const vec<T, 2>& v) {
|
|
/// REFERENCE:
|
|
/// https://en.wikipedia.org/wiki/Shear_matrix
|
|
|
|
return {
|
|
{ T{1}, v.y },
|
|
{ v.x, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 2> shear(const mat<T, 2>& m, const vec<T, 2>& v) {
|
|
return m * shear(v);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> shear3(const vec<T, 2>& v) {
|
|
return mat<T, 3>(shear(v));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 3> shear3(const mat<T, 3>& m, const vec<T, 2>& v) {
|
|
return m * shear3(v);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Matrix Projections
|
|
//
|
|
|
|
namespace vmath_hpp
|
|
{
|
|
// orthographic
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> orthographic_lh(T width, T height, T znear, T zfar) {
|
|
/// REFERENCE:
|
|
/// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixortholh
|
|
|
|
const T rwidth = rcp(width);
|
|
const T rheight = rcp(height);
|
|
const T frange = rcp(zfar - znear);
|
|
|
|
const T sx = T{2} * rwidth;
|
|
const T sy = T{2} * rheight;
|
|
const T sz = frange;
|
|
const T tz = -frange * znear;
|
|
|
|
return {
|
|
{ sx, T{0}, T{0}, T{0} },
|
|
{ T{0}, sy, T{0}, T{0} },
|
|
{ T{0}, T{0}, sz, T{0} },
|
|
{ T{0}, T{0}, tz, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> orthographic_rh(T width, T height, T znear, T zfar) {
|
|
/// REFERENCE:
|
|
/// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixorthorh
|
|
|
|
const T rwidth = rcp(width);
|
|
const T rheight = rcp(height);
|
|
const T frange = rcp(znear - zfar);
|
|
|
|
const T sx = T{2} * rwidth;
|
|
const T sy = T{2} * rheight;
|
|
const T sz = frange;
|
|
const T tz = frange * znear;
|
|
|
|
return {
|
|
{ sx, T{0}, T{0}, T{0} },
|
|
{ T{0}, sy, T{0}, T{0} },
|
|
{ T{0}, T{0}, sz, T{0} },
|
|
{ T{0}, T{0}, tz, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> orthographic_lh(T left, T right, T bottom, T top, T znear, T zfar) {
|
|
/// REFERENCE:
|
|
/// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixorthooffcenterlh
|
|
|
|
const T rwidth = rcp(right - left);
|
|
const T rheight = rcp(top - bottom);
|
|
const T frange = rcp(zfar - znear);
|
|
|
|
return {
|
|
{ T{2} * rwidth, T{0}, T{0}, T{0} },
|
|
{ T{0}, T{2} * rheight, T{0}, T{0} },
|
|
{ T{0}, T{0}, frange, T{0} },
|
|
{ -(left + right) * rwidth, -(top + bottom) * rheight, -frange * znear, T{1} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> orthographic_rh(T left, T right, T bottom, T top, T znear, T zfar) {
|
|
/// REFERENCE:
|
|
/// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixorthooffcenterrh
|
|
|
|
const T rwidth = rcp(right - left);
|
|
const T rheight = rcp(top - bottom);
|
|
const T frange = rcp(znear - zfar);
|
|
|
|
return {
|
|
{ T{2} * rwidth, T{0}, T{0}, T{0} },
|
|
{ T{0}, T{2} * rheight, T{0}, T{0} },
|
|
{ T{0}, T{0}, frange, T{0} },
|
|
{ -(left + right) * rwidth, -(top + bottom) * rheight, frange * znear, T{1} }};
|
|
}
|
|
|
|
// perspective
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> perspective_lh(T width, T height, T znear, T zfar) {
|
|
/// REFERENCE:
|
|
/// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivelh
|
|
|
|
const T sx = T{2} * znear * rcp(width);
|
|
const T sy = T{2} * znear * rcp(height);
|
|
const T sz = zfar * rcp(zfar - znear);
|
|
const T tz = (znear * zfar) * rcp(znear - zfar);
|
|
|
|
return {
|
|
{ T{sx}, T{0}, T{0}, T{0} },
|
|
{ T{0}, T{sy}, T{0}, T{0} },
|
|
{ T{0}, T{0}, T{sz}, T{1} },
|
|
{ T{0}, T{0}, T{tz}, T{0} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> perspective_rh(T width, T height, T znear, T zfar) {
|
|
/// REFERENCE:
|
|
/// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectiverh
|
|
|
|
const T sx = T{2} * znear * rcp(width);
|
|
const T sy = T{2} * znear * rcp(height);
|
|
const T sz = zfar * rcp(znear - zfar);
|
|
const T tz = (znear * zfar) * rcp(znear - zfar);
|
|
|
|
return {
|
|
{ sx, T{0}, T{0}, T{0} },
|
|
{ T{0}, sy, T{0}, T{0} },
|
|
{ T{0}, T{0}, sz, -T{1} },
|
|
{ T{0}, T{0}, tz, T{0} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> perspective_lh(T left, T right, T bottom, T top, T znear, T zfar) {
|
|
/// REFERENCE:
|
|
/// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectiveoffcenterlh
|
|
|
|
const T znear2 = T{2} * znear;
|
|
const T rwidth = rcp(right - left);
|
|
const T rheight = rcp(top - bottom);
|
|
const T frange = zfar * rcp(zfar - znear);
|
|
|
|
return {
|
|
{ znear2 * rwidth, T{0}, T{0}, T{0} },
|
|
{ T{0}, znear2 * rheight, T{0}, T{0} },
|
|
{ -(left + right) * rwidth, -(top + bottom) * rheight, frange, T{1} },
|
|
{ T{0}, T{0}, -frange * znear, T{0} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> perspective_rh(T left, T right, T bottom, T top, T znear, T zfar) {
|
|
/// REFERENCE:
|
|
/// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectiveoffcenterrh
|
|
|
|
const T znear2 = T{2} * znear;
|
|
const T rwidth = rcp(right - left);
|
|
const T rheight = rcp(top - bottom);
|
|
const T frange = zfar * rcp(znear - zfar);
|
|
|
|
return {
|
|
{ znear2 * rwidth, T{0}, T{0}, T{0} },
|
|
{ T{0}, znear2 * rheight, T{0}, T{0} },
|
|
{ (left + right) * rwidth, (top + bottom) * rheight, frange, -T{1} },
|
|
{ T{0}, T{0}, frange * znear, T{0} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> perspective_fov_lh(T fovy, T aspect, T znear, T zfar) {
|
|
/// REFERENCE:
|
|
/// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovlh
|
|
|
|
const T sy = rcp(tan(fovy * T{0.5f}));
|
|
const T sx = sy * rcp(aspect);
|
|
const T sz = zfar * rcp(zfar - znear);
|
|
const T tz = (znear * zfar) * rcp(znear - zfar);
|
|
|
|
return {
|
|
{ sx, T{0}, T{0}, T{0} },
|
|
{ T{0}, sy, T{0}, T{0} },
|
|
{ T{0}, T{0}, sz, T{1} },
|
|
{ T{0}, T{0}, tz, T{0} }};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr mat<T, 4> perspective_fov_rh(T fovy, T aspect, T znear, T zfar) {
|
|
/// REFERENCE:
|
|
/// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovrh
|
|
|
|
const T sy = rcp(tan(fovy * T{0.5f}));
|
|
const T sx = sy * rcp(aspect);
|
|
const T sz = zfar * rcp(znear - zfar);
|
|
const T tz = (znear * zfar) * rcp(znear - zfar);
|
|
return {
|
|
{ sx, T{0}, T{0}, T{0} },
|
|
{ T{0}, sy, T{0}, T{0} },
|
|
{ T{0}, T{0}, sz, -T{1} },
|
|
{ T{0}, T{0}, tz, T{0} }};
|
|
}
|
|
}
|
|
|
|
//
|
|
// Vector Transform
|
|
//
|
|
|
|
namespace vmath_hpp
|
|
{
|
|
// angle
|
|
|
|
template < typename T, std::size_t Size >
|
|
[[nodiscard]] constexpr T angle(const vec<T, Size>& x, const vec<T, Size>& y) {
|
|
const T rs = rsqrt(length2(x) * length2(y));
|
|
return acos(clamp(dot(x, y) * rs, -T{1}, T{1}));
|
|
}
|
|
|
|
// rotate
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr vec<T, 2> rotate(const vec<T, 2>& v, T angle) {
|
|
return v * rotate(angle);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr vec<T, 3> rotate_x(const vec<T, 3>& v, T angle) {
|
|
return v * qrotate(angle, unit3_x<T>);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr vec<T, 3> rotate_y(const vec<T, 3>& v, T angle) {
|
|
return v * qrotate(angle, unit3_y<T>);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr vec<T, 3> rotate_z(const vec<T, 3>& v, T angle) {
|
|
return v * qrotate(angle, unit3_z<T>);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr vec<T, 3> rotate(const vec<T, 3>& v, const qua<T>& q) {
|
|
return v * q;
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr vec<T, 3> rotate(const vec<T, 3>& v, T angle, const vec<T, 3>& axis) {
|
|
return v * qrotate(angle, axis);
|
|
}
|
|
|
|
// project
|
|
|
|
template < typename T, std::size_t Size >
|
|
[[nodiscard]] constexpr vec<T, Size> project(const vec<T, Size>& v, const vec<T, Size>& normal) {
|
|
return dot(v, normal) * rlength2(normal) * normal;
|
|
}
|
|
|
|
// perpendicular
|
|
|
|
template < typename T, std::size_t Size >
|
|
[[nodiscard]] constexpr vec<T, Size> perpendicular(const vec<T, Size>& v, const vec<T, Size>& normal) {
|
|
return v - project(v, normal);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Quaternion Transform
|
|
//
|
|
|
|
namespace vmath_hpp
|
|
{
|
|
// qrotate
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate(const mat<T, 3>& m) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
|
|
|
|
auto xyzw = T{0.5f} * sqrt(max(T{0}, vec{
|
|
T{1} + m[0][0] - m[1][1] - m[2][2],
|
|
T{1} - m[0][0] + m[1][1] - m[2][2],
|
|
T{1} - m[0][0] - m[1][1] + m[2][2],
|
|
T{1} + m[0][0] + m[1][1] + m[2][2]}));
|
|
|
|
return qua(copysign(xyzw, {
|
|
m[1][2] - m[2][1],
|
|
m[2][0] - m[0][2],
|
|
m[0][1] - m[1][0],
|
|
T{1}}));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate(const qua<T>& q, const mat<T, 3>& m) {
|
|
return q * qrotate(m);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate(const vec<T, 3>& from, const vec<T, 3>& to) {
|
|
/// REFERENCE:
|
|
/// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
|
|
|
|
const T n = sqrt(length2(from) * length2(to));
|
|
const T s = dot(from, to) + n;
|
|
|
|
if ( s < T{0.000001f} * n ) {
|
|
return abs(from.z) < abs(from.x)
|
|
? normalize(qua{vec{-from.y, from.x, T{0}}, T{0}})
|
|
: normalize(qua{vec{T{0}, -from.z, from.y}, T{0}});
|
|
}
|
|
|
|
return normalize(qua{cross(from, to), s});
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate(const qua<T>& q, const vec<T, 3>& from, const vec<T, 3>& to) {
|
|
return q * qrotate(from, to);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate(T angle, const vec<T, 3>& axis) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/
|
|
|
|
const auto [s, c] = sincos(angle * T{0.5f});
|
|
const auto [x, y, z] = normalize(axis);
|
|
|
|
return {vec{x, y, z} * s, c};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate(const qua<T>& q, T angle, const vec<T, 3>& axis) {
|
|
return q * qrotate(angle, axis);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate_x(T angle) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/
|
|
|
|
const auto [s, c] = sincos(angle * T{0.5f});
|
|
|
|
return {vec{s, T{0}, T{0}}, c};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate_x(const qua<T>& q, T angle) {
|
|
return qrotate(q, angle, unit3_x<T>);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate_y(T angle) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/
|
|
|
|
const auto [s, c] = sincos(angle * T{0.5f});
|
|
|
|
return {vec{T{0}, s, T{0}}, c};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate_y(const qua<T>& q, T angle) {
|
|
return qrotate(q, angle, unit3_y<T>);
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate_z(T angle) {
|
|
/// REFERENCE:
|
|
/// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/
|
|
|
|
const auto [s, c] = sincos(angle * T{0.5f});
|
|
|
|
return {vec{T{0}, T{0}, s}, c};
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qrotate_z(const qua<T>& q, T angle) {
|
|
return qrotate(q, angle, unit3_z<T>);
|
|
}
|
|
|
|
// look_at
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qlook_at_lh(const vec<T, 3>& dir, const vec<T, 3>& up) {
|
|
return qrotate(look_at_lh(dir, up));
|
|
}
|
|
|
|
template < typename T >
|
|
[[nodiscard]] constexpr qua<T> qlook_at_rh(const vec<T, 3>& dir, const vec<T, 3>& up) {
|
|
return qrotate(look_at_rh(dir, up));
|
|
}
|
|
}
|