#pragma once #include #include #include namespace orange::Math { mat4 translate(const vec3& v) { mat4 result; result[3] = vec4{ v[0], v[1], v[2], 1.0f }; return result; } mat4 rotate(const Radian& angle, const vec3& v) { const float c = Math::cos(angle); const float s = Math::sin(angle); const vec3 axis = normalize(v); const vec3 t = (1.0f - c) * axis; mat4 rot; rot[0][0] = c + t[0] * axis[0]; rot[0][1] = 0 + t[0] * axis[1] + s * axis[2]; rot[0][2] = 0 + t[0] * axis[2] - s * axis[1]; rot[0][3] = 0; rot[1][0] = 0 + t[1] * axis[0] - s * axis[2]; rot[1][1] = c + t[1] * axis[1]; rot[1][2] = 0 + t[1] * axis[2] + s * axis[0]; rot[1][3] = 0; rot[2][0] = 0 + t[2] * axis[0] + s * axis[1]; rot[2][1] = 0 + t[2] * axis[1] - s * axis[0]; rot[2][2] = c + t[2] * axis[2]; rot[2][3] = 0; return rot; } mat4 scale(const vec3& v) { return mat4{vec4{v[0], v[1], v[2], 1.0f}}; } mat4 ortho(float left, float right, float bottom, float top) { mat4 result; result[0][0] = 2.0f / (right - left); result[1][1] = 2.0f / (top - bottom); result[2][2] = -1.0f; result[3][0] = -(right + left) / (right - left); result[3][1] = -(top + bottom) / (top - bottom); return result; } mat4 ortho(float left, float right, float bottom, float top, float zNear, float zFar) { mat4 result; result[0][0] = 2.0f / (right - left); result[1][1] = 2.0f / (top - bottom); result[2][2] = -2.0f / (zFar - zNear); result[3][0] = -(right + left) / (right - left); result[3][1] = -(top + bottom) / (top - bottom); result[3][2] = -(zFar + zNear) / (zFar - zNear); return result; } mat4 perspective(const Radian& fovy, float aspect, float zNear, float zFar) { Assert(fabsf(aspect - Math::Epsilon) > 0.0f && "Math::perspective `fovy` is 0/inf."); const float tanHalfFovy = Math::tan(0.5f * fovy); mat4 result{0.0f}; result[0][0] = 1.0f / (aspect * tanHalfFovy); result[1][1] = 1.0f / (tanHalfFovy); result[2][2] = -(zFar + zNear) / (zFar - zNear); result[2][3] = -1.0f; result[3][2] = -2.0f * zFar * zNear / (zFar - zNear); return result; } mat4 infinitePerspective(const Radian& fovy, float aspect, float zNear) { const float range = Math::tan(0.5f * fovy) * zNear; const float left = -range * aspect; const float right = range * aspect; const float bottom = -range; const float top = range; mat4 result{0.0f}; result[0][0] = (2.0f * zNear) / (right - left); result[1][1] = (2.0f * zNear) / (top - bottom); result[2][2] = -1.0f; result[2][3] = -1.0f; result[3][2] = -2.0f * zNear; return result; } template T lookAt(const vec3& eye, const vec3& center, const vec3& up); template <> mat4 lookAt( const vec3& eye, const vec3& center, const vec3& up) { const vec3 f = normalize(center - eye); const vec3 s = normalize(cross(f, up)); const vec3 u = cross(s, f); mat4 result; result[0][0] = +s.x; result[1][0] = +s.y; result[2][0] = +s.z; result[0][1] = +u.x; result[1][1] = +u.y; result[2][1] = +u.z; result[0][2] = -f.x; result[1][2] = -f.y; result[2][2] = -f.z; result[3][0] = -dot(s, eye); result[3][1] = -dot(u, eye); result[3][2] = +dot(f, eye); return result; } template <> quat lookAt( const vec3& eye, const vec3& center, const vec3& up) { const float similar = 0.001f; if (length(center - eye) < similar) return quat{}; // You cannot look at where you are! return matrix4ToQuaternion(lookAt(eye, center, up)); } }