Compute frustum planes from corner points

Started by
3 comments, last by Vexator 12 years, 5 months ago
Guys, you have to help me, this is driving me crazy. I've implemented frustum culling a while ago, based on the article by lighthouse3D. Computing the frustum planes from the view and projection matrices directly works perfectly fine; but I'd like to compute them from the frustum corners instead as I need those for debug rendering and the generation of portal frustums.


The clip space approach creates a perfect frustum (original source: http://www.lighthous...tation-details/)


void Frustum::compute( const mat4 &viewMatrix, const mat4 &projectionMatrix )
{
const mat4 &v = viewMatrix;
const mat4 &p = projectionMatrix;

mat4 clipMatrix;

clipMatrix[0][0] = v[0][0]*p[0][0]+v[0][1]*p[1][0]+v[0][2]*p[2][0]+v[0][3]*p[3][0];
clipMatrix[1][0] = v[0][0]*p[0][1]+v[0][1]*p[1][1]+v[0][2]*p[2][1]+v[0][3]*p[3][1];
clipMatrix[2][0] = v[0][0]*p[0][2]+v[0][1]*p[1][2]+v[0][2]*p[2][2]+v[0][3]*p[3][2];
clipMatrix[3][0] = v[0][0]*p[0][3]+v[0][1]*p[1][3]+v[0][2]*p[2][3]+v[0][3]*p[3][3];
clipMatrix[0][1] = v[1][0]*p[0][0]+v[1][1]*p[1][0]+v[1][2]*p[2][0]+v[1][3]*p[3][0];
clipMatrix[1][1] = v[1][0]*p[0][1]+v[1][1]*p[1][1]+v[1][2]*p[2][1]+v[1][3]*p[3][1];
clipMatrix[2][1] = v[1][0]*p[0][2]+v[1][1]*p[1][2]+v[1][2]*p[2][2]+v[1][3]*p[3][2];
clipMatrix[3][1] = v[1][0]*p[0][3]+v[1][1]*p[1][3]+v[1][2]*p[2][3]+v[1][3]*p[3][3];
clipMatrix[0][2] = v[2][0]*p[0][0]+v[2][1]*p[1][0]+v[2][2]*p[2][0]+v[2][3]*p[3][0];
clipMatrix[1][2] = v[2][0]*p[0][1]+v[2][1]*p[1][1]+v[2][2]*p[2][1]+v[2][3]*p[3][1];
clipMatrix[2][2] = v[2][0]*p[0][2]+v[2][1]*p[1][2]+v[2][2]*p[2][2]+v[2][3]*p[3][2];
clipMatrix[3][2] = v[2][0]*p[0][3]+v[2][1]*p[1][3]+v[2][2]*p[2][3]+v[2][3]*p[3][3];
clipMatrix[0][3] = v[3][0]*p[0][0]+v[3][1]*p[1][0]+v[3][2]*p[2][0]+v[3][3]*p[3][0];
clipMatrix[1][3] = v[3][0]*p[0][1]+v[3][1]*p[1][1]+v[3][2]*p[2][1]+v[3][3]*p[3][1];
clipMatrix[2][3] = v[3][0]*p[0][2]+v[3][1]*p[1][2]+v[3][2]*p[2][2]+v[3][3]*p[3][2];
clipMatrix[3][3] = v[3][0]*p[0][3]+v[3][1]*p[1][3]+v[3][2]*p[2][3]+v[3][3]*p[3][3];

m_planes[PLANE_RIGHT].x = clipMatrix[3][0]-clipMatrix[0][0];
m_planes[PLANE_RIGHT].y = clipMatrix[3][1]-clipMatrix[0][1];
m_planes[PLANE_RIGHT].z = clipMatrix[3][2]-clipMatrix[0][2];
m_planes[PLANE_RIGHT].w = clipMatrix[3][3]-clipMatrix[0][3];

m_planes[PLANE_LEFT].x = clipMatrix[3][0]+clipMatrix[0][0];
m_planes[PLANE_LEFT].y = clipMatrix[3][1]+clipMatrix[0][1];
m_planes[PLANE_LEFT].z = clipMatrix[3][2]+clipMatrix[0][2];
m_planes[PLANE_LEFT].w = clipMatrix[3][3]+clipMatrix[0][3];

m_planes[PLANE_BOTTOM].x = clipMatrix[3][0]+clipMatrix[1][0];
m_planes[PLANE_BOTTOM].y = clipMatrix[3][1]+clipMatrix[1][1];
m_planes[PLANE_BOTTOM].z = clipMatrix[3][2]+clipMatrix[1][2];
m_planes[PLANE_BOTTOM].w = clipMatrix[3][3]+clipMatrix[1][3];

m_planes[PLANE_TOP].x = clipMatrix[3][0]-clipMatrix[1][0];
m_planes[PLANE_TOP].y = clipMatrix[3][1]-clipMatrix[1][1];
m_planes[PLANE_TOP].z = clipMatrix[3][2]-clipMatrix[1][2];
m_planes[PLANE_TOP].w = clipMatrix[3][3]-clipMatrix[1][3];

m_planes[PLANE_BACK].x = clipMatrix[3][0]-clipMatrix[2][0];
m_planes[PLANE_BACK].y = clipMatrix[3][1]-clipMatrix[2][1];
m_planes[PLANE_BACK].z = clipMatrix[3][2]-clipMatrix[2][2];
m_planes[PLANE_BACK].w = clipMatrix[3][3]-clipMatrix[2][3];

m_planes[PLANE_FRONT].x = clipMatrix[3][0]+clipMatrix[2][0];
m_planes[PLANE_FRONT].y = clipMatrix[3][1]+clipMatrix[2][1];
m_planes[PLANE_FRONT].z = clipMatrix[3][2]+clipMatrix[2][2];
m_planes[PLANE_FRONT].w = clipMatrix[3][3]+clipMatrix[2][3];

for( int i = 0; i < 6; i++ )
{
m_planes = glm::normalize( m_planes );
}}


The geometric approach, which computes the frustums corners first, fails.. my geometry is sometimes clipped when it shouldn't and not clipped when it should be (source: http://www.lighthous...implementation/)

vec4 planeFromPoints( vec3 &v1, vec3 &v2, vec3 &v3)
{
vec3 aux1, aux2;

aux1 = v1 - v2;
aux2 = v3 - v2;

vec3 normal = glm::normalize(aux2 * aux1);

float d = (glm::dot(normal, v2));

return vec4( normal, d);
}

#define ANG2RAD 3.14159265358979323846/180.0f

void Frustum::compute( const mat4 &viewMatrix, float angle, float ratio, float nearD, float farD )
{
float tang = (float)tan( ANG2RAD * angle * 0.5 ) ;

float nh = nearD * tang;
float nw = nh * ratio;
float fh = farD * tang;
float fw = fh * ratio;

// this is the only thing i've changed:
// extract view vectors from view matrix
vec3 s = vec3( viewMatrix[0] );
vec3 u = vec3( viewMatrix[1] );
vec3 f = vec3( viewMatrix[2] );
vec3 eye = vec3( -viewMatrix[3] );

vec3 nc = eye - f * nearD;
vec3 fc = eye - f * farD;

// near plane corners
vec3 ntl = nc + u * nh - s * nw;
vec3 ntr = nc + u * nh + s * nw;
vec3 nbl = nc - u * nh - s * nw;
vec3 nbr = nc - u * nh + s * nw;

// far plane corners
vec3 ftl = fc + u * fh - s * fw;
vec3 ftr = fc + u * fh + s * fw;
vec3 fbl = fc - u * fh - s * fw;
vec3 fbr = fc - u * fh + s * fw;

m_planes[PLANE_TOP] = planeFromPoints( ntr, ntl, ftl );
m_planes[PLANE_BOTTOM] = planeFromPoints( nbl, nbr, fbr );
m_planes[PLANE_LEFT] = planeFromPoints( ntl, nbl,fbl );
m_planes[PLANE_RIGHT] = planeFromPoints( nbr, ntr, fbr );
m_planes[PLANE_BACK] = planeFromPoints( ntl, ntr, nbr );
m_planes[PLANE_FRONT] = planeFromPoints( ftr, ftl, fbl );}


I just can't spot the error - do you see what's wrong? Thank you!
Wunderwerk Engine is an OpenGL-based, shader-driven, cross-platform game engine. It is targeted at aspiring game designers who have been kept from realizing their ideas due to lacking programming skills.

blog.wunderwerk-engine.com
Advertisement
This is not answering your question, but you could stick with calculating the frustum from the view * proj matrix and get the corner points by intersecting the planes instead. That is how I do it.

Otherwise, have you checked that your planes are all facing the right direction?
would you show me how you calculate[color=#1C2837][size=2] the corner points by intersecting the planes? i could then render the "working" frustum planes to narrow down the problem.
Wunderwerk Engine is an OpenGL-based, shader-driven, cross-platform game engine. It is targeted at aspiring game designers who have been kept from realizing their ideas due to lacking programming skills.

blog.wunderwerk-engine.com
This is the code I am using:


static Vector3 intersection(const Plane &p0, const Plane &p1, const Plane &p2)
{
Vector3 n1(p0.a, p0.b, p0.c);
float d1 = p0.d;

Vector3 n2(p1.a, p1.b, p1.c);
float d2 = p1.d;

Vector3 n3(p2.a, p2.b, p2.c);
float d3 = p2.d;


// d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 )
//P = ------------------------------------------------
// N1 . ( N2 * N3 )

return -(d1 * cross(n2, n3) + d2 * cross(n3, n1) + d3 * cross(n1, n2)) / dot(n1, (cross(n2, n3)));
}


Maybe you have to invert the sign of the resulting point.
great, thank you!
Wunderwerk Engine is an OpenGL-based, shader-driven, cross-platform game engine. It is targeted at aspiring game designers who have been kept from realizing their ideas due to lacking programming skills.

blog.wunderwerk-engine.com

This topic is closed to new replies.

Advertisement