Search code examples
c++openglglsltessellation

Drawing tessallated LineLoops in OpenGL/GLSL


I am rendering some LineLoops on a sphere (borders on a planet) and want to tessallate them into shorter lines to prevent long lines clipping into the sphere. Example: enter image description here

Here is my current source code: C++ draw call:

void Border::Draw() const
{
    glBindVertexArray(_vao);

    glPatchParameteri(GL_PATCH_VERTICES, 2);
    glDrawArrays(GL_PATCHES, 0, _size);

    glBindVertexArray(0);
}

Vertex Shader:

#version 400

in layout(location = 0) vec3 position;

void main()
{
    gl_Position = vec4(position, 1.0);
}

Tessallation Control Shader:

#version 400

layout (vertices = 2) out;

void main()
{
    if(gl_InvocationID == 0)
    {
        //get the distance between two points
        float dist = length(gl_in[0].gl_Position - gl_in[1].gl_Position);
        gl_TessLevelOuter[0] = 1;
        //divide line in segments of size 1.0
        gl_TessLevelOuter[1] = abs(dist);
    }

    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}

Tessallation Evaluation Shader

#version 400

layout (isolines, equal_spacing) in;

uniform float planetRadius;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    vec4 p = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);

    //offset point so it is on the spheres surface
    p = normalize(p);
    p *= planetRadius;

    gl_Position = projection * view * p;
}

Fragment Shader:

#version 400

out vec4 outColor;

void main()
{
    outColor = vec4(1.0, 1.0, 1.0, 1.0);
}

The tessallation doesn't seem to work like I expect it to work (documentation on isolines is also bad).

This is how it looked when I draw it with LineLoops and only Vertex/Fragment Shader:

enter image description here

and this is how it looks like after I implemented my tessallation:

enter image description here

The lines also do not look tessallated and have the same length as before.

Greetings Jhonny

Edit: Found the solution myself. Look in answer section below to see it.


Solution

  • I found the solution. The problem lies within the tessallation shaders inability to draw line strips. So if you hava a line strip defined by the points {p1, p2, p3, p4, p5, p6} it draws lines between:
    p1 -> p2
    p3 -> p4
    p5 -> p6

    I fixed it by giving the shader every point 2 times, so my list looks like this:
    {p1, p2, p2, p3, p3, p4, p4, p5, p5, p6, p6, p1}
    The tessallation shader creates following lines:
    p1 -> p2
    p2 -> p3
    p3 -> p4
    p4 -> p5
    p5 -> p6
    p6 -> p1

    My shaders now look like this:

    TessControl:

    #version 430
    
    layout (vertices = 2) out;
    
    void main()
    {
        if(gl_InvocationID == 0)
        {
            float dist = length(gl_in[0].gl_Position.xyz - gl_in[1].gl_Position.xyz);
    
            gl_TessLevelOuter[0] = 1;
            gl_TessLevelOuter[1] = dist;
        }
    
        gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
    }
    

    TessEval:

    #version 430
    
    layout (isolines, equal_spacing) in;
    
    uniform float planetRadius;
    uniform mat4 view;
    uniform mat4 projection;
    
    void main()
    {
        //only interpolate and normalize xyz coordinates. Thanks to @aslg
        vec3 p = mix(gl_in[0].gl_Position.xyz, gl_in[1].gl_Position.xyz, gl_TessCoord.x);
    
        p = normalize(p);
        p *= planetRadius;
    
        gl_Position = projection * view * vec4(p, 1.0);
    }