'Avoid Z-fighting on 2D objects

I do display some 2D items (text + lines + arrows) in 3D scene. All items are selectable, after selection color is changed from white to blue. For some of items, I am struggling with Z-fighting. See pictures: selected item (blue) is covered by white arrow. At the second picture is white arrow hidden.

Z-fighting fully visible

How and where in code should I move item closer to camera if item.isSelected() ? I can not use GL_POLYGON_OFFSET_LINE, see glPolygonOffset() bugs with lines.

  @Override
  /**
   * Render the MyObject
   */
  public void render(GL gl, RenderParameters params, boolean selection)
  {
    //code, some checks
    
    // Load the Transformation matrix of this TreeDataItem
    Matrix4f trafo = item.getGlobalTrafo( );
    if( trafo == null )
    {
        trafo = new Matrix4f();
        Matrix4f.setIdentity(trafo);
    }
    
    // Get the PMI type if not done so yet
    int nonTextDLSize = getNonTextDL().size();
    int textDLSize = getTextDL().size();
    if(pmiType == PmiType.PT_UNKNOWN)
    {
      // Check if it is a PMI with visu available
      if(nonTextDLSize > 0 || textDLSize > 0)
        pmiType = PmiType.PT_VISUAL;
      else
      {
        Vector3f ptO = item.getTextOrigin();
        if( ptO != null )
          ptO = Matrix4f.transformPoint(trafo, ptO, null);
        Vector3f vecX = item.getTextXAxis();
        Vector3f vecY = item.getTextYAxis();
        // Check if it is a Coordinate System PMI
        pmiData = createCoordSystemPmiData(ptO, vecX, vecY);
        if(pmiData != null)
          pmiType = PmiType.PT_COORDSYSTEM;
        else
          // Nothing to be done for an unknown PMI
          return;
      }
    }
    
    // Set camera frustum
    GL2 gl2 = (GL2)gl;

    if(params == null)
      return;
    Camera camera = params.getCamera();
    if(camera == null)
      return;
    if(!camera.hasFrustum())
    {
      BBox bbox = (pmiData != null) ? pmiData.getBBox(gl2, params) : item.getBBox();
      if(bbox != null && trafo != null)
        camera.addBBoxToBounding( bbox, trafo );
      return;
    }

    //code, set preferences, e.g. color, line thickness

    // Now draw the PMI visu
    
    if (usePMIBeforeGeom) //Preference option settings if PMIs should be in front of geometry
      gl2.glDisable(GL2.GL_DEPTH_TEST);
    
    switch(pmiType)
    {
    case PT_COORDSYSTEM: // a Coordinate System PMI
      //code
      break;
    case PT_VISUAL: // a PMI with visual representation stored

      if(nonTextDLSize > 0) //those items should be fixed!!!!
      {
        FloatBuffer bf = ByteBuffer.allocateDirect( 4 * 16 ).order( ByteOrder.nativeOrder( ) ).asFloatBuffer( );
        trafo.store( bf );
        bf.rewind( );
        
        gl2.glPushMatrix( );
        gl2.glMultMatrixf( bf );
        
        if (!selection && !(item.isHighlight()) && usePMIColorFromFile)
        {
          if (pmiGeomColor != null)
            gl2.glColor4fv(pmiGeomColor);
        }

        gl2.glLineWidth( selection ? 4 : item.isHighlight() ? lineThickness * 2 : lineThickness );
        for( Integer nonTextDL : getNonTextDL( ) )
        {
          gl2.glCallList( nonTextDL );
        }
    
        gl2.glPopMatrix( );
        
        bf.clear( );
        bf = null;
      }
      if(textDLSize > 0 )
      {
        //code
      }
    }
  }


Solution 1:[1]

For drawing PMIs in front of geometry is used:

gl2.glDepthRange(k, k); instead of gl2.glDisable(GL2.GL_DEPTH_TEST).

Then I can draw selected items in closer range:

if (item.isSelected() && usePMIBeforeGeom)
  gl2.glDepthRange(SELECTION_DEPTH_RANGE, SELECTION_DEPTH_RANGE);

Finally I set range back.

gl2.glDepthRange(OpenGLRenderer.NEAR_DEPTH_RANGE, OpenGLRenderer.FAR_DEPTH_RANGE);

Code:

case PT_VISUAL: // a PMI with visual representation stored
  if(nonTextDLSize > 0)
  {
    FloatBuffer bf = ByteBuffer.allocateDirect( 4 * 16 ).order( ByteOrder.nativeOrder( ) ).asFloatBuffer( );
    trafo.store( bf );
    bf.rewind( );
    
    gl2.glPushMatrix( );
    gl2.glMultMatrixf( bf );
    
    if (!selection && !(item.isHighlight()) && usePMIColorFromFile)
    {
      if (pmiGeomColor != null)
        gl2.glColor4fv(pmiGeomColor);
    }

    //gl2.glLineWidth( selection ? 4 : lineThickness );
    
    if (item.isSelected() && usePMIBeforeGeom)
      gl2.glDepthRange(SELECTION_DEPTH_RANGE, SELECTION_DEPTH_RANGE);
    
    gl2.glLineWidth( selection ? 4 : item.isHighlight() ? lineThickness * 2 : lineThickness );
    for( Integer nonTextDL : getNonTextDL( ) )
    {
      gl2.glCallList( nonTextDL );
    }
    if (item.isSelected())
      gl2.glDepthRange(OpenGLRenderer.NEAR_DEPTH_RANGE, OpenGLRenderer.FAR_DEPTH_RANGE);

    gl2.glPopMatrix( );
    
    bf.clear( );
    bf = null;
  }
  if(textDLSize > 0 )
  {
    //code
  }

Constants:

private static final double SELECTION_DEPTH_RANGE = 0.000003;
public static final double NEAR_DEPTH_RANGE = 0.000004;
public static final double FAR_DEPTH_RANGE = 1.0;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1