MinorMapillai
MinorMapillai

Reputation: 199

glPolygonMode not rendering in correct mode

I recently started learning tessellation and today I was trying to draw a triangle after tessellation so that I can see all the tessellated smaller triangles using glPolygonMode(GL_FRONT_AND_BACK, GL_LINE). But for some reason the output is just a coloured background without any triangle in it. For the tessellation, I make a control shader and evaluation shader and then link them to the program.(Code below)

// Source code for Tesselation Control Shader
static const GLchar * tesselation_control_shader[] = 
{
    "#version 450 core                                  \n"
    "                                                   \n"
    "layout(vertices = 3) out;                          \n"
    "                                                   \n"
    "void main(void)                                    \n"
    "{                                                  \n"
    "   //Only if I am invocation 0                     \n"
    "   if (gl_InvocationID == 0)                       \n"
    "   {                                               \n"
    "       gl_TessLevelInner[0] = 5.0;                 \n"
    "       gl_TessLevelOuter[0] = 5.0;                 \n"
    "       gl_TessLevelOuter[1] = 5.0;                 \n"
    "       gl_TessLevelOuter[2] = 5.0;                 \n"
    "   }                                               \n"
    "                                                   \n"
    "   // Everybody copies their input to their input  \n"
    "   gl_out[gl_InvocationID].gl_Position =           \n"
    "       gl_in[gl_InvocationID].gl_Position;         \n"
    "}                                                  \n"
};

// Source code for tesselation evaluation shader
static const GLchar * tesselation_evaluation_shader[] =
{
    "#version 450 core                                          \n"
    "                                                           \n"
    "layout(triangles, equal_spacing, cw) in;                   \n"
    "                                                           \n"
    "void main(void)                                            \n"
    "{                                                          \n"
    "   gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position +  \n"
    "       gl_TessCoord.y * gl_in[1].gl_Position +             \n"
    "       gl_TessCoord.z * gl_in[2].gl_Position);             \n"
    "}                                                          \n"
};

I then call the glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) in my render function right before draw the triangle using glDrawArrays(GL_TRIANGLE, 0, 3). I initially thought that the glPolygonMode was defaulting to GL_FILL but I don't think that's the issue since I am just following a book (OpenGL Superbible 7th Edition). How can I fix this?

Edit:
I have added the code of my entire program below:

