|
| 1 | +// |
| 2 | +// Copyright (c) 2022 Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) |
| 3 | +// |
| 4 | +// This code is released under an unmodified zlib license. |
| 5 | +// For conditions of distribution and use, please see: |
| 6 | +// https://opensource.org/licenses/Zlib |
| 7 | +// |
| 8 | + |
| 9 | +#ifndef SIEGE_ENGINE_UTILS_MATH_TRANSFORM_H |
| 10 | +#define SIEGE_ENGINE_UTILS_MATH_TRANSFORM_H |
| 11 | + |
| 12 | +#include <cmath> |
| 13 | + |
| 14 | +#include "mat/Mat4.h" |
| 15 | +#include "vec/Vec2.h" |
| 16 | +#include "vec/Vec3.h" |
| 17 | + |
| 18 | +namespace Siege |
| 19 | +{ |
| 20 | +/** |
| 21 | + * Creates a view matrix which is pointing at a specific location in 3D space |
| 22 | + * @param eye the position of the camera |
| 23 | + * @param center the location the camera is pointing at |
| 24 | + * @param up the global up direction in world space (defaults to -1 on the y axis) |
| 25 | + * @return a new 4x4 matrix with the view matrix values |
| 26 | + */ |
| 27 | +inline constexpr Mat4 LookAt(const Vec3& eye, const Vec3& center, const Vec3& up = Vec3::Up()) |
| 28 | +{ |
| 29 | + Vec3 const f(Vec3::Normalise(center - eye)); |
| 30 | + Vec3 const s(Vec3::Normalise(Vec3::Cross(f, up))); |
| 31 | + Vec3 const u(Vec3::Cross(s, f)); |
| 32 | + |
| 33 | + Mat4 result {1}; |
| 34 | + result[0][0] = s.x; |
| 35 | + result[1][0] = s.y; |
| 36 | + result[2][0] = s.z; |
| 37 | + result[0][1] = u.x; |
| 38 | + result[1][1] = u.y; |
| 39 | + result[2][1] = u.z; |
| 40 | + result[0][2] = -f.x; |
| 41 | + result[1][2] = -f.y; |
| 42 | + result[2][2] = -f.z; |
| 43 | + result[3][0] = -Vec3::Dot(s, eye); |
| 44 | + result[3][1] = -Vec3::Dot(u, eye); |
| 45 | + result[3][2] = Vec3::Dot(f, eye); |
| 46 | + return result; |
| 47 | +} |
| 48 | + |
| 49 | +/** |
| 50 | + * Creates a translation matrix. A translation matrix specifies a movement in space |
| 51 | + * @param matrix the 4x4 matrix to translate |
| 52 | + * @param position the position to move the matrix to |
| 53 | + * @return a new matrix with the provided translation |
| 54 | + */ |
| 55 | +inline constexpr Mat4 Translate(const Mat4& matrix, const Vec3& position) |
| 56 | +{ |
| 57 | + Mat4 result = matrix; |
| 58 | + result[3] = |
| 59 | + matrix[0] * position[0] + matrix[1] * position[1] + matrix[2] * position[2] + matrix[3]; |
| 60 | + return result; |
| 61 | +} |
| 62 | + |
| 63 | +/** |
| 64 | + * Creates a rotation matrix |
| 65 | + * @param matrix the matrix to rotate |
| 66 | + * @param angle the angle of rotation |
| 67 | + * @param rotation the axis to rotate the matrix on (specified by using 1 for the axis) |
| 68 | + * @return a new matrix specifying the rotation |
| 69 | + */ |
| 70 | +inline constexpr Mat4 Rotate(const Mat4& matrix, float angle, const Vec3& rotation) |
| 71 | +{ |
| 72 | + float const a = angle; |
| 73 | + float const c = cos(a); |
| 74 | + float const s = sin(a); |
| 75 | + |
| 76 | + Vec3 axis(Vec3::Normalise(rotation)); |
| 77 | + Vec3 temp((1 - c) * axis); |
| 78 | + |
| 79 | + Mat4 rotate; |
| 80 | + rotate[0][0] = c + temp[0] * axis[0]; |
| 81 | + rotate[0][1] = temp[0] * axis[1] + s * axis[2]; |
| 82 | + rotate[0][2] = temp[0] * axis[2] - s * axis[1]; |
| 83 | + |
| 84 | + rotate[1][0] = temp[1] * axis[0] - s * axis[2]; |
| 85 | + rotate[1][1] = c + temp[1] * axis[1]; |
| 86 | + rotate[1][2] = temp[1] * axis[2] + s * axis[0]; |
| 87 | + |
| 88 | + rotate[2][0] = temp[2] * axis[0] + s * axis[1]; |
| 89 | + rotate[2][1] = temp[2] * axis[1] - s * axis[0]; |
| 90 | + rotate[2][2] = c + temp[2] * axis[2]; |
| 91 | + |
| 92 | + Mat4 result; |
| 93 | + result[0] = matrix[0] * rotate[0][0] + matrix[1] * rotate[0][1] + matrix[2] * rotate[0][2]; |
| 94 | + result[1] = matrix[0] * rotate[1][0] + matrix[1] * rotate[1][1] + matrix[2] * rotate[1][2]; |
| 95 | + result[2] = matrix[0] * rotate[2][0] + matrix[1] * rotate[2][1] + matrix[2] * rotate[2][2]; |
| 96 | + result[3] = matrix[3]; |
| 97 | + return result; |
| 98 | +} |
| 99 | + |
| 100 | +/** |
| 101 | + * Creates a scale matrix |
| 102 | + * @param matrix the matrix to scale |
| 103 | + * @param scale the dimensions to scale the matrix by |
| 104 | + * @return a matrix with the new scaling factors |
| 105 | + */ |
| 106 | +inline constexpr Mat4 Scale(const Mat4& matrix, const Vec3 scale) |
| 107 | +{ |
| 108 | + Mat4 result; |
| 109 | + result[0] = matrix[0] * scale.x; |
| 110 | + result[1] = matrix[1] * scale.y; |
| 111 | + result[2] = matrix[2] * scale.z; |
| 112 | + result[3] = matrix[3]; |
| 113 | + return result; |
| 114 | +} |
| 115 | + |
| 116 | +/** |
| 117 | + * Creates a transform matrix in 3D space |
| 118 | + * @param position the position in 3D space |
| 119 | + * @param rotation the rotation in 3D space |
| 120 | + * @param scale the scale in 3D space |
| 121 | + * @return a new 4x4 matrix specifying the 3D transform |
| 122 | + */ |
| 123 | +inline constexpr Mat4 Transform3D(const Vec3& position, const Vec3& rotation, const Vec3& scale) |
| 124 | +{ |
| 125 | + const float cosR = Float::Cos(rotation.z); |
| 126 | + const float sinR = Float::Sin(rotation.z); |
| 127 | + const float cosP = Float::Cos(rotation.x); |
| 128 | + const float sinP = Float::Sin(rotation.x); |
| 129 | + const float cosY = Float::Cos(rotation.y); |
| 130 | + const float sinY = Float::Sin(rotation.y); |
| 131 | + |
| 132 | + return {{scale.x * (cosY * cosR + sinY * sinP * sinR), |
| 133 | + scale.x * (cosP * sinR), |
| 134 | + scale.x * (cosY * sinP * sinR - cosR * sinY)}, |
| 135 | + {scale.y * (cosR * sinY * sinP - cosY * sinR), |
| 136 | + scale.y * (cosP * cosR), |
| 137 | + scale.y * (cosY * cosR * sinP + sinY * sinR)}, |
| 138 | + {scale.z * (cosP * sinY), scale.z * (-sinP), scale.z * (cosY * cosP)}, |
| 139 | + {position.XYZ(), 1.0f}}; |
| 140 | +} |
| 141 | + |
| 142 | +/** |
| 143 | + * Calculates the normal matrix for a 3D object |
| 144 | + * @param rotation the rotation of the object |
| 145 | + * @param scale the scale of the object |
| 146 | + * @return a 4x4 matrix specifying the object normals |
| 147 | + */ |
| 148 | +inline constexpr Mat4 Normal(const Vec3& rotation, const Vec3& scale) |
| 149 | +{ |
| 150 | + const float cosR = Float::Cos(rotation.z); |
| 151 | + const float sinR = Float::Sin(rotation.z); |
| 152 | + const float cosP = Float::Cos(rotation.x); |
| 153 | + const float sinP = Float::Sin(rotation.x); |
| 154 | + const float cosY = Float::Cos(rotation.y); |
| 155 | + const float SinY = Float::Sin(rotation.y); |
| 156 | + |
| 157 | + Siege::Vec3 inverseScale = 1.0f / scale; |
| 158 | + |
| 159 | + return {{ |
| 160 | + inverseScale.x * (cosY * cosR + SinY * sinP * sinR), |
| 161 | + inverseScale.x * (cosP * sinR), |
| 162 | + inverseScale.x * (cosY * sinP * sinR - cosR * SinY), |
| 163 | + }, |
| 164 | + { |
| 165 | + inverseScale.y * (cosR * SinY * sinP - cosY * sinR), |
| 166 | + inverseScale.y * (cosP * cosR), |
| 167 | + inverseScale.y * (cosY * cosR * sinP + SinY * sinR), |
| 168 | + }, |
| 169 | + { |
| 170 | + inverseScale.z * (cosP * SinY), |
| 171 | + inverseScale.z * (-sinP), |
| 172 | + inverseScale.z * (cosY * cosP), |
| 173 | + }}; |
| 174 | +} |
| 175 | +} // namespace Siege |
| 176 | + |
| 177 | +#endif // SIEGE_ENGINE_UTILS_MATH_TRANSFORM_H |
0 commit comments