2020-08-11 12:07:21 -04:00
|
|
|
#include "transform.hpp"
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
#include "math.hpp"
|
|
|
|
|
2020-08-18 00:35:49 -04:00
|
|
|
/*
|
|
|
|
These produce left-handed matrices.
|
|
|
|
Metal/DX12 are both NDC +y down.
|
|
|
|
*/
|
|
|
|
Matrix4x4 transform::perspective(const float field_of_view, const float aspect, const float z_near, const float z_far) {
|
|
|
|
const float tan_half_fov = tanf(field_of_view / 2.0f);
|
|
|
|
|
|
|
|
Matrix4x4 result(0.0f);
|
|
|
|
result[0][0] = 1.0f / (aspect * tan_half_fov);
|
|
|
|
result[1][1] = 1.0f / tan_half_fov;
|
|
|
|
result[2][2] = z_far / (z_far - z_near);
|
|
|
|
result[2][3] = 1.0f;
|
|
|
|
result[3][2] = -(z_far * z_near) / (z_far - z_near);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4x4 transform::infinite_perspective(const float field_of_view, const float aspect, const float z_near) {
|
|
|
|
const float range = tanf(field_of_view / 2.0f) * z_near;
|
2020-08-11 12:07:21 -04:00
|
|
|
const float left = -range * aspect;
|
|
|
|
const float right = range * aspect;
|
|
|
|
const float bottom = -range;
|
|
|
|
const float top = range;
|
|
|
|
|
|
|
|
Matrix4x4 result(0.0f);
|
2020-08-18 00:35:49 -04:00
|
|
|
result[0][0] = (2.0f * z_near) / (right - left);
|
|
|
|
result[1][1] = (2.0f * z_near) / (top - bottom);
|
2020-08-18 00:46:16 -04:00
|
|
|
result[2][2] = 1.0f - std::numeric_limits<float>::epsilon(); // prevent NaN
|
2020-08-18 00:35:49 -04:00
|
|
|
result[2][3] = 1.0f;
|
2020-08-18 00:46:16 -04:00
|
|
|
result[3][2] = -(2.0 - std::numeric_limits<float>::epsilon()) * z_near;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4x4 transform::orthographic(float left, float right, float bottom, float top, float zNear, float zFar) {
|
|
|
|
Matrix4x4 result(1.0f);
|
|
|
|
result[0][0] = 2.0f / (right - left);
|
|
|
|
result[1][1] = 2.0f / (top - bottom);
|
2020-08-18 00:35:49 -04:00
|
|
|
result[2][2] = 1.0f / (zFar - zNear);
|
2020-08-11 12:07:21 -04:00
|
|
|
result[3][0] = -(right + left) / (right - left);
|
|
|
|
result[3][1] = -(top + bottom) / (top - bottom);
|
|
|
|
result[3][2] = - zNear / (zFar - zNear);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4x4 transform::look_at(const Vector3 eye, const Vector3 center, const Vector3 up) {
|
|
|
|
const Vector3 f = normalize(center - eye);
|
2020-08-19 17:15:00 -04:00
|
|
|
const Vector3 s = normalize(cross(up, f));
|
2020-08-18 00:35:49 -04:00
|
|
|
const Vector3 u = cross(f, s);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
Matrix4x4 result(1.0f);
|
|
|
|
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;
|
2020-08-18 00:35:49 -04:00
|
|
|
result[0][2] = f.x;
|
|
|
|
result[1][2] = f.y;
|
|
|
|
result[2][2] = f.z;
|
2020-08-11 12:07:21 -04:00
|
|
|
result[3][0] = -dot(s, eye);
|
|
|
|
result[3][1] = -dot(u, eye);
|
2020-08-18 00:35:49 -04:00
|
|
|
result[3][2] = -dot(f, eye);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4x4 transform::translate(const Matrix4x4 matrix, const Vector3 translation) {
|
|
|
|
Matrix4x4 result(1.0f);
|
|
|
|
result[3] = Vector4(translation, 1.0);
|
|
|
|
|
|
|
|
return matrix * result;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4x4 transform::rotate(const Matrix4x4 matrix, const float angle, const Vector3 v) {
|
|
|
|
const float a = angle;
|
|
|
|
const float c = cosf(a);
|
|
|
|
const float s = sinf(a);
|
|
|
|
|
|
|
|
const Vector3 axis = normalize(v);
|
|
|
|
const Vector3 temp = Vector3((1.0f - c) * axis);
|
|
|
|
|
|
|
|
Matrix4x4 Rotate(1.0f);
|
|
|
|
Rotate[0][0] = c + temp[0] * axis[0];
|
|
|
|
Rotate[0][1] = temp[0] * axis[1] + s * axis[2];
|
|
|
|
Rotate[0][2] = temp[0] * axis[2] - s * axis[1];
|
|
|
|
|
|
|
|
Rotate[1][0] = temp[1] * axis[0] - s * axis[2];
|
|
|
|
Rotate[1][1] = c + temp[1] * axis[1];
|
|
|
|
Rotate[1][2] = temp[1] * axis[2] + s * axis[0];
|
|
|
|
|
|
|
|
Rotate[2][0] = temp[2] * axis[0] + s * axis[1];
|
|
|
|
Rotate[2][1] = temp[2] * axis[1] - s * axis[0];
|
|
|
|
Rotate[2][2] = c + temp[2] * axis[2];
|
|
|
|
|
|
|
|
Matrix4x4 result(1.0f);
|
2020-08-19 17:15:00 -04:00
|
|
|
result[0] = matrix[0] * Rotate[0][0] + matrix[1] * Rotate[0][1] + matrix[2] * Rotate[0][2];
|
|
|
|
result[1] = matrix[0] * Rotate[1][0] + matrix[1] * Rotate[1][1] + matrix[2] * Rotate[1][2];
|
|
|
|
result[2] = matrix[0] * Rotate[2][0] + matrix[1] * Rotate[2][1] + matrix[2] * Rotate[2][2];
|
|
|
|
result[3] = matrix[3];
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2020-08-19 17:15:00 -04:00
|
|
|
return result;
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4x4 transform::scale(const Matrix4x4 matrix, const Vector3 scale) {
|
|
|
|
Matrix4x4 result(1.0f);
|
|
|
|
result[0][0] = scale.x;
|
|
|
|
result[1][1] = scale.y;
|
|
|
|
result[2][2] = scale.z;
|
|
|
|
|
|
|
|
return matrix * result;
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion transform::quat_look_at(const Vector3 eye, const Vector3 center, const Vector3 up) {
|
|
|
|
const Vector3 direction = normalize(center - eye);
|
|
|
|
|
|
|
|
Matrix3x3 result(1.0f);
|
2020-08-18 00:35:49 -04:00
|
|
|
result[2] = direction;
|
2020-08-19 22:46:07 -04:00
|
|
|
result[0] = normalize(cross(up, result[2]));
|
2020-08-11 12:07:21 -04:00
|
|
|
result[1] = cross(result[2], result[0]);
|
|
|
|
|
|
|
|
return quat_from_matrix(result);
|
|
|
|
}
|