GLuint compile_shaders(void)
{
    GLuint vertex_shader;
    GLuint fragment_shader;
    GLuint control_shader;
    GLuint evaluation_shader;
    GLuint program;

    // Source code for Vertex Shader
    static const GLchar * vertex_shader_source[] =
    {
        "#version 450 core                                                      \n"
        "                                                                       \n"
        "// offset and color are input vertex attribute                         \n"
        "layout (location = 0) in vec4 offset;                                  \n"
        "layout (location = 1) in vec4 color;                                   \n"
        "                                                                       \n"
        "//Declare VS_OUT as an output interface block                          \n"
        "out VS_OUT                                                             \n"
        "{                                                                      \n"
        "   vec4 color; //Send color to next stage                              \n"
        "}vs_out;                                                               \n"
        "                                                                       \n"
        "void main(void)                                                        \n"
        "{                                                                      \n"
        "   //Decalre a hardcoded array of positions                            \n"
        "   const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0),       \n"
        "                                    vec4(-0.25, -0.25, 0.5, 1.0),      \n"
        "                                    vec4(0.25, 0.25, 0.5, 1.0));       \n"
        "                                                                       \n"
        "   //Index into our array using gl_VertexID                            \n"
        "   gl_Position = vertices[gl_VertexID] + offset;                       \n"
        "                                                                       \n"
        "//color = vec4(1.0, 0.0, 0.0, 1.0);                                    \n"
        "//Output fixed value for vs_color                                      \n"
        "vs_out.color = color;                                                  \n"
        "}                                                                      \n"
    };

    // Source code for Fragment Shader
    static const GLchar * fragment_shader_source[] =
    {
        "#version 450 core                                                              \n"
        "                                                                               \n"
        "//Declare VS_OUT as an input interface block                                   \n"
        "in VS_OUT                                                                      \n"
        "{                                                                              \n"
        "   vec4 color; //Send color to next stage                                      \n"
        "}fs_in;                                                                        \n"
        "                                                                               \n"
        "//Ouput to the framebuffer                                                     \n"
        "out vec4 color;                                                                \n"
        "                                                                               \n"
        "void main(void)                                                                \n"
        "{                                                                              \n"
        "// Simply assign the color we were given by the vertex shader to our output    \n"
        "   color = fs_in.color;                                                        \n"
        "}                                                                              \n"
    };

    // Source code for Tesselation Control Shader
    static const GLchar * tesselation_control_shader[] = 
    {
        "#version 450 core                                  \n"
        "                                                   \n"
        "layout(vertices = 3) out;                          \n"
        "                                                   \n"
        "void main(void)                                    \n"
        "{                                                  \n"
        "   //Only if I am invocation 0                     \n"
        "   if (gl_InvocationID == 0)                       \n"
        "   {                                               \n"
        "       gl_TessLevelInner[0] = 5.0;                 \n"
        "       gl_TessLevelOuter[0] = 5.0;                 \n"
        "       gl_TessLevelOuter[1] = 5.0;                 \n"
        "       gl_TessLevelOuter[2] = 5.0;                 \n"
        "   }                                               \n"
        "                                                   \n"
        "   // Everybody copies their input to their input  \n"
        "   gl_out[gl_InvocationID].gl_Position =           \n"
        "       gl_in[gl_InvocationID].gl_Position;         \n"
        "}                                                  \n"
    };

    // Source code for tesselation evaluation shader
    static const GLchar * tesselation_evaluation_shader[] =
    {
        "#version 450 core                                          \n"
        "                                                           \n"
        "layout(triangles, equal_spacing, cw) in;                   \n"
        "                                                           \n"
        "void main(void)                                            \n"
        "{                                                          \n"
        "   gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position +  \n"
        "       gl_TessCoord.y * gl_in[1].gl_Position +             \n"
        "       gl_TessCoord.z * gl_in[2].gl_Position);             \n"
        "}                                                          \n"
    };

    // Create and compiler Vertex Shader
    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
    glCompileShader(vertex_shader);

    // Create and compiler Fragment Shader
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
    glCompileShader(fragment_shader);


    // Create and compile tesselation control shader
    control_shader = glCreateShader(GL_TESS_CONTROL_SHADER);
    glShaderSource(control_shader, 1, tesselation_control_shader, NULL);
    glCompileShader(control_shader);

    // Create and compile tesselation evaluation shader
    evaluation_shader = glCreateShader(GL_TESS_CONTROL_SHADER);
    glShaderSource(evaluation_shader, 1, tesselation_control_shader, NULL);
    glCompileShader(evaluation_shader);

    // Create program, attach shaders to it, and link it
    program = glCreateProgram();
    glAttachShader(program, vertex_shader);
    glAttachShader(program, fragment_shader);
    glAttachShader(program, control_shader);
    glAttachShader(program, evaluation_shader);
    glLinkProgram(program);

    // Delete shaders as program has them now
    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);
    glDeleteShader(control_shader);
    glDeleteShader(evaluation_shader);

    return program;
};

class TesselationCSOne : public sb7::application
{
public:

    void startup()
    {
        rendering_program = compile_shaders();
        glCreateVertexArrays(1, &vertex_array_object);
        glBindVertexArray(vertex_array_object);
    }

    void shutdown()
    {
        glDeleteVertexArrays(1, &vertex_array_object);
        glDeleteProgram(rendering_program);
        glDeleteVertexArrays(1, &vertex_array_object);
    }

    // Our rendering function
    void render(double currentTime)
    {
        // Sets colour
        static const GLfloat color[] = { (float)sin(currentTime) * 0.5f + 0.5f, (float)sin(currentTime) * 0.5f + 0.5f, 0.0f, 1.0f };

        glClearBufferfv(GL_COLOR, 0, color);

        //Tell OpenGL to draw only the outlines of the resulting triangle
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

        // Use program object we created for rendering
        glUseProgram(rendering_program);

        GLfloat attrib[] = { 1.0, 0.0, 0.0, 0.0 };/*{ (float)sin(currentTime) * 0.5f, (float)sin(currentTime) * 0.6f, 0.0f, 0.0f };*/

        // Update value of input attribute 0
        glVertexAttrib4fv(0, attrib);

        // Draw pathes for tesselation shaders
        glPatchParameteri(GL_PATCH_VERTICES, 3);
        // Draw one triangle
        glDrawArrays(GL_PATCHES, 0, 3);
    }

private:

    GLuint rendering_program;
    GLuint vertex_array_object;
};

// Only instance of DECLARE_MAIN to state entry point
DECLARE_MAIN(TesselationCSOne);

Upvotes: 1

Views: 1199

Answers (2)

MinorMapillai
MinorMapillai

Reputation: 199

So after checking a lot of sources and the Superbible's code repository I realized I have a lot of unnecessary code (For example, the interface blocks in the shaders) and even quite a few mistakes (For example I had two program varibles).
But, after fixing all that the code that produces the required output (A tessellated triangle) is:

/**
        Program to draw a triangle with tesselation.
**/
#include <sb7.h>

