Browse Source

core: fix bugs in mat4::lookat() and mat4::perspective(), and ensure these

function use degrees rather than radians.
legacy
Sam Hocevar gary 13 years ago
parent
commit
3978ea9e2a
4 changed files with 111 additions and 82 deletions
  1. +86
    -72
      src/matrix.cpp
  2. +21
    -6
      src/matrix.h
  3. +2
    -2
      src/scene.cpp
  4. +2
    -2
      src/video.cpp

+ 86
- 72
src/matrix.cpp View File

@@ -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 <windows.h>
# undef near /* Fuck Microsoft */
# undef far /* Fuck Microsoft again */
#endif

#include <cmath> /* for M_PI */
#include <cstdlib> /* free() */
#include <cstring> /* 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 */


+ 21
- 6
src/matrix.h View File

@@ -358,14 +358,29 @@ template <typename T> struct Mat4
T det() const;
Mat4<T> invert() const;

static Mat4<T> ortho(T left, T right, T bottom, T top, T near, T far);
static Mat4<T> frustum(T left, T right, T bottom, T top, T near, T far);
static Mat4<T> lookat(Vec3<T> eye, Vec3<T> center, Vec3<T> up);
static Mat4<T> perspective(T theta, T width, T height, T near, T far);
/* Helpers for transformation matrices */
static Mat4<T> translate(T x, T y, T z);
static Mat4<T> translate(Vec3<T> v);
static Mat4<T> rotate(T theta, T x, T y, T z);
static Mat4<T> rotate(T theta, Vec3<T> v);
static Mat4<T> rotate(T angle, T x, T y, T z);
static Mat4<T> rotate(T angle, Vec3<T> v);

static inline Mat4<T> translate(Mat4<T> mat, Vec3<T> v)
{
return translate(v) * mat;
}

static inline Mat4<T> rotate(Mat4<T> mat, T angle, Vec3<T> v)
{
return rotate(angle, v) * mat;
}

/* Helpers for view matrices */
static Mat4<T> lookat(Vec3<T> eye, Vec3<T> center, Vec3<T> up);

/* Helpers for projection matrices */
static Mat4<T> ortho(T left, T right, T bottom, T top, T near, T far);
static Mat4<T> frustum(T left, T right, T bottom, T top, T near, T far);
static Mat4<T> perspective(T fov_y, T width, T height, T near, T far);

void printf() const;



+ 2
- 2
src/scene.cpp View File

@@ -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


+ 2
- 2
src/video.cpp View File

@@ -17,6 +17,8 @@
#if defined _WIN32 && !defined _XBOX
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# 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;


Loading…
Cancel
Save