Using glClipPlanes and plane equations

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.

Advertisements
Explore posts in the same categories: d, OpenGL, problems

Tags: , , ,

You can comment below, or link to this permanent URL from your own site.

7 Comments on “Using glClipPlanes and plane equations”

  1. Jarrett Says:

    Please don’t allocate a new array on every call and then delete it. You’ll make the GC very sad šŸ˜¦

    Instead, have the function take a double[4] to store the results, and pass one in.

    void planeEquation( double[4] result, float x1, float y1…);

    double[4] eq = void;
    planeEquation(eq, ix1, iy1…);
    glClipPlane(GL_CLIP_PLANE3, eq.ptr);

    • pihlaja Says:

      Yes. You are absolutely right. I usually try to avoid using “new” in anything that might be called multiple times, but too often I just forget about it. Thanks for the reminder.


  2. Try these:

    http://flipcode.com/archives/3D_Geometry_Primer_Chapter_1-Introduction.shtml

    http://flipcode.com/archives/3D_Geometry_Primer_Chapter_2-Issue_01_Appendix.shtml

    It’s really simple once you grok vector ops including the dot and cross products. E.g. your “It seems that the order of them somehow dictates which side of it will be clipped and which side will be visible” actually stems from properties of the cross product.

    In a brief, given a vector [A, B, C] in R^3, all points which yield the same value of the dot product with this point lie on the same plane. So all points (x, y, z) for which Ax+By*Cz = some constant lie on a plane perpendicular to this vector. The plane equation is Ax+By+Cz+D=0, therefore you to find the plane equation on which some point (x, y, z) resides, you substitute D=-(Ax+By+Cz).

    All points for which Ax+By+Cz+D > 0 are on the positive half-space of the plane. All of them for which Ax+By+Cz+D < 0 are in the negative half-space (these are the points you want clipped out).

    Now, to get a plane equation defined by any 3 points (let's call them p0, p1, p2) in R^3, you first find the [A, B, C] vector (called a normal) as the cross product of (p1-p0) and (p2-p0). The order in which you specify p0, p1 and p2 defines in which direction the normal points. In a right-handed coordinate system which OpenGL uses by default, you can visualize it to yourself such that the "front side" (the side from which the normal points towards the viewer) of a triangle is the one from which you see the vertices in counter-clockwise order (that's pretty ad-hoc but should suffice for the purpose of this explanation).

    Finally, when you have the normal vector (and hence A, B and C of the plane equation), you calculate D as mentioned earlier, substituting any point into the equation, hence e.g. D = -(p0.x * A + p0.y * B + p0.z * C).

    BTW, it's rather unfortunate that you're switching from hand-clipping primitives to clipping planes in GL – this means that you need to submit each differently clipped primitive as a separate batch, thus hurting performance. I'm planning to do the exact opposite of what you're doing. For clipping arbitrary polygons, just go with http://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm

    Oh yea, and *what Jarrett said*. Except the result/output param is by convention the last one, not the first šŸ˜›

    • pihlaja Says:

      Thanks for the maths. I should really get the time to understand trigonometry better. I used to write 3D engines without truly understanding “anything” about them. And it usually went wrong at some point!

      I know my performance is bad anyway… I already was submitting each primitive separately, as my rendering system isn’t very clever or good. But the software clipping was just getting too heavy on my brain! I’m also doing glTranslate before every widget. I’ve been thinking that maybe I should have all my rectangles in one OpenGL space, and then somehow composite them in the right order, and propably optimize it so that rectangles with the same textures would be drawn in one batch, if possible. But I really have no idea how to write such a system. It’s easier for me to just go through my tree of rectangles and draw them all. If you have better ideas and clear explanations on how to do it better, I’d be glad to hear about it, but as I’m not an expert coder, I might just leave it in a state where I can understand it. Unless someone else is willing to code it for me/with me!

      On my laptop I’m mostly getting over 50 frames per second with a couple of widgets, but it will get below 30 with a lot of text. So, it could definitely be faster.

      It would be nice seeing what you are doing lately. I might try to release a small commercial application in “a couple of months”, if I’m lucky. But I’m not making any promises here, as it’s usually so that I can’t fulfill them!


      • I’m not quite sure what you mean by compositing the geometry in ‘the right order’. In my GUI toolkit, that’s quite simple and obtained directly from the compositional widget structure — you just iterate the widgets and get the order directly. Container widgets decide in which order their children should be drawn. The reverse order of this is useful e.g. for processing clicks, so if you can do one, you can do the other.

        30-50 frames is not too fast, I’m afraid. You’re likely to be heavily CPU-bound with such a batch-heavy approach. You should be aiming for drawing everything in a single batch, really. Not always possible, especially with viewports which do external rendering, but if you pack icons and text together into a single large texture, you should get down to a few batches. And if you have complex geometry to clip, you could try storing the plane equations in textures and rolling shaders which extract the proper sets of planes for each widget from them — that gives you clipping on the GPU while not having to do Sutherland-Hodgman.

        As for me — I’m about to graduate, working on my insane renderer ATM: http://h3.gd/code/nucleus/

        Good luck with your commercial app!

      • pihlaja Says:

        Just read this post:
        http://labs.qt.nokia.com/2010/05/18/a-qt-scenegraph/

        It’s mostly about this same issue… optimizing OpenGL in user interfaces. It seems that in the Qt camp, they’re trying to do it with a scene-graph. I’ve only briefly skimmed through the Hybrid code, but it seems you’ve got something similar, but maybe not? Maybe it wasn’t a tree, just lists of rectangles or something. But anyway, the article above discusses what I meant with the “compositing the geometry in the right order”. I mean just that, that if I’d make a tree out of it, and then optimize the drawing order based on textures and OpenGL state changes needed.
        I’m just puzzled if it really would speed up my drawing, as then I would have to do a lot of maintenance in CPU (like matrix calculations etc.) And in the case of a tree, I’d be creating a tree, and then traversing it every frame, instead of the current situation where I only traverse through the natural parent-child tree of my widgets. So, maybe a tree would be overkill, and just a list of rectangles and foreaching through that might be enough.
        Oh, well. If I’ll get the time, I’ll try to go with the scene-graph tree thing…

  3. James Bray Says:

    “Iā€™m a pragmatic self-taught trial-by-error coder, with very poor mathematical knowledge”

    Amen! I thought I was the only one šŸ™‚


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: