djk's picture

Cutting Planes

I have implemented cutting planes in my app today and the behavior in OpenTk seems odd.

The object I have drawn is a rudder with the center of pressure at x=0 the leading edge at -1.125 and the trailing edge at 3.375.

If I define the cutting plane as:

            double[] planeEq = {1, 0, 0, 2};
            GL.ClipPlane(ClipPlaneName.ClipPlane0, planeEq);
            GL.Enable(EnableCap.ClipPlane0);

I would have expected the trailing edge portion to be drawn truncated off at x=2. Nothing is drawn on the screen.

If I change it to:

            double[] planeEq = {1, 0, 0, -2};
            GL.ClipPlane(ClipPlaneName.ClipPlane0, planeEq);
            GL.Enable(EnableCap.ClipPlane0);

The rudder is truncated at x=2 and the trailing edge portion is drawn.

And Finally,

            double[] planeEq = {-1, 0, 0, -2};
            GL.ClipPlane(ClipPlaneName.ClipPlane0, planeEq);
            GL.Enable(EnableCap.ClipPlane0);

The rudder is truncated at x=2 and the Leading edge portion is left.

I believe that the clip plane is working with respect to the plane normal (as in the side of the model to keep is what I expect), but the plane constant seems to be changing signs.

Can anyone confirm if this is correct behavior for OpenGL or an issue in OpenTk?

djk

AttachmentSize
ClippingPlane.png99.5 KB

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

OpenTK does not process the data of OpenGL calls in any way, i.e. it passes the equation of GL.ClipPlane to the underlying OpenGL function directly (you can verify with GL.GetClipPlane). It also doesn't touch the modelview matrix, so by the process of elimination this behaviour is (probably) defined by OpenGL.

From http://opengl.org/sdk/docs/man/xhtml/glClipPlane.xml:

glClipPlane specifies a half-space using a four-component plane equation. When glClipPlane is called, equation is transformed by the inverse of the modelview matrix and stored in the resulting eye coordinates. [...] If the dot product of the eye coordinates of a vertex with the stored plane equation components is positive or zero, the vertex is in with respect to that clipping plane. Otherwise, it is out.

The only thing I can think of right now, is to check your modelview matrix.

Maybe someone more experienced with this region of OpenGL programming can be of more help?

djk's picture

I am in the office reading my RedBook, and in addition to what you sited above the plane equation is what I expected ie. ax+by+cz+d=0. I believe the modelview is in the correct state, but I will double check that in a few moments.

djk's picture

I have attached an image that shows what is happening. After more testing this morning, I have found that clipping at X=0 seems to work correctly with out regard to the view orientation. However when I clip at x=2 I get results that are view dependant and seemingly non-sensical.

In all cases, once the clipping plane is defined and enabled it is transformed with the model as the view is changed which is the effect I am after.

At this time it does not seem like OpenTk is the issue, however if anyone has a robust method for inserting cutting planes without reguard to the view orientation I am all ears.

djk

Inertia's picture

I've not used clipping planes so far, but the way I understand it they do not disable the frustum clipping (which could be the issue here, that the model is clipped by a different plane than the manual clip plane you are defining). Since you didn't cite any code about your modelview/projection setup this is hard to tell.

Maybe this article ( translated german->english with http://babelfish.altavista.com/ ) can help:

http://wiki.delphigl.com/index.php/glClipPlane

djk's picture

I came up with a brute force work around. It seems like the ClipPlane works fine when the plane constant is zero. If I transform the clipping plane and tell the ClipPlane function to use a 0 plane constant I get the results I need.

private void ClippingPlane()
{
    if (_cuttingPlaneEnabled)
    {
        GL.PushMatrix();
 
        // for some reason the plane constant is not working when it is non-zero
        // to work around this limitation I am translating the clipping plane.
        // ToDo: use tolerance vice absolute test
            if (Math.Abs(_planeEq[0]) == 1)
                GL.Translate(_clipPlaneConstant, 0, 0);
            else if (Math.Abs(_planeEq[1]) == 1)
                GL.Translate(0, _clipPlaneConstant, 0);
            else if (Math.Abs(_planeEq[2]) == 1)
                GL.Translate(0, 0, _clipPlaneConstant);
            else
            {
                // deal with arbitrary plane need to rotate to the normal direction then translate.
            }
 
            GL.ClipPlane(ClipPlaneName.ClipPlane0, _planeEq);
 
        GL.PopMatrix();
 
        GL.Enable(EnableCap.ClipPlane0);
    }
    else
    {
        GL.Disable(EnableCap.ClipPlane0);
    }
}
 
/// <summary>
/// Set the plane equation ax+by+cz+d=0 for the clipping plane
/// </summary>
/// <param name="planeEq">Array of four doubles representing a,b,c,d in the plane equation.</param>
public void SetClippingPlane(double[] planeEq)
{
   _planeEq = planeEq;
 
   // for some reason the plane constant is not working when it is non-zero
   // to work around this limitation I am translating the clipping plane. So
   // place the plane constant located in _planeEq[3] in the _clipPlaneConstant for
   // later use in the clipping routine and then set the _planeEq[3] to zero.
 
   _clipPlaneConstant = _planeEq[3];
   _planeEq[3] = 0.0;
}
 
/// <summary>
/// Enable or Disable the cutting plane in the view.
/// </summary>
/// <param name="enable">True enables the cutting plane, False disables the cutting plane.</param>
public void EnableCuttingPlane(bool enable)
{
    _cuttingPlaneEnabled = enable;
}