Skip to content

Instantly share code, notes, and snippets.

@BlockoS
Created November 29, 2009 21:53
Show Gist options
  • Save BlockoS/245086 to your computer and use it in GitHub Desktop.
Save BlockoS/245086 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <string.h>
#include "Frustum.h"
Frustum::Frustum() :
m_x(1.0f, 0.0f, 0.0f),
m_y(0.0f, 1.0f, 0.0f),
m_z(0.0f, 0.0f, 1.0f),
m_position(0.0f, 0.0f, -1.0f),
m_near(0.1f),
m_far(10.0f)
{}
Frustum::~Frustum()
{}
void Frustum::LookAt( const vec3& eye,
const vec3& target,
const vec3& up )
{
m_position = eye;
vsub(m_z, target, eye);
vnormalize(m_z);
// x = z * up
vcross(m_x, m_z, up);
vnormalize(m_x);
// y = x * z;
vcross(m_y, m_x, m_z);
vnormalize(m_y);
ComputeModelview();
}
void Frustum::ComputeModelview ()
{
m_modelview.data[ 0] = m_x.x;
m_modelview.data[ 4] = m_x.y;
m_modelview.data[ 8] = m_x.z;
m_modelview.data[12] = -vdot(m_x, m_position);
m_modelview.data[ 1] = m_y.x;
m_modelview.data[ 5] = m_y.y;
m_modelview.data[ 9] = m_y.z;
m_modelview.data[13] = -vdot(m_y, m_position);
m_modelview.data[ 2] = -m_z.x;
m_modelview.data[ 6] = -m_z.y;
m_modelview.data[10] = -m_z.z;
m_modelview.data[14] = vdot(m_z, m_position);
m_modelview.data[ 3] = 0.0f;
m_modelview.data[ 7] = 0.0f;
m_modelview.data[11] = 0.0f;
m_modelview.data[15] = 1.0f;
//--
m_inverseModelview.data[ 0] = m_modelview.data[ 0];
m_inverseModelview.data[ 4] = m_modelview.data[ 1];
m_inverseModelview.data[ 8] = m_modelview.data[ 2];
m_inverseModelview.data[12] = -m_modelview.data[12];
m_inverseModelview.data[ 1] = m_modelview.data[ 4];
m_inverseModelview.data[ 5] = m_modelview.data[ 5];
m_inverseModelview.data[ 9] = m_modelview.data[ 6];
m_inverseModelview.data[13] = -m_modelview.data[13];
m_inverseModelview.data[ 2] = m_modelview.data[ 8];
m_inverseModelview.data[ 6] = m_modelview.data[ 9];
m_inverseModelview.data[10] = m_modelview.data[10];
m_inverseModelview.data[14] = -m_modelview.data[14];
m_inverseModelview.data[ 3] = 0.0f;
m_inverseModelview.data[ 7] = 0.0f;
m_inverseModelview.data[11] = 0.0f;
m_inverseModelview.data[15] = 1.0f;
}
Ortho::Ortho() :
Frustum(),
m_translate(-0.0f, -0.0f, -10.1f / 9.9f),
m_nearPoint(1.0f, 1.0f, -2.0f / 9.9f)
{
m_box.min.x = -1.0f;
m_box.min.y = -1.0f;
m_box.min.z = 0.1f;
m_box.max.x = 1.0f;
m_box.max.y = 1.0f;
m_box.max.z = 10.0f;
ComputeProjection();
ComputeModelview();
}
Ortho::~Ortho(){}
void Ortho::Update(float left, float right,
float bottom, float top,
float near, float far)
{
m_near = near;
m_far = far;
m_translate.x = (right + left) / (left - right);
m_translate.y = (top + bottom) / (bottom - top);
m_translate.z = (far + near) / (near - far);
m_nearPoint.x = 2.0f / (right - left);
m_nearPoint.y = 2.0f / (top - bottom);
m_nearPoint.z = -2.0f / (far - near);
m_box.min.x = left;
m_box.min.y = bottom;
m_box.min.z = near;
m_box.max.x = right;
m_box.max.y = top;
m_box.max.z = far;
ComputeProjection();
}
void Ortho::ComputeProjection ()
{
memset(m_projection.data, 0, sizeof(float[16]));
m_projection.data[ 0] = m_nearPoint.x;
m_projection.data[ 5] = m_nearPoint.y;
m_projection.data[10] = m_nearPoint.z;
m_projection.data[12] = m_translate.x;
m_projection.data[13] = m_translate.y;
m_projection.data[14] = m_translate.z;
m_projection.data[15] = 1.0;
}
bool Ortho::Contains(const vec3& v) const
{
vec3 u;
mPointMul (u, m_modelview, v);
return m_box.contains(u);
}
int Ortho::Contains(const aabb& b) const
{
aabb tb;
mPointMul (tb.min, m_modelview, b.min);
mPointMul (tb.max, m_modelview, b.max);
return m_box.intersects(tb) ? 0 : -1;
}
Perspective::Perspective() :
Frustum()
{
m_tang = tan(m_fov);
m_height = m_near * m_tang;
m_width = m_height * m_ratio;
ComputeProjection();
ComputeModelview();
ComputePlaneEquations();
}
Perspective::~Perspective()
{}
void Perspective::LookAt( const vec3& eye,
const vec3& target,
const vec3& up )
{
Frustum::LookAt(eye, target, up);
ComputePlaneEquations();
}
void Perspective::Update( float angle,
float aspectRatio,
float near,
float far )
{
m_ratio = aspectRatio;
m_fov = (float(M_PI) * angle) / 360.0f;
m_tang = tan(m_fov);
m_near = near;
m_far = far;
m_height = m_near * m_tang;
m_width = m_height * m_ratio;
ComputeProjection();
ComputePlaneEquations();
}
void Perspective::ComputePlaneEquations()
{
float t;
float clip[16];
clip[ 0] = m_modelview.data[ 0] * m_projection.data[ 0];
clip[ 1] = m_modelview.data[ 1] * m_projection.data[ 5];
clip[ 2] = m_modelview.data[ 2] * m_projection.data[10];
clip[ 3] = -m_modelview.data[ 2];
clip[ 4] = m_modelview.data[ 4] * m_projection.data[ 0];
clip[ 5] = m_modelview.data[ 5] * m_projection.data[ 5];
clip[ 6] = m_modelview.data[ 6] * m_projection.data[10];
clip[ 7] = -m_modelview.data[ 6];
clip[ 8] = m_modelview.data[ 8] * m_projection.data[ 0];
clip[ 9] = m_modelview.data[ 9] * m_projection.data[ 5];
clip[10] = m_modelview.data[10] * m_projection.data[10];
clip[11] = -m_modelview.data[10];
clip[12] = m_modelview.data[12] * m_projection.data[ 0];
clip[13] = m_modelview.data[13] * m_projection.data[ 5];
clip[14] = m_modelview.data[14] * m_projection.data[10] + m_projection.data[14];
clip[15] = -m_modelview.data[14];
// right
m_plane[0] = clip[ 3] - clip[ 0];
m_plane[1] = clip[ 7] - clip[ 4];
m_plane[2] = clip[11] - clip[ 8];
m_plane[3] = clip[15] - clip[12];
t = sqrt( m_plane[0] * m_plane[0] + m_plane[1] * m_plane[1] + m_plane[2] * m_plane[2] );
m_plane[0] /= t;
m_plane[1] /= t;
m_plane[2] /= t;
m_plane[3] /= t;
// left
m_plane[4] = clip[ 3] + clip[ 0];
m_plane[5] = clip[ 7] + clip[ 4];
m_plane[6] = clip[11] + clip[ 8];
m_plane[7] = clip[15] + clip[12];
t = sqrt( m_plane[4] * m_plane[4] + m_plane[5] * m_plane[5] + m_plane[6] * m_plane[6] );
m_plane[4] /= t;
m_plane[5] /= t;
m_plane[6] /= t;
m_plane[7] /= t;
// bottom
m_plane[8] = clip[ 3] + clip[ 1];
m_plane[9] = clip[ 7] + clip[ 5];
m_plane[10] = clip[11] + clip[ 9];
m_plane[11] = clip[15] + clip[13];
t = sqrt( m_plane[8] * m_plane[8] + m_plane[9] * m_plane[9] + m_plane[10] * m_plane[10] );
m_plane[8] /= t;
m_plane[9] /= t;
m_plane[10] /= t;
m_plane[11] /= t;
// top
m_plane[12] = clip[ 3] - clip[ 1];
m_plane[13] = clip[ 7] - clip[ 5];
m_plane[14] = clip[11] - clip[ 9];
m_plane[15] = clip[15] - clip[13];
t = sqrt( m_plane[12] * m_plane[12] + m_plane[13] * m_plane[13] + m_plane[14] * m_plane[14] );
m_plane[12] /= t;
m_plane[13] /= t;
m_plane[14] /= t;
m_plane[15] /= t;
// far
m_plane[16] = clip[ 3] - clip[ 2];
m_plane[17] = clip[ 7] - clip[ 6];
m_plane[18] = clip[11] - clip[10];
m_plane[19] = clip[15] - clip[14];
t = sqrt( m_plane[16] * m_plane[16] + m_plane[17] * m_plane[17] + m_plane[18] * m_plane[18] );
m_plane[16] /= t;
m_plane[17] /= t;
m_plane[18] /= t;
m_plane[19] /= t;
// near
m_plane[20] = clip[ 3] + clip[ 2];
m_plane[21] = clip[ 7] + clip[ 6];
m_plane[22] = clip[11] + clip[10];
m_plane[23] = clip[15] + clip[14];
t = sqrt( m_plane[20] * m_plane[20] + m_plane[21] * m_plane[21] + m_plane[22] * m_plane[22] );
m_plane[20] /= t;
m_plane[21] /= t;
m_plane[22] /= t;
m_plane[23] /= t;
}
bool Perspective::Contains(const vec3& iP) const
{
float pcz;
float pcx;
float pcy;
float aux;
vec3 v;
vsub(v, iP, m_position);
pcz = vdot(v, m_z);
if(( pcz > m_far ) || ( pcz < m_near ))
return false;
pcy = vdot(v, m_y);
aux = pcz * m_tang;
if(( pcy > aux ) || ( pcy < -aux ))
return false;
pcx = vdot(v, m_x);
aux *= m_ratio;
if(( pcx > aux ) || ( pcx < -aux ))
return false;
return true;
}
int Perspective::Contains(const aabb& iB) const
{
int intersect = 0;
int test = 0;
for(int i=0; i<6; ++i){
test = iB.intersects(m_plane + (i * 4));
if(test < 0)
return -1;
if(test > 0)
intersect = 1;
}
return intersect;
}
void Perspective::ComputeProjection()
{
memset(m_projection.data, 0, sizeof(float[16]));
m_projection.data[ 0] = 1.0f / (m_ratio * m_tang);
m_projection.data[ 5] = 1.0f / m_tang;
m_projection.data[10] = (m_far + m_near) / (m_near - m_far);
m_projection.data[14] = 2.0f * m_far * m_near / (m_near - m_far);
m_projection.data[11] = -1.0f;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment