I started learning opengl and I'm at the stage of tessellation and I have problem, my triangle won't displaying when I attach tesselation shaders to program. Shaders compile correctly and there is no linking error. Everything seems to be fine from the code side. When i only use vertex shader and fragment shader everything works good. What could be the reason?
Shaders::Shaders(const char* vertexPath, const char* fragmentPath, const char* tessControlPath, const char* tessEvaluationPath)
{
std::string vs_str = load_file(vertexPath);
std::string fs_str = load_file(fragmentPath);
std::string tc_str = load_file(tessControlPath);
std::string te_str = load_file(tessEvaluationPath);
const char* vs_src = vs_str.c_str();
const char* fs_src = fs_str.c_str();
const char* tc_src = tc_str.c_str();
const char* te_src = te_str.c_str();
create_shader(GL_VERTEX_SHADER, vertexShader, vs_src);
create_shader(GL_FRAGMENT_SHADER, fragmentShader, fs_src);
create_shader(GL_TESS_CONTROL_SHADER, tessControlShader, tc_src);
create_shader(GL_TESS_EVALUATION_SHADER, tessEvaluationShader, te_src);
program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glAttachShader(program, tessControlShader);
glAttachShader(program, tessEvaluationShader);
glLinkProgram(program);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteShader(tessControlShader);
glDeleteShader(tessEvaluationShader);
glCreateVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
}
void Shaders::create_shader(GLenum type, GLuint& shader, const char* src)
{
GLint isCompiled = 0;
shader = glCreateShader(type);
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<GLchar> errorLog(maxLength);
glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
for (int i = 0; i < errorLog.size(); i++)
{
std::cerr << errorLog[i];
}
glDeleteShader(shader);
}
}
int main()
{
Window* window = new Window(1200, 1000);
Shaders* shader = new Shaders("shaders/vertex.glsl", "shaders/fragment.glsl", "shaders/tess_control.glsl", "shaders/tess_evaluation.glsl");
while (glfwWindowShouldClose(window->get_window()) == false)
{
window->loop();
const GLfloat color[]{1.0f, 0.5f, 0.5f, 1.0f};
glClearBufferfv(GL_COLOR, 0, color);
const GLfloat attrib[]{0.0f, 0.0f, 1.0f, 1.0f};
glUseProgram(shader->get_program());
glVertexAttrib4fv(0, attrib);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawArrays(GL_PATCHES, 0, 3);
}
delete window;
delete shader;
glfwTerminate();
}
vertex.glsl
#version 450 core
layout (location = 0) in vec4 color;
out VS_OUT
{
vec4 color;
} vs_out;
void main(void)
{
const vec4 vertices[3] = vec4[3](vec4( 0.25, -0.25, 0.5, 1.0), vec4(-0.25, -0.25, 0.5, 1.0), vec4(0.25, 0.25, 0.5, 1.0));
gl_Position = vertices[gl_VertexID];
vs_out.color = color;
}
fragment.glsl
#version 450 core
in VS_OUT
{
vec4 color;
} fs_in;
out vec4 color;
void main(void)
{
color = fs_in.color;
}
tess_control.glsl
#version 450 core
layout (vertices = 3) 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;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
tess_evaluation.glsl
#version 450 core
layout (triangles, equal_spacing, ccw) in;
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);
}
You have specifies the number of vertices that will be used to make up a single patch primitive, by glPatchParameteri
:
glPatchParameteri(GL_PATCH_VERTICES, 3);
glDrawArrays(GL_PATCHES, 0, 3);
Further more you have to pass the color all the way, through all the shader stages, from the vertex shader to the fragment shader:
The input to the Tessellation Control Shader is a patch and the output is patch too. But the input patch size can be different of the output patch size. While the input patch size is defined by GL_PATCH_VERTICES
, the output patch size is define by layout (vertices = 3) out
. Thus you have to specify, in the shader program, how the attributes of the input patch are mapped to the attributes of the output patch.
#version 450 core
layout (vertices = 3) out;
in VS_OUT
{
vec4 color;
} in_data[];
out VS_OUT
{
vec4 color;
} out_data[];
void main(void)
{
out_data[gl_InvocationID].color = in_data[gl_InvocationID].color;
if (gl_InvocationID = 0)
{
gl_TessLevelInner[0] = 5.0;
gl_TessLevelOuter[0] = 5.0;
gl_TessLevelOuter[1] = 5.0;
gl_TessLevelOuter[2] = 5.0;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
The Tessellation Evaluation Shader performs the interpolation. The attributes of the output patch of the tessellation control shader are interpolated dependent on gl_TessCoord
.
You have to implement the algorithm which interpolates the attributes in the shader program.
#version 450 core
layout (triangles, equal_spacing, ccw) in;
in VS_OUT
{
vec4 color;
} in_data[];
out VS_OUT
{
vec4 color;
} out_data;
void main(void)
{
out_data.color = in_data[0].color * gl_TessCoord.x + in_data[1].color * gl_TessCoord.y + in_data[2].color * gl_TessCoord.z;
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);
}