Search code examples
c#openglopentksketchup

OpenTK Primitive type switching in immediate mode


I can't post images because I don't have enough reputation, so only links are provided.

I'm using OpenTK to render a 3D model (importing it works fine). The model was made in sketchup and the edge lines are also exported. When I try to render it, the lines are drawn over all of the polygons, even if they should be behind and therefore invisible. I have deduced that this is probably due to calling GL.End() and then switching to line mode and (probably) rendering over the existing image.

Is there a way to have both lines and triangles rendered simultaneously (with correct depth and overlap)? If not, how should I draw the lines? Can I draw them as triangles?

In my renderer: https://i.sstatic.net/oC9Ux.png

In sketchup(how I'm trying to make it look): https://i.sstatic.net/Jmu1S.png

My rendering code (world is the imported collada data, geometryLines are the lines being rendered and the triangles are the triangulated faces).

        GL.Begin(PrimitiveType.Triangles);
        GL.Color3(Color.Red);
        GL.Enable(EnableCap.LineSmooth);
        GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
        foreach (Triangle tri in world.triangles)
        {
            GL.Vertex3(tri.vertices[0]);
            GL.Vertex3(tri.vertices[1]);
            GL.Vertex3(tri.vertices[2]);
        }

        GL.End();
        GL.Begin(PrimitiveType.Lines);
        GL.Color3(Color.Blue);
        GL.Enable(EnableCap.LineSmooth);
        GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
        foreach (GeometryLine line in world.geometryLines)
        {
            GL.Vertex3(line.vertices[0]);
            GL.Vertex3(line.vertices[1]);
        }

        GL.End();


        SwapBuffers();

Solution

  • (responding to your update)

    The issue you're seeing with lines not fully appearing over the geometry you've rendered is a typical case of Z-fighting. The depth buffer records the depth of the closest geometry that was rendered at each pixel. When new geometry (your lines) is rendered above existing geometry (your triangles), the new pixels are only kept if their depth is less than what was recorded in the depth buffer. However, when you render two objects at more or less exactly the same depth (such as your lines and the edges of your triangles), which geometry is closer or farther at a given pixel becomes somewhat arbitrary due to floating-point errors.

    The usual way to work around this issue is to use a hack called depth biasing. You start by drawing your triangle-based geometry, then you draw your lines while instructing OpenGL to offset their depth a tiny bit towards the viewer. This is achieved using the glPolygonOffset function. The result is that the lines pass the depth test and are drawn above the triangles.

    This is the technique used for decals such as bullet holes on walls. Note that you may want to disable depth writing when drawing decals since you usually consider that they are at the same depth as the wall itself, and want to avoid Z-fighting between multiple decals.