GLSL Tesselation Shader drawing triangles in different orientations for each patch

47 Views Asked by At

I'm building a simple terrain on OpenGL using Tesselation Shaders and patches, but I'm having trouble with how OpenGL draws these patches. The triangles generated by OpenGL are being drawn in a different orientation for each patch, as shown in the pictures.

Difference between triangles of neighbour patches

Overview of different patches

I would like to know if there's a simple way to fix this problem, such as with some OpenGL built-in parameter, or it's necessary to reorient the triangles manually.

I'm using OpenGL 4.0. I'm creating a total of 8 patches, with my tessLevel set to 64.

Currently, this is how my code looks:

Tesselation Control Shader

#version 400

layout (vertices = 4) out;

uniform int tessLevel;
#define ID gl_InvocationID

void Preset();

void main()
{
    gl_out[ID].gl_Position = gl_in[ID].gl_Position;

    if (ID == 0)
    {
        Preset();
    }
}

void Preset()
{
    gl_TessLevelOuter[0] = tessLevel;
    gl_TessLevelOuter[1] = tessLevel;
    gl_TessLevelOuter[2] = tessLevel;
    gl_TessLevelOuter[3] = tessLevel;

    gl_TessLevelInner[0] = tessLevel;
    gl_TessLevelInner[1] = tessLevel;
}

Tesselation Evaluation Shader

#version 400

layout(quads, equal_spacing, cw) in;

uniform vec3 lightPos;
out vec3 tesLightDirection;

vec4 CalculateInterpolatedPosition(float u, float v);

void main()
{
    float u = gl_TessCoord.x;
    float v = gl_TessCoord.y;

    vec4 interpolatedPosition = CalculateInterpolatedPosition(u, v);
    tesLightDirection = normalize(lightPos - interpolatedPosition.xyz);

    gl_Position = interpolatedPosition;
}

vec4 CalculateInterpolatedPosition(float u, float v)
{
    vec4 p0 = gl_in[0].gl_Position;
    vec4 p1 = gl_in[1].gl_Position;
    vec4 p2 = gl_in[2].gl_Position;
    vec4 p3 = gl_in[3].gl_Position;

    return  p0 * (1 - u) * (1 - v) +
            p1 * u * (1 - v) +
            p3 * v * (1 - u) +
            p2 * u * v;
}

And my patches are being built in the following way, in my C++ program:

void Terrain::GenerateVertices()
{
    for (int i = 0; i < totalPatches + 1; i++)
    {
        for (int j = 0; j < totalPatches + 1; j++)
        {
            vertices.push_back(vec3(j, 0, i));
        }
    }

    for (int i = 0; i < totalPatches; i++)
    {
        for (int j = 0; j < totalPatches; j++)
        {
            int startingPoint = i * (totalPatches + 1) + j;

            indices.push_back(startingPoint);
            indices.push_back(startingPoint + 1);
            indices.push_back(startingPoint + totalPatches + 2);
            indices.push_back(startingPoint + totalPatches + 1);
        }
    }
}

void Terrain::Render(mat4 projection, mat4 view)
{
    shader.use();
    mat4 VPMatrix = projection * view;

    shader.setUniform("VP", VPMatrix);
    shader.setUniform("M", transform.modelMatrix());

    glBindVertexArray(vaoID);
    glPatchParameteri(GL_PATCH_VERTICES, 4);
    glDrawElements(GL_PATCHES, indices.size(), GL_UNSIGNED_INT, (GLubyte*)NULL);
    glBindVertexArray(0);
}
1

There are 1 best solutions below

0
On

You don't get to control the triangulation of the mesh. There are some basic guarantees about how triangulation works, but outside of those, it's up to the implementation. So whatever you're doing in your tessellator needs to be able to work with any (reasonable) triangulation.