Sign in to follow this  
myers

Oblique plane clipping artifacts

Recommended Posts

I've been playing around with Eric Lengyel's famous oblique plane clipping code, and I can't stop the z-buffer precision from being badly reduced. I keep getting these depth artifacts where fragments that should be occluded are showing through, even very close to the near clipping plane. These artifacts are so bad that I can't see how the technique is really useable for, say, reflections. So I was wondering: does anyone actually use the near plane for oblique clipping, or is it standard just to create extra clip planes?

Share this post


Link to post
Share on other sites
Okay, er, I've tried to tidy up the code for human consumption, so I've probably inserted many new errors. But here goes.

This transforms the clip plane from world to camera space:


vector4D cameraspace_plane()
{
vector4D plane;
matrix4x4 modelview;
float A, B, C;
float pX, pY, pZ, pW; //transformed point
float nX, nY, nZ, nW, inverse_normal_length; //transformed normal

glGetFloatv(GL_MODELVIEW_MATRIX, modelview);

A = 0;
B = 0;
C = 0;
pX = A*modelview[0] + B*modelview[4] + C*modelview[8] + modelview[12];
pY = A*modelview[1] + B*modelview[5] + C*modelview[9] + modelview[13];
pZ = A*modelview[2] + B*modelview[6] + C*modelview[10] + modelview[14];
pW = 1;
//transforming normal
A = 0;
B = 1;
= 0;
nX = A*modelview[0] + B*modelview[4] + C*modelview[8];
nY = A*modelview[1] + B*modelview[5] + C*modelview[9];
Z = A*modelview[2] + B*modelview[6] + C*modelview[10];
nW = 0;
//normalize
inverse_normal_length = 1/ sqrtf( nX*nX + nY*nY + nZ*nZ );
nX *= inverse_normal_length;
nY *= inverse_normal_length;
nZ *= inverse_normal_length;
//clip plane values
plane.x = nX;
plane.y = nY;
plane.z = nZ;
//dot between normal and point
plane.w = -(pX*nX + pY*nY + pZ*nZ);

return plane;
}




This returns the modelview matrix we want:


matrix4x4 set_modelview()
{
matrix4x4 modelview;

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//Rotate and transform
if(camera.orientation.w<1 && camera.orientation.w>-1)
glRotatef(theta, camera.orientation.x, camera.orientation.y, camera.orientation.z);
glTranslatef(-camera.position.x, -camera.position.y, -camera.position.z);

glGetFloatv(GL_MODELVIEW_MATRIX,modelview);

return modelview;
}




And this sets the modelview and projection matrices, the latter of which has Eric Lengyel's transformations applied to it:


void set_camera()
{
//Obtain modelview matrix
matrix4x4 modelview=set_modelview();

//Transform the clip plane to camera space
vector4D plane=cameraspace_plane();

//Set projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

gluPerspective(45.0f, 1.333f, 1.0f, 1024.0f);

//Eric's routine
ModifyProjectionMatrix(plane);

//Set modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLoadMatrixf(modelview);

//Render etc.
}




What's strange is that everything is fine apart from the z-buffer artifacts. The near plane seems to be set where I want it to be. I guess something must be amiss with the far plane?

Share this post


Link to post
Share on other sites
Hi --

Famous, eh? The projection matrix technique does unavoidably reduce the z-buffer precision, but unless you're creating an extreme case specifically designed to break it, you shouldn't see a problem. I use the technique for a lot of things (water, mirrors, etc.) without problems.

What you're seeing probably means that the clipping plane isn't in the right place in camera space. Make sure that all of the following are true:

1) Your clipping plane normal points away from the camera position C. That is, the camera is on the negative side of the plane P. If the dot product (Px,Py,Pz,Pw) * (Cx,Cy,Cz,1) isn't negative, then negate all four components of your clipping plane.

2) You're transforming the clipping plane from the correct space into camera space. Is your clipping plane in world space or the local space of some object?

3) You're transforming the clipping plane into camera space with the right mathematical transform. A 4D vector P representing a plane is transformed by a 4x4 matrix M by computing P' = P * Inverse(M).

I noticed you're transforming the plane normal and a point on the plane separately, but it's much better to just transform a whole 4D plane vector at once. (Your calculation looks right, but it's more work.)

One other thing to note is that you don't have to renormalize the plane once it's been transformed. It gets normalized implicitly when the new projection matrix is calculated.

Share this post


Link to post
Share on other sites
Quote:
Original post by Eric Lengyel
Hi --

Famous, eh?


Well, it's mentioned in at least three GameDev threads. That probably makes you famous enough to go on Celebrity Big Brother. :)

Quote:
What you're seeing probably means that the clipping plane isn't in the right place in camera space. Make sure that all of the following are true:

1) Your clipping plane normal points away from the camera position C. That is, the camera is on the negative side of the plane P. If the dot product (Px,Py,Pz,Pw) * (Cx,Cy,Cz,1) isn't negative, then negate all four components of your clipping plane.


The normal did point away from the camera (P.C<0), but since you mentioned it I thought I'd negate the plane components anyway just to see what happened. I expected this would just flip the plane - i.e. clip everything in front of it, rather than behind it. It did - but the z-artifacts were gone! So then it was just a matter of inverting the plane normal to get the clip space I wanted. It's fair to say I don't really understand why it's working now (maybe the sign of the plane's d component was wrong?). But oh well!

Incidentally, the artifacts return if I move the camera to a position co-planar with the clip plane. I guess that makes sense, though, and for reflections, at least, it doesn't matter.

Quote:
I noticed you're transforming the plane normal and a point on the plane separately, but it's much better to just transform a whole 4D plane vector at once. (Your calculation looks right, but it's more work.)


D'oh. Yes, thanks.

Quote:
One other thing to note is that you don't have to renormalize the plane once it's been transformed. It gets normalized implicitly when the new projection matrix is calculated.


Ah, righto.

Looks like your code's okay after all, then. You can sleep easy again!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this