PDA

View Full Version : Clipping Planes in JOGL



Mar Ee
06-24-2015, 08:37 PM
Hello, I am quite new to JOGL (and OpenGL in general).
I am building an application for an assignment. I'm attempting to make a 'TARDIS', from the Doctor Who series (basically a box that's bigger on the inside than on the outside).
For it to look nice, I need to use two clipping planes to render the interior of the TARDIS from the exterior. I got the plane equations for that (x + z = 0 and x - z = 0, where x and z are the camera's position) but I cannot find the glClipPlane function. NetBeans doesn't even find the function in the GL3 object.
Do I have to enable something in the vertex/fragment .glsl files? Do I have an old version of JOGL? Thanks in advance.

GClements
06-24-2015, 09:47 PM
glClipPlane() and glEnable(GL_CLIP_PLANEi) are deprecated in OpenGL 3+, so they aren't available in a core profile context.

The new approach is to use glEnable(GL_CLIP_DISTANCEi) and have the vertex shader write to gl_ClipDistance[i] (https://www.opengl.org/sdk/docs/man4/html/gl_ClipDistance.xhtml).

Mar Ee
06-24-2015, 11:16 PM
Thanks! Could you provide me with an example? Where do I add these functions, and where do I define the planes?

Alfonse Reinheart
06-24-2015, 11:27 PM
A better way to do this is with the stencil buffer. You basically render the entrance to the TARDIS, but you use write masking (https://www.opengl.org/wiki/Write_Mask) so that you only update the stencil buffer (you should still use the depth test). When you render the interior, you render it using the stencil test (https://www.opengl.org/wiki/Stencil_Test), such that only those fragments being written to pixels that have the stencil value laid down by the TARDIS entrance pass.

That way, all pixels that aren't explicitly behind the TARDIS door will be culled by the stencil test.

Mar Ee
06-24-2015, 11:49 PM
Right, so let me see if I understood it:

First, I'll need a rectangle to define my door, which in my case is (2,0,-2),(2,4,-2),(-2,0,-2) and (-2,4,-2).
Then, instead of drawing it, I'll use it to draw on the stencil buffer:

glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
rectangle.draw();

After that, I need to enable the stencil test and draw the interior:

glEnable(GL_STENCIL_TEST);
interior.draw();
glDisable(GL_STENCIL_TEST);

Am I missing something?

Alfonse Reinheart
06-25-2015, 12:36 AM
Am I missing something?

Lots of things.

First: you must make sure that you actually have a stencil buffer. So you must use whatever tool you use to create an OpenGL context and get it to make one with a stencil buffer.

Second: you must clear the stencil buffer to some known value (set via glClearStencil) every frame, right along with the depth and color buffers. It could be any value you choose, but 0 is a good choice, so let's go with that.

Third: when rendering the door, you must turn off depth writes too. But you still want depth testing.

Fourth: when rendering the door, you must tell the system what stencil value you want to apply. So long as that value is not zero (the one we choose for the clear stencil), we're fine. So let's choose 0x1.

In order to write a stencil value, you need to do three things. You must enable the stencil test.

You must then set the reference stencil value for all fragments generated during rendering with glStencilFunc[Separate]. So it would look something like:



glStencilFunc(GL_ALWAYS, 0x1, 0xFFFFFFFF);


The first parameter sets the stencil test to always pass (so no self-stenciling). The second parameter sets the stencil value to 0x1. The third is a masking value.

You must also tell the system to write the incoming stencil value, but only where appropriate. This requires glStencilOp[Separate]:



glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);


The first parameter is what should happen if stenciling fails (keep the old value from the stencil buffer). The second is if the stencil test passes and the depth test fails (again, keep the old value). The third says what should happen if the stencil and depth tests pass (replace the framebuffer stencil value with 0x1).

Fifth: Remember to turn off everything that was just turned on after rendering the door, except the stencil test if the very next thing is the interior space.

Sixth: When drawing the interior, you need to have set appropriate stencil-func and stencil-op parameters. The stencil test should fail if the stencil value in the framebuffer is not equal to 0x1. Thus, the fragment will be discarded for anything rendered outside of the doorway. But you never want to update the framebuffer's stencil value; you want that kept the same.



glStencilFunc(GL_EQUAL, 0x1, 0xFFFFFFFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

GClements
06-25-2015, 09:32 AM
A better way to do this is with the stencil buffer.
A stencil test has the advantage of not needing to compute clip planes. Also, it isn't limited to a convex polygon.

However, clip planes can discard entire primitives prior to rasterisation, whereas a stencil test operates at the fragment level, so there may be performance advantages to using clip planes.

* You'd have to measure performance to get a definitive answer.