Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: How to draw one line on top of another in OpenGL without Z-fighting

Hybrid View

  1. #1
    Junior Member Newbie
    Join Date
    Jul 2012
    Posts
    10

    How to draw one line on top of another in OpenGL without Z-fighting

    I've asked this question on SO, but with no answer so far (and with one close request, typical SO...)

    I'm having the following problem. While glPolygonOffset works perfectly for meshes, for example when I'm trying to draw a wireframe outline on top of the object, it doesn't work for simple lines.

    Here is how it works for meshes:

    Code :
        // draw object	
        mTexture.enableAndBind();
        gl::color( Colorf( 1, 1, 1 ) );
        gl::draw( mVboMesh );
        mTexture.unbind();
     
        // overlay wireframe
        gl::enableWireframe();
        glLineWidth(1);
        glEnable( GL_POLYGON_OFFSET_LINE );
        glPolygonOffset( -1, -1 );
        glColor3f( 0, 0, 1 );
        gl::draw( mVboMesh );
        glDisable( GL_POLYGON_OFFSET_LINE );
        gl::disableWireframe();



    For some reason it doesn't work for lines. What I'm trying to achieve is to draw a coordinate frame's arrows over a grid. I'm using the very same GL_POLYGON_OFFSET_LINE mode as when I was drawing lines, just like I was doing for the wireframe over the object. However in this case glPolygonOffset( -1, -1 ); makes absolutely no difference. I've tried it with huge values like 100 and it's the same. Absolutely no effect. Here is what I'm doing:

    Code :
        // enable 3D rendering
        gl::enable( GL_CULL_FACE );
        gl::enableDepthRead();
        gl::enableDepthWrite();
     
        // drawing the grid
        int size = 2000;
        int step = 25;
        gl::color( Colorf( 0.2f, 0.2f, 0.2f ) );
        for( float i = -size; i <= size; i += step )
        {
        	glBegin( GL_LINES );
        	glVertex3f( i, 0, -size );
        	glVertex3f( i, 0, size );
        	glVertex3f( -size, 0, i );
        	glVertex3f( size, 0, i );
        	glEnd( );
        }
     
        // drawing the arrows
        glEnable( GL_POLYGON_OFFSET_LINE );
        glPolygonOffset( -1, -1 );
     
        glBegin( GL_LINES );
        gl::color( Colorf( 1, 0, 0 ) );
        glVertex3f( 0, 0, 0 );
        glVertex3f( 100, 0, 0 );
        gl::color( Colorf( 0, 1, 0 ) );
        glVertex3f( 0, 0, 0 );
        glVertex3f( 0, 100, 0 );
        gl::color( Colorf( 0, 0, 1 ) );
        glVertex3f( 0, 0, 0 );
        glVertex3f( 0, 0, 100 );
        glEnd( );
     
        glDisable( GL_POLYGON_OFFSET_LINE );
     
        // disable 3D rendering
        gl::disableDepthWrite();
        gl::disableDepthRead();
        gl::disable( GL_CULL_FACE );
    and an example of the Z-fighting I get:



    One hack I've tried and what worked perfectly is:

    1. disable depth read, enable depth write
    2. draw grid
    3. draw arrows
    4. enable depth read
    5. draw other objects

    However this is a very special case and while it works for a flat grid and arrows, it wouldn't work for pretty much anything else with a complex shape.

    My questions are:

    1. Why does glPolygonOffset not work for lines-on-lines while it works for lines-on-polygon?
    2. How can I fix it, without resorting to the above hack, what only works in very specific cases?

    // I'm using Cinder as a framework, but it shouldn't matter since I'm using raw OpenGL commands


    Update (keeping it like this for reference)

    I've checked the answer in the first comment, and tried that method as well, however that one doesn't work either, since the result depends on the distance from the camera.


    Code :
        // draw coordinate frame and grid
        glDepthRange (0.01, 1.0);
        drawGrid( 2000.0f, 25.0f );
        glDepthRange (0.0, 0.99);	
        gl::drawCoordinateFrame( 100.0f, 5.0f, 2.0f );
     
        glDepthRange (0.0, 1.0);
     
        // draw object



    SO post ends here

    Can you help me with this issue? Should I calculate a custom value for the glDepthRange trick, on-the-fly? Or should I turn at least one of the objects into a polygon? How would you solve this problem properly? For example what would you do if you had a 3D polyline and you'd like to re-draw over one segment? In that case you cannot even turn it into a polygon.

    Thanks!

  2. #2
    Member Regular Contributor
    Join Date
    Dec 2007
    Posts
    251
    For whatever reason lines produce (slightly) different depth values compared to polys, so you will see problems like this. Maybe rendering lines as polys instead of GL_LINES would work better. glPolygonoffset does work, but I've found it unreliable in the past. And made worse by different hardware that gives different results, so generally I try and avoid it.

  3. #3
    Junior Member Newbie
    Join Date
    Jul 2012
    Posts
    10
    But then what's the best way? Render them as small cylinders? Calculate depth-range shift on-the-fly, based on the camera distance / projection matrix?

  4. #4
    Senior Member OpenGL Pro
    Join Date
    Jan 2012
    Location
    Australia
    Posts
    1,117
    I have never found a one size fits all solution to this problem. For your case you could just disable depth testing since you always want them on top.

  5. #5
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    3,183
    Alternatively, if you only want lines to be occluded by polygons, render lines with only depth testing (with GL_LEQUAL depth test), never depth writing. And render them last. Then you won't have lines fighting lines.

    Yet another solution is Eric Lengyel's projection matrix offset trick, which basically lets you render something N depth steps closer to the eyepoint (scales better than PolygonOffset). A few links on that:

    * glPolygonOffset whats the deal here? is it good or bad? (gamedev.net)
    * Projection Matrix Tricks (Lengyel)
    * Mathematics for 3D Game Programming and Computer Graphics (Lengyel)
    Last edited by Dark Photon; 12-04-2012 at 07:42 PM.

  6. #6
    Member Regular Contributor malexander's Avatar
    Join Date
    Aug 2009
    Location
    Ontario
    Posts
    315
    1. Why does glPolygonOffset not work for lines-on-lines while it works for lines-on-polygon?
    Because polygon offset only works for polygons, not lines. GL_POLYGON_OFFSET_LINE only applies to polygons whose fill mode is GL_LINE; similarly, GL_POLYGON_OFFSET_POINT applies to polygons with fill mode GL_POINT. See http://www.opengl.org/sdk/docs/man3/xhtml/glPolygonMode.xml.

    So, you can't use glPolygonOffset() to offset lines or points in Z. The reason it works for lines-on-polygons is because it's the polygon that is shifted away from the camera, not the line.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •