Yet another glOrtho, glFrustum & gluPerspective (OpenGL)
Posted: Sun Dec 02, 2012 9:29 pm
I've done a little bit of clean-up in my OpenGL projection routines and put the resulting source code here (see below). You might find it handy if you are looking for a replacement for glOrtho, glFrustum or gluPerspective, especially if you've just switched from the fixed to programmable graphics pipeline and found out that these routines are not available any more.
ma_matrix4_projection.h
ma_matrix4_projection.inl
glOrtho() equivalent:
glFrustum() equivalent:
gluPerspective() equivalent:
ma_matrix4_projection.h
ma_matrix4_projection.inl
glOrtho() equivalent:
Code: Select all
template <typename T>
inline Matrix4<T> make_ortho(T left, T right, T bottom, T top, T znear, T zfar)
{
// from OpenGL spec PDF: can be rewritten as:
// / 2/(r-l) 0 0 -(r+l)/(r-l) \ / 2/(r-l) 0 0 (r+l)/(l-r) \
// | 0 2/(t-b) 0 -(t+b)/(t-b) | => | 0 2/(t-b) 0 (t+b)/(b-t) |
// | 0 0 -2/(f-n) -(f+n)/(f-n) | | 0 0 2/(n-f) (f+n)/(n-f) |
// \ 0 0 0 1 / \ 0 0 0 1 /
// invalid for: l=r, b=t, or n=f
FS_ASSERT(left != right);
FS_ASSERT(bottom != top);
FS_ASSERT(znear != zfar);
const T p_fn = zfar + znear;
const T m_nf = znear - zfar; // ~ -m_fn
const T p_rl = right + left;
const T m_rl = right - left;
const T p_tb = top + bottom;
const T m_tb = top - bottom;
const T m_lr = -m_rl;
const T m_bt = -m_tb;
return Matrix4<T>(
T(2)/m_rl, T(0), T(0), p_rl/m_lr,
T(0), T(2)/m_tb, T(0), p_tb/m_bt,
T(0), T(0), T(2)/m_nf, p_fn/m_nf,
T(0), T(0), T(0), T(1)
);
}
Code: Select all
template <typename T>
inline Matrix4<T> make_frustum(T left, T right, T bottom, T top, T znear, T zfar)
{
// from OpenGL spec PDF: can be rewritten as:
// / 2n/(r-l) 0 (r+l)/(r-l) 0 \ / 2n/(r-l) 0 (r+l)/(r-l) 0 \
// | 0 2n/(t-b) (t+b)/(t-b) 0 | => | 0 2n/(t-b) (t+b)/(t-b) 0 |
// | 0 0 -(f+n)/(f-n) -2fn/(f-n) | | 0 0 (f+n)/(n-f) 2fn/(n-f) |
// \ 0 0 -1 0 / \ 0 0 -1 0 /
// invalid for: n<=0, f<=0, l=r, b=t, or n=f
FS_ASSERT(znear > T(0));
FS_ASSERT(zfar > T(0));
FS_ASSERT(left != right);
FS_ASSERT(bottom != top);
FS_ASSERT(znear != zfar);
const T x_2n = znear + znear;
const T x_2nf = T(2) * znear * zfar;
const T p_fn = zfar + znear;
const T m_nf = znear - zfar; // ~ -m_fn
const T p_rl = right + left;
const T m_rl = right - left;
const T p_tb = top + bottom;
const T m_tb = top - bottom;
return Matrix4<T>(
x_2n/m_rl, T(0), p_rl/m_rl, T(0),
T(0), x_2n/m_tb, p_tb/m_tb, T(0),
T(0), T(0), p_fn/m_nf, x_2nf/m_nf,
T(0), T(0), T(-1), T(0)
);
}
Code: Select all
template <typename T>
inline Matrix4<T> make_perspective(T fovy_deg, T aspect, T znear, T zfar)
{
// from OpenGL spec PDF: can be rewritten as:
// / c/a 0 0 0 \ / c/a 0 0 0 \
// | 0 c 0 0 | ==> | 0 c 0 0 |
// | 0 0 -(f+n)/(f-n) -2nf/(f+n) | | 0 0 (f+n)/(n-f) 2nf/(n-f) |
// \ 0 0 -1 0 / \ 0 0 -1 0 /
FS_ASSERT(znear > T(0));
FS_ASSERT(zfar > T(0));
FS_ASSERT(aspect != T(0));
FS_ASSERT(znear != zfar);
const T half_fovy_rad = T(M_PI) * fovy_deg / T(360);
const auto si_co = sin_cos(half_fovy_rad);
const T si = si_co.first;
const T co = si_co.second;
FS_ASSERT(si != T(0));
const T c = co / si; // cotangent
const T a = aspect;
const T x_2nf = T(2) * znear * zfar;
const T p_fn = zfar + znear;
const T m_nf = znear - zfar;
return Matrix4<T>(
c/a, T(0), T(0), T(0),
T(0), c, T(0), T(0),
T(0), T(0), p_fn/m_nf, x_2nf/m_nf,
T(0), T(0), T(-1), T(0)
);
}