class TesselatedTriangle : public sb7::application
{
    void init()
    {
        static const char title[] = "Tessellated Triangle";

        sb7::application::init();

        memcpy(info.title, title, sizeof(title));
    }

    virtual void startup()
    {
        static const char * vertex_shader_source[] =
        {
            "#version 450 core                                                 \n"
            "                                                                  \n"
            "void main(void)                                                   \n"
            "{                                                                 \n"
            "    const vec4 vertices[] = vec4[](vec4( 0.25, -0.25, 0.5, 1.0),  \n"
            "                                   vec4(-0.25, -0.25, 0.5, 1.0),  \n"
            "                                   vec4( 0.25,  0.25, 0.5, 1.0)); \n"
            "                                                                  \n"
            "    gl_Position = vertices[gl_VertexID];                          \n"
            "}                                                                 \n"
        };

        static const char * tesselation_control_shader_source[] =
        {
            "#version 450 core                                                                 \n"
            "                                                                                  \n"
            "layout (vertices = 3) out;                                                        \n"
            "                                                                                  \n"
            "void main(void)                                                                   \n"
            "{                                                                                 \n"
            "    if (gl_InvocationID == 0)                                                     \n"
            "    {                                                                             \n"
            "        gl_TessLevelInner[0] = 5.0;                                               \n"
            "        gl_TessLevelOuter[0] = 5.0;                                               \n"
            "        gl_TessLevelOuter[1] = 5.0;                                               \n"
            "        gl_TessLevelOuter[2] = 5.0;                                               \n"
            "    }                                                                             \n"
            "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;     \n"
            "}                                                                                 \n"
        };

        static const char * tesselation_evaluation_shader_source[] =
        {
            "#version 450 core                                                                 \n"
            "                                                                                  \n"
            "layout (triangles, equal_spacing, cw) in;                                         \n"
            "                                                                                  \n"
            "void main(void)                                                                   \n"
            "{                                                                                 \n"
            "    gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +                       \n"
            "                  (gl_TessCoord.y * gl_in[1].gl_Position) +                       \n"
            "                  (gl_TessCoord.z * gl_in[2].gl_Position);                        \n"
            "}                                                                                 \n"
        };

        static const char * fragment_shader_source[] =
        {
            "#version 450 core                                                 \n"
            "                                                                  \n"
            "out vec4 color;                                                   \n"
            "                                                                  \n"
            "void main(void)                                                   \n"
            "{                                                                 \n"
            "    color = vec4(0.0, 0.8, 1.0, 1.0);                             \n"
            "}                                                                 \n"
        };

        rendering_program = glCreateProgram();

        // Compile shaders
        GLuint vs = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vs, 1, vertex_shader_source, NULL);
        glCompileShader(vs);

        GLuint tcs = glCreateShader(GL_TESS_CONTROL_SHADER);
        glShaderSource(tcs, 1, tesselation_control_shader_source, NULL);
        glCompileShader(tcs);

        GLuint tes = glCreateShader(GL_TESS_EVALUATION_SHADER);
        glShaderSource(tes, 1, tesselation_evaluation_shader_source, NULL);
        glCompileShader(tes);

        GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fs, 1, fragment_shader_source, NULL);
        glCompileShader(fs);

        // Attach shaders to the program
        glAttachShader(rendering_program, vs);
        glAttachShader(rendering_program, tcs);
        glAttachShader(rendering_program, tes);
        glAttachShader(rendering_program, fs);

        // Link the program
        glLinkProgram(rendering_program);

        // Generate vertex arrays
        glGenVertexArrays(1, &vertex_array_object);
        glBindVertexArray(vertex_array_object);

        // Declare the drawing mode for the polygons
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    }

    virtual void render(double currentTime)
    {
        static const GLfloat green[] = { 0.0f, 0.25f, 0.0f, 1.0f };

        glClearBufferfv(GL_COLOR, 0, green);

        glUseProgram(rendering_program);

        glDrawArrays(GL_PATCHES, 0, 3);
    }

    virtual void shutdown()
    {
        glDeleteVertexArrays(1, &vertex_array_object);

        glDeleteProgram(rendering_program);
    }


private:

    GLuint          rendering_program;
    GLuint          vertex_array_object;

};

// One and only instance of DECLARE_MAIN
DECLARE_MAIN(TesselatedTriangle)

Hopefully this helps somebody else with the same problem.

Upvotes: 1

Rabbid76
Rabbid76

Reputation: 210998

If you use a tessellation shader then you have to draw Patches. You have to set the size of the patches by glPatchParameteri( GL_PATCH_VERTICES, ...) and the primitive type has to be GL_PATCHES.

