From 3978ea9e2aa0fa3acac4b3eb3b895dc65d37cca9 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 31 Oct 2011 16:51:25 +0000 Subject: [PATCH] core: fix bugs in mat4::lookat() and mat4::perspective(), and ensure these function use degrees rather than radians. --- src/matrix.cpp | 158 +++++++++++++++++++++++++++---------------------- src/matrix.h | 27 +++++++-- src/scene.cpp | 4 +- src/video.cpp | 4 +- 4 files changed, 111 insertions(+), 82 deletions(-) diff --git a/src/matrix.cpp b/src/matrix.cpp index 1d90da24..bf71fd32 100644 --- a/src/matrix.cpp +++ b/src/matrix.cpp @@ -12,6 +12,15 @@ # include "config.h" #endif +#if defined WIN32 && !defined _XBOX +# define _USE_MATH_DEFINES /* for M_PI */ +# define WIN32_LEAN_AND_MEAN +# include +# undef near /* Fuck Microsoft */ +# undef far /* Fuck Microsoft again */ +#endif + +#include /* for M_PI */ #include /* free() */ #include /* strdup() */ @@ -46,7 +55,7 @@ template<> vec3 cross(vec3 v1, vec3 v2) template<> vec2 normalize(vec2 v) { - float norm = v.sqlen(); + float norm = v.len(); if (!norm) return vec2(0); return v / norm; @@ -54,7 +63,7 @@ template<> vec2 normalize(vec2 v) template<> vec3 normalize(vec3 v) { - float norm = v.sqlen(); + float norm = v.len(); if (!norm) return vec3(0); return v / norm; @@ -62,7 +71,7 @@ template<> vec3 normalize(vec3 v) template<> vec4 normalize(vec4 v) { - float norm = v.sqlen(); + float norm = v.len(); if (!norm) return vec4(0); return v / norm; @@ -188,42 +197,6 @@ template<> std::ostream &operator<<(std::ostream &stream, mat4 const &m) } #endif -template<> mat4 mat4::ortho(float left, float right, float bottom, - float top, float near, float far) -{ - float invrl = (right != left) ? 1.0f / (right - left) : 0.0f; - float invtb = (top != bottom) ? 1.0f / (top - bottom) : 0.0f; - float invfn = (far != near) ? 1.0f / (far - near) : 0.0f; - - mat4 ret(0.0f); - ret[0][0] = 2.0f * invrl; - ret[1][1] = 2.0f * invtb; - ret[2][2] = -2.0f * invfn; - ret[3][0] = - (right + left) * invrl; - ret[3][1] = - (top + bottom) * invtb; - ret[3][2] = - (far + near) * invfn; - ret[3][3] = 1.0f; - return ret; -} - -template<> mat4 mat4::frustum(float left, float right, float bottom, - float top, float near, float far) -{ - float invrl = (right != left) ? 1.0f / (right - left) : 0.0f; - float invtb = (top != bottom) ? 1.0f / (top - bottom) : 0.0f; - float invfn = (far != near) ? 1.0f / (far - near) : 0.0f; - - mat4 ret(0.0f); - ret[0][0] = 2.0f * near * invrl; - ret[1][1] = 2.0f * near * invtb; - ret[2][0] = (right + left) * invrl; - ret[2][1] = (top + bottom) * invtb; - ret[2][2] = - (far + near) * invfn; - ret[2][3] = -1.0f; - ret[3][2] = -2.0f * far * near * invfn; - return ret; -} - template<> mat4 mat4::translate(float x, float y, float z) { mat4 ret(1.0f); @@ -238,39 +211,12 @@ template<> mat4 mat4::translate(vec3 v) return translate(v.x, v.y, v.z); } -template<> mat4 mat4::lookat(vec3 eye, vec3 center, vec3 up) -{ - vec3 f = normalize(center - eye); - vec3 u = normalize(up); - vec3 s = normalize(cross(f, u)); - u = cross(s, f); - - mat4 ret(1.0f); - ret[0][0] = s.x; - ret[0][1] = s.y; - ret[0][2] = s.z; - ret[1][0] = u.x; - ret[1][1] = u.y; - ret[1][2] = u.z; - ret[2][0] =-f.x; - ret[2][1] =-f.y; - ret[2][2] =-f.z; - return ret * mat4::translate(-eye); -} - -template<> mat4 mat4::perspective(float theta, float width, - float height, float near, float far) +template<> mat4 mat4::rotate(float angle, float x, float y, float z) { - float t1 = tanf(theta * 0.5f); - float t2 = t1 * height / width; - - return frustum(-near * t1, near * t1, -near * t2, near * t2, near, far); -} + angle *= (M_PI / 180.0f); -template<> mat4 mat4::rotate(float theta, float x, float y, float z) -{ - float st = sinf(theta); - float ct = cosf(theta); + float st = sinf(angle); + float ct = cosf(angle); float len = sqrtf(x * x + y * y + z * z); float invlen = len ? 1.0f / len : 0.0f; @@ -299,9 +245,77 @@ template<> mat4 mat4::rotate(float theta, float x, float y, float z) return ret; } -template<> mat4 mat4::rotate(float theta, vec3 v) +template<> mat4 mat4::rotate(float angle, vec3 v) +{ + return rotate(angle, v.x, v.y, v.z); +} + +template<> mat4 mat4::lookat(vec3 eye, vec3 center, vec3 up) +{ + vec3 v3 = normalize(eye - center); + vec3 v2 = normalize(up); + vec3 v1 = normalize(cross(v2, v3)); + v2 = cross(v3, v1); + + mat4 orient(1.0f); + orient[0][0] = v1.x; + orient[0][1] = v2.x; + orient[0][2] = v3.x; + orient[1][0] = v1.y; + orient[1][1] = v2.y; + orient[1][2] = v3.y; + orient[2][0] = v1.z; + orient[2][1] = v2.z; + orient[2][2] = v3.z; + + return orient * mat4::translate(-eye); +} + +template<> mat4 mat4::ortho(float left, float right, float bottom, + float top, float near, float far) +{ + float invrl = (right != left) ? 1.0f / (right - left) : 0.0f; + float invtb = (top != bottom) ? 1.0f / (top - bottom) : 0.0f; + float invfn = (far != near) ? 1.0f / (far - near) : 0.0f; + + mat4 ret(0.0f); + ret[0][0] = 2.0f * invrl; + ret[1][1] = 2.0f * invtb; + ret[2][2] = -2.0f * invfn; + ret[3][0] = - (right + left) * invrl; + ret[3][1] = - (top + bottom) * invtb; + ret[3][2] = - (far + near) * invfn; + ret[3][3] = 1.0f; + return ret; +} + +template<> mat4 mat4::frustum(float left, float right, float bottom, + float top, float near, float far) +{ + float invrl = (right != left) ? 1.0f / (right - left) : 0.0f; + float invtb = (top != bottom) ? 1.0f / (top - bottom) : 0.0f; + float invfn = (far != near) ? 1.0f / (far - near) : 0.0f; + + mat4 ret(0.0f); + ret[0][0] = 2.0f * near * invrl; + ret[1][1] = 2.0f * near * invtb; + ret[2][0] = (right + left) * invrl; + ret[2][1] = (top + bottom) * invtb; + ret[2][2] = - (far + near) * invfn; + ret[2][3] = -1.0f; + ret[3][2] = -2.0f * far * near * invfn; + return ret; +} + +template<> mat4 mat4::perspective(float fov_y, float width, + float height, float near, float far) { - return rotate(theta, v.x, v.y, v.z); + fov_y *= (M_PI / 180.0f); + + float t2 = tanf(fov_y * 0.5f); + float t1 = t2 * width / height; + + return frustum(-near * t1, near * t1, -near * t2, near * t2, near, far); } } /* namespace lol */ diff --git a/src/matrix.h b/src/matrix.h index 01f14f52..84331e5b 100644 --- a/src/matrix.h +++ b/src/matrix.h @@ -358,14 +358,29 @@ template struct Mat4 T det() const; Mat4 invert() const; - static Mat4 ortho(T left, T right, T bottom, T top, T near, T far); - static Mat4 frustum(T left, T right, T bottom, T top, T near, T far); - static Mat4 lookat(Vec3 eye, Vec3 center, Vec3 up); - static Mat4 perspective(T theta, T width, T height, T near, T far); + /* Helpers for transformation matrices */ static Mat4 translate(T x, T y, T z); static Mat4 translate(Vec3 v); - static Mat4 rotate(T theta, T x, T y, T z); - static Mat4 rotate(T theta, Vec3 v); + static Mat4 rotate(T angle, T x, T y, T z); + static Mat4 rotate(T angle, Vec3 v); + + static inline Mat4 translate(Mat4 mat, Vec3 v) + { + return translate(v) * mat; + } + + static inline Mat4 rotate(Mat4 mat, T angle, Vec3 v) + { + return rotate(angle, v) * mat; + } + + /* Helpers for view matrices */ + static Mat4 lookat(Vec3 eye, Vec3 center, Vec3 up); + + /* Helpers for projection matrices */ + static Mat4 ortho(T left, T right, T bottom, T top, T near, T far); + static Mat4 frustum(T left, T right, T bottom, T top, T near, T far); + static Mat4 perspective(T fov_y, T width, T height, T near, T far); void printf() const; diff --git a/src/scene.cpp b/src/scene.cpp index 652c82e9..790acd37 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -287,8 +287,8 @@ void Scene::Render() // XXX: rename to Blit() #if 0 static float f = 0.0f; f += 0.01f; - data->model_matrix *= mat4::rotate(0.1f * sinf(f), 1.0f, 0.0f, 0.0f); - data->model_matrix *= mat4::rotate(0.3f * cosf(f), 0.0f, 0.0f, 1.0f); + data->model_matrix *= mat4::rotate(6.0f * sinf(f), 1.0f, 0.0f, 0.0f); + data->model_matrix *= mat4::rotate(17.0f * cosf(f), 0.0f, 0.0f, 1.0f); #endif data->model_matrix *= mat4::translate(-320.0f, -240.0f, 0.0f); // XXX: end of debug stuff diff --git a/src/video.cpp b/src/video.cpp index 6919dd4c..102e1372 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -17,6 +17,8 @@ #if defined _WIN32 && !defined _XBOX # define WIN32_LEAN_AND_MEAN # include +# undef near /* Fuck Microsoft */ +# undef far /* Fuck Microsoft again */ #endif #include "core.h" @@ -79,8 +81,6 @@ void Video::Setup(ivec2 size) void Video::SetFov(float theta) { -#undef near /* Fuck Microsoft */ -#undef far /* Fuck Microsoft again */ vec2 size = GetSize(); float near = -size.x - size.y; float far = size.x + size.y;