158 lines
4.1 KiB
C++
158 lines
4.1 KiB
C++
#pragma once
|
|
|
|
#include <Orange/Math/Common.h>
|
|
#include <Orange/Math/Vector.h>
|
|
#include <Orange/Math/Quaternion.h>
|
|
|
|
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 <typename T>
|
|
T lookAt(const vec3& eye, const vec3& center, const vec3& up);
|
|
|
|
template <>
|
|
mat4 lookAt<mat4>(
|
|
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<quat>(
|
|
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<mat4>(eye, center, up));
|
|
}
|
|
}
|