Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Passing colours through tessellation shaders

I am learning tessellation now. Trying to pass the colour via tesselation shaders. Like I found here, the most consistent answer:
Passing data through tessellation shaders to the fragment shader
So far consulting also these sources, but did not find the problem in my code yet:
https://www.khronos.org/opengl/wiki/Tessellation_Control_Shader
https://www.khronos.org/opengl/wiki/Tessellation_Evaluation_Shader
As failing to pass for complex shapes, I narrowed problem down to simple basic triangle. Here is the problem. Only the last, third color is taken from the triangle data passed to shaders, see the TessTriangleRainbow::points in the C++ code snippet for tessellated triangle. No matter that I do, the first ad second color is ignored:
enter image description here
Note, exactly the same code and data but not tessellated looks ok:
enter image description here
Vertex shader for tessellated triangle:

#version 430 core
layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 color;
out vec4 vs_color;

void main()
{
    gl_Position = vec4(pos,   1.f);
    vs_color    = vec4(color, 1.f);
}

Tessellation control shader:

#version 430 core
layout (vertices = 3) out;
      in  vec4 vs_color [];
patch out vec4 patch_color;

void main()
{
    gl_TessLevelOuter[0] = 10.0;
    gl_TessLevelOuter[1] = 10.0;
    gl_TessLevelOuter[2] = 10.0;
    gl_TessLevelInner[0] = 5.0;
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
    
    patch_color = vs_color [gl_InvocationID];
}

Tesselation evaluation shader:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#version 430 core

layout (triangles, equal_spacing, cw) in;
patch in  vec4 patch_color;
      out vec4 tes_color;
void main(void)
{
    gl_Position= (
        gl_TessCoord.x * gl_in[0].gl_Position +
        gl_TessCoord.y * gl_in[1].gl_Position +
        gl_TessCoord.z * gl_in[2].gl_Position );

    tes_color = patch_color;
}

Fragment shader for tessellated triangle:

#version 430 core
out vec4 color;
in vec4 tes_color;
void main()
{
    color = tes_color;
}

Tessellated triangle source:

GLfloat TessTriangleRainbow::points[] =
{
    //x      y       z       r    g    b
  -0.5f, -0.5f,   0.0f,   0.0f, 0.f, 1.f,   // first   xyz vertex + rgb color
   0.5f, -0.5f,   0.0f,   1.0f, 0.f, 0.f,   // second  xyz vertex + rgb color
   0.0f,  0.5f,   0.0f,   0.0f, 1.f, 0.f    // third   xyz vertex + rgb color
};
//The base class Tess is tesselation shader aware
//It is responsible for compiling linking the shaders
TessTriangleRainbow::TessTriangleRainbow()
    : Tess ("shaders/tesselation/triangleRainbow.tcs", "shaders/tesselation/triangleRainbow.tes",
            "shaders/tesselation/triangleRainbow.vs",  "shaders/tesselation/triangleRainbow.fs")
{
    build();
}

void TessTriangleRainbow::build()
{
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    unsigned int vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(points), &points, GL_STATIC_DRAW);

    //get XYZ values into location 0 on vertex shader
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    //RGBA to location 1
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);


    glBindVertexArray(0);
}
void TessTriangleRainbow::draw()
{
    glUseProgram(*this); //the inherited overloaded (int) operator returns the program id
    glPatchParameteri(GL_PATCH_VERTICES, 3);

    glBindVertexArray(vao);
    glDrawArrays(GL_PATCHES, 0, 3);
}

Vertex shader for non tessellated triangle:

#version 430 core
layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 color;
out vec4 vs_color;
void main()
{
    gl_Position = vec4(pos,   1.f);
    vs_color    = vec4(color, 1.f);
}

Fragment shader for non tessellated triangle:

#version 430 core
out vec4 color;
in vec4 vs_color;
void main()
{
    color = vs_color;
}

Non tessellated triangle source, is almost identical to the tessellated one:

GLfloat TriangleRainbow::points[] = identically the same as tessellated ones
//base Shape class builds the program from shaders
TriangleRainbow::TriangleRainbow()
    : Shape ( "shaders/tesselation/triangleRainbow.1.vs",  "shaders/tesselation/triangleRainbow.1.fs")
{
    build();
}

void TriangleRainbow::build()
{
    ... it is identically the same as the tessellated one
}
void TriangleRainbow::draw()
{
    glUseProgram(*this); //the inherited overloaded (int) operator returns the program id
    glBindVertexArray(vao);
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

Piece of main function:

    TessTriangleRainbow   tessTriRainbow;
    TriangleRainbow       triRainbow;
    ... other shapes

    if (!tessTriRainbow.program.success) /*report tessellated triangle shader compile errors*/ ...
    if (!triRainbow.program.success) /*report triangle shader compile errors*/ ...
    ...

    glDisable(GL_CULL_FACE);
    //glEnable(GL_DEPTH_TEST);

    int currentShape = 0;
    while (!glfwWindowShouldClose(window))
    {
        processInputs(window);
        if (keyPressed) { /* change here currentShape to draw*/ ... }

        glClearColor(0.f, 0.f, 1.f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        switch (currentShape)
        {
        case 0: triRainbow.draw();     break;
        case 1: tessTriRainbow.draw(); break;
        ...

Update:
The response from @Rabbid76 works exactly as provided. When I apply the glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) there can be seen clearly the difference:
Non tessellated:
enter image description here
Tessellated:
enter image description here

>Solution :

You are using Per-patch output. So all the color attributes in the primitive become the same (from the last vertex in the patch):

patch out vec4 patch_color;

void main()
{
  // [...] 
  
   patch_color = vs_color [gl_InvocationID];
}

If you want a color per vertex, you have to use Per-vertex outputs. The output variable has to be an array.

Tessellation control shader:

out vec4 vertex_color[];

void main
{
    // [...]

    vertex_color[gl_InvocationID] = vs_color[gl_InvocationID];
}

Tesselation evaluation shader:

#version 430 core

layout (triangles, equal_spacing, cw) in;
in  vec4 vertex_color[];
out vec4 tes_color;

void main(void)
{
    gl_Position =
        gl_TessCoord.x * gl_in[0].gl_Position +
        gl_TessCoord.y * gl_in[1].gl_Position +
        gl_TessCoord.z * gl_in[2].gl_Position;

    tes_color = 
        gl_TessCoord.x * vertex_color[0] +
        gl_TessCoord.y * vertex_color[1] +
        gl_TessCoord.z * vertex_color[2];
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading