Archive for the ‘OpenGL’ category

Using glClipPlanes and plane equations

5.10.2010

About a year ago, I searched for an OpenGL way of clipping a rectangle in 2D/3D space. To explain further: I’m making a GUI library with OpenGL, and I wanted a parent rectangle to be able to clip it’s child rectangles even if they were textured. I found glClipPlane, and tried it briefly. There was almost no documentation found, or it was very mathematical talking about plane equations without properly explaining how it should be transferred to code. I also could not find any coding examples of using them.

So, I spent about three months writing a system that would do this clipping in software. For flat rectangles this was easy, but for textured stuff it was very complex, as it was manipulating the texturecoords to get the clipping done. I somehow managed to write it, but the system was incomprehensible, added some software overhead, didn’t properly support my per widget zooming system, and I had to put all my OpenGL drawing inside this clipping subsystem. For about a year I was semi-satisfied with it, but as I changed to another way of drawing fonts, I needed either a new clipping system, or I’d have to adapt the external font code to my awful clipping system.

Then I did another search and found this page: http://local.wasp.uwa.edu.au/~pbourke/geometry/planeeq/

It’s dated 1989, and it’s another one of those mathematicians only explanations (I’m a pragmatic self-taught trial-by-error coder, with very poor mathematical knowledge, sorry). But for the first time it had something that looked a bit like pseudo-code and translated well into programming. So, I tested it and with a few first misses I was able to get the following code of it, that works for me. I’m not sure if this is the correct or best way of using plane equations, but it’s the only one that I’ve gotten working.

double[] planeEquation( float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)
{
double[] eq = new double[4];
eq[0] = (y1*(z2 – z3)) + (y2*(z3 – z1)) + (y3*(z1 – z2));
eq[1] = (z1*(x2 – x3)) + (z2*(x3 – x1)) + (z3*(x1 – x2));
eq[2] = (x1*(y2 – y3)) + (x2*(y3 – y1)) + (x3*(y1 – y2));
eq[3] = -((x1*((y2*z3) – (y3*z2))) + (x2*((y3*z1) – (y1*z3))) + (x3*((y1*z2) – (y2*z1))));
return eq;
}

Horrible formatting there. I don’t know how to use wordpress to get the code looking correct…

Then I’m doing the following on each parent rectangle, just before starting to translate or draw the children:

double[] left_eq = planeEquation(ix1,iy1,iz, ix1,iy2,iz, ix1,iy2,iz+1.0f);

glClipPlane(GL_CLIP_PLANE0, left_eq.ptr);

glEnable(GL_CLIP_PLANE0);

delete left_eq;

double[] right_eq = planeEquation(ix2,iy1,iz, ix2,iy2,iz, ix2,iy2,iz-1.0f);

glClipPlane(GL_CLIP_PLANE1, right_eq.ptr);

glEnable(GL_CLIP_PLANE1);

delete right_eq;

double[] top_eq = planeEquation(ix1,iy1,iz, ix2,iy1,iz, ix2,iy1,iz-1.0f);

glClipPlane(GL_CLIP_PLANE2, top_eq.ptr);

glEnable(GL_CLIP_PLANE2);

delete top_eq;

double[] bottom_eq = planeEquation(ix1,iy2,iz, ix2,iy2,iz, ix2,iy2,iz+1.0f);

glClipPlane(GL_CLIP_PLANE3, bottom_eq.ptr);

glEnable(GL_CLIP_PLANE3);

delete bottom_eq;

So all you have to give to this planeEquation function is three points on the clipping plane. It seems that the order of them somehow dictates which side of it will be clipped and which side will be visible. In this example just changing the direction of the last Z from plus to minus, changes which side gets clipped.

I hope this is useful to someone trying to get some sense into glClipPlane and plane equations. This might all be just wrong, but it works for me! Any corrections and suggestions in the comments, please.