Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

gpu

opengl

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:

// 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();

mesh

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:

// 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:

lines

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

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.

//// 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  

mix

like image 880
hyperknot Avatar asked Dec 04 '12 17:12

hyperknot


1 Answers

I guess one hack could be to draw the line just a bit closer to the view point (let's say 0.1 closer). This should avoid z-fighting.

In order to do so, you calculate the normalized directional vector from your point to the POV position. Then you scale it with a small factor, and add it to your line point coordinates

like image 195
Zerto Avatar answered Oct 11 '22 05:10

Zerto