Weirdness with glClipPlane

Sage
Posts: 1,199
Joined: 2004.10
Post: #1
I've used glClipPlane before and it always did what it's supposed to do. It made a clipping plane in the modelview space which was static relative to the scene.

But, for some baffling reason I'm seeing a dynamic clip plane which slides around relative to the camera position! It's driving me batty, and I'm hoping some kind soul here can give some suggestions to help me out.

First, a video of what I'm talking about. I'm doing simple reflections, and in the video you'll see a scene of a bunch of textured boxes reflected in a textured plane. I'm rendering world flipped across the plane and using a glClipPlane to clip the scene by that reflection plane.

http://shamyl.zakariya.net/etc/ClippingPlaneWoes.mov

The relevant code is below. It's a little ugly right now since I'm experimenting. That being said, the reflected rendering and reflected frustum culling work great. The issue at hand is that the clipping plane slides around as the camera moves and looks around. I have no idea why this would happen!

Code:
void World::renderReflectionsForCamera( const CameraRef &camera, bool shadows )
{
    _renderingReflection = true;
    
    for ( EntityCameraReflectionMap::const_iterator it( _reflectionCameras.begin() ), end( _reflectionCameras.end() );
          it != end; ++it )
    {
        _renderingReflectionForEntity = it->first;
        for ( std::map< CameraRef, ReflectionRTTCameraRef >::const_iterator cIt( it->second.begin() ), cEnd( it->second.end() );
              cIt != cEnd; ++cIt )
        {
            CameraRef camera = cIt->first;
            
            //
            // Don't bother rendering the reflection if this camera can't see the reflecting entity
            //

            if ( camera->frustum().intersects( it->first->aabb() ))
            {
                glError();

                _activeReflectionCamera = cIt->second;
                _activeReflectionCamera->begin();

                displayForCamera( camera, shadows );

                _activeReflectionCamera->end();
                
                glError();
            }
        }
    }
    
    _renderingReflectionForEntity.reset();
    _activeReflectionCamera.reset();
    _renderingReflection = false;
    
}

void World::displayForCamera( const CameraRef &camera, bool shadows )
{
    LightRef noLight;
    glError();
    
    
    Frustum frustum = camera->frustum();
    
    if ( _renderingReflection )
    {
        _activeReflectionCamera->setFarPlane( _farPlane );
        _activeReflectionCamera->set();
        
        plane reflectionPlane = _activeReflectionCamera->reflectionPlane();
        mat4 householderTransform = _activeReflectionCamera->householderTransform();
        vec3 refPoint = vec3( reflectionPlane.a, reflectionPlane.b, reflectionPlane.c ) * reflectionPlane.d;

        glError();

        GLdouble clipPlane[4] = { reflectionPlane.a,reflectionPlane.b,reflectionPlane.c,reflectionPlane.d };
        glEnable( GL_CLIP_PLANE0 );
        glClipPlane( GL_CLIP_PLANE0, clipPlane );  

        glPushMatrix();

        glTranslatef( refPoint.x, refPoint.y, refPoint.z );
        glMultMatrixf( householderTransform );
        glTranslatef( -refPoint.x, -refPoint.y, -refPoint.z );
        
        frustum = _activeReflectionCamera->reflectedFrustum();
    }
    else
    {
        camera->setFarPlane( _farPlane );
        camera->set();
    }
    
    //
    // Prepare visibility set, then run visibility determination
    // against each graph to populate it. Then, finish it so we can render.
    //
    
    _visibilitySet->begin();
    for ( GraphRefMap::iterator it( _graphs.begin() ), end( _graphs.end() );
          it != end; ++it )
    {
        it->second->determineVisibility( _visibilitySet, frustum );
    }
    _visibilitySet->done();

    glError();

    glEnable( GL_DEPTH_TEST );
    glDepthFunc( GL_LEQUAL );
    glEnable( GL_CULL_FACE );
    glCullFace( GL_BACK );
    glFrontFace( GL_CCW );
    glDisable( GL_BLEND );
    
    glError();

    // render opaque lighting
    displayLighting( true, shadows );  

    // render transparent lighting, grabbing depth & color tex if necessary
    if ( _visibilitySet->transparentRenderPassNeeded() )
    {      
        if ( _visibilitySet->transparentRenderPassNeedsDepthTexture() )
        {
            grabDepthTexture();
        }

        if ( _visibilitySet->transparentRenderPassNeedsColorTexture() )
        {
            grabColorTexture();
        }
        
        displayLighting( false, shadows );
    }
        
    glError();

    displayPass( RenderPass::FinalPass, noLight, false );  
    
    if ( _debugGraphs )
    {
        glDisable( GL_FOG );
        glDisable( GL_LIGHTING );
        glEnable( GL_COLOR_MATERIAL );
        glEnable( GL_BLEND );
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
        
        for ( GraphRefMap::iterator it( _graphs.begin() ), end( _graphs.end() );
              it != end; ++it )
        {
            it->second->debugRender();
        }
    }
    
    glDisable( GL_ALPHA_TEST );
    
    if ( _renderingReflection )
    {
        glDisable( GL_CLIP_PLANE0 );
        glPopMatrix();
    }
}
Quote this message in a reply
Member
Posts: 45
Joined: 2006.07
Post: #2
This has happened to me before. I haven't looked at your code in detail but I'm looking at p. 140 of the red book, 3rd ed. which says (italics are mine):
Quote:All points with eye coordinates (xe, ye, ze, we) that satisfy (A B C D) M^-1 (xe ye ze we)^T >= 0 lie in the half-space defined by the plane, where M is the current modelview matrix at the time glClipPlane() is called.
The last time I had this problem, it was because I defined a clip plane before I had placed my camera where I wanted it (essentially putting the clip plane and the camera in different coordinate systems).
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #3
Interesting. I didn't realize glClipPlane was relative to a particular modelview. I just assumed it was magic, I guess. I'm going to have to do some more experimentation.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #4
SOLVED!

What I didn't know is that if you're using vertex shaders, you have to calculate the clip vertex. Probably something I read in the orange book and then forgot immediately.

So, if you have this problem, it's a one-liner. Add this to your vertex shader:
Code:
gl_ClipVertex = gl_ModelViewMatrix*gl_Vertex;

Obviously, the above is valid only if what you want is clipping planes defined in modelview space.
Quote this message in a reply
Member
Posts: 45
Joined: 2006.07
Post: #5
Glad I didn't have the misfortune to mess with clip planes and vertex shaders at the same time!

Also I guess I should pick up an orange book -- seems like there's some non-intuitive things happening in there...
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #6
UH-OH!

It seems that writing to gl_ClipVertex forces software vertex execution ( on the x1600 at least ). What a shame. I pretty much have to give up on rendering reflections if it's going to cause horrible slowdowns.
Quote this message in a reply
Member
Posts: 72
Joined: 2006.10
Post: #7
You could always implement the clip plane yourself by discarding pixels on the wrong side of the plane in your fragment shader.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #8
I've considered that, but the trouble is I'm rendering the entire "world" reflected across the plane, which means all my shaders would have to have the discard code, which wouldn't be used 99.99% of the time.

Seems like a waste.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #9
If you only need one clip plane you can do that weird changing-the-shape-of-the-view-frustum trick. That seems to be the "done thing" these days.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #10
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #11
Now, now that's interesting. OSC, to the rescue.

Thanks, chief.
Quote this message in a reply
Member
Posts: 45
Joined: 2006.07
Post: #12
neat idea.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #13
It works! Thanks for the link!
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Alpha blending weirdness on GMA 950 akb825 15 9,130 Sep 1, 2009 06:22 PM
Last Post: arekkusu
  OpenGL weirdness DoG 9 4,128 Oct 31, 2006 04:49 AM
Last Post: DoG