If the the number of vertices in a patch is 3, then you have to do it like this:

glPatchParameteri(GL_PATCH_VERTICES, 3); 
glDrawArrays(GL_PATCHES, 0, 3)

See OpenGL 4.6 API Core Profile Specification; 10.1.15 Separate Patches; page 342:

Separate patches are specified with mode PATCHES. A patch is an ordered collection of vertices used for primitive tessellation (section 11.2). The vertices comprising a patch have no implied geometric ordering. The vertices of a patch are used by tessellation shaders and the fixed-function tessellator to generate new point, line, or triangle primitives.

void PatchParameteri( enum pname, int value );

with pname set to PATCH_VERTICES


Your shader program doesn't even link, because the fragment shader tries to read from an input interface block, which is not declared as an output from the previous shader stage.
You have to pass the vertex attributes, through the tessellation control and evaluation shader to the fragment shader:

Tessellation control shader:

#version 450 core                                 

layout(vertices = 3) out;

in VS_OUT                                                                    
{                                                                            
   vec4 color;                                   
} tesc_in[];

out TESC_OUT                                                                    
{                                                                            
   vec4 color;                                   
} tesc_out[];                          

void main(void)                                   
{                                                 
   if (gl_InvocationID == 0)                      
   {                                              
       gl_TessLevelInner[0] = 5.0;                
       gl_TessLevelOuter[0] = 5.0;                
       gl_TessLevelOuter[1] = 5.0;                
       gl_TessLevelOuter[2] = 5.0;                
   }                                              

   tesc_out[gl_InvocationID].color     = tesc_in[gl_InvocationID].color;                    
   gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;        
} 

Tessellation evaluation shader:

#version 450 core                                         

layout(triangles, equal_spacing, cw) in; 

in TESC_OUT                                                                    
{                                                                            
   vec4 color;                                   
} tese_in[];

out TESE_OUT                                                                    
{                                                                            
   vec4 color;                                   
} tese_out;                  

void main(void)                                           
{                               
   tese_out.color = ( gl_TessCoord.x * tese_in[0].color + 
                      gl_TessCoord.y * tese_in[1].color +            
                      gl_TessCoord.z * tese_in[2].color ) / 3.0;

   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 ) / 3.0;            
}                                                         

Fragment shader:

#version 450 core                                                            

in TESE_OUT                                                                    
{                                                                            
   vec4 color;                                  
} fs_in;                                                                      

out vec4 color;                                                              

void main(void)                                                              
{                                                                            
   color = fs_in.color;                                                      
}       

Further, I recommend to check if a shader object was successfully compiled:

GLuint shaderObj = .... ;
glCompileShader( shaderObj );

GLint status = GL_TRUE;
glGetShaderiv( shaderObj, GL_COMPILE_STATUS, &status );
if ( status == GL_FALSE )
{
    GLint logLen;
    glGetShaderiv( shaderObj, GL_INFO_LOG_LENGTH, &logLen );
    std::vector< char >log( logLen );
    GLsizei written;
    glGetShaderInfoLog( shaderObj, logLen, &written, log.data() );
    std::cout << "compile error:" << std::endl << log.data() << std::endl;
}

and a shader program object was successfully linked:

GLuint progObj = ....;
glLinkProgram( progObj );

GLint status = GL_TRUE;
glGetProgramiv( progObj, GL_LINK_STATUS, &status );
if ( status == GL_FALSE )
{
    GLint logLen;
    glGetProgramiv( progObj, GL_INFO_LOG_LENGTH, &logLen );
    std::vector< char >log( logLen );
    GLsizei written;
    glGetProgramInfoLog( progObj, logLen, &written, log.data() );
    std::cout  << "link error:" << std::endl << log.data() << std::endl;
}

By the way, read about Raw string literals, which simplify the declaration of the shader source code strings:

e.g.

std::string fragment_shader_source = R"(
#version 450 core                                                            

in TESE_OUT                                                                    
{                                                                            
    vec4 color;                                  
} fs_in;                                                                      

out vec4 color;                                                              

void main(void)                                                              
{                                                                            
    color = fs_in.color;                                                      
}                                                                          
)"; 

Further note, the the offset probably moves the the triangle out of the viewport. Either change the value of the offset in the attribute initialization:

GLfloat attrib[] = { 0.0, 0.0, 0.0, 0.0 };

or get rid of the offest in the vertex shader for debug reasons

gl_Position = vertices[gl_VertexID]; 

You have to ensure that the color attribute is set too:

GLfloat attrib1[] = { 1.0, 1.0, 0.0, 1.0 };
glVertexAttrib4fv(1, attrib1);

The result may look like this:

preview

Upvotes: 3

Related Questions