I'm a bit confused about how the shader pipeline works with regards to passing data through each stage.
What I'm trying to do is pass color data that is loaded in the vertex stage using glVertexAttrib4fv()
through the tessellation control shader, and then the tessellation evaluation shader, so that it can be used in the fragment shader. I'm not sure if I've made some sort of conceptual mistake (quite possible, since I'm still trying to get my head around this over fixed functions), but either way, as soon as I try and pass anything through the tessellation shaders, my primitives refuse to render at all. Before that, my primitive renders, but it only renders in black. My shaders are as follows:
Vertex Shader:
static const GLchar* vss[] =
{
"#version 430 core \n"
" \n"
"layout (location = 0) in vec4 offset; \n"
"layout (location = 1) in vec4 color; \n"
" \n"
"out vec4 vs_color; \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] + offset; \n"
" vs_color = color; \n"
"} \n"
};
Tessellation control shader:
static const GLchar* tc_ss[] =
{
"#version 430 core \n"
"layout (vertices = 3) out; \n"
"in vec4 vs_color; \n"
"out vec4 tcs_color; \n"
"void main(void) \n"
"{ \n"
" if (gl_InvocationID == 0) \n"
" { \n"
" gl_TessLevelInner[0] = 10.0; \n"
" gl_TessLevelOuter[0] = 10.0; \n"
" gl_TessLevelOuter[1] = 10.0; \n"
" gl_TessLevelOuter[2] = 10.0; \n"
" } \n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; \n"
" tcs_color = vs_color; \n"
"}"
};
Tessellation Evaluation shader:
static const GLchar* te_ss[] =
{
"#version 430 core \n"
"in vec4 tcs_color; \n"
"out vec4 tes_color; \n"
"layout (triangles, equal_spacing, cw) in; \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"
" tes_color = tcs_color; \n"
"}"
};
Fragment shader:
static const GLchar* fss[] =
{
"#version 430 core \n"
"in vec4 tes_color; \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = tes_color; \n"
"} \n"
};
All shader stages can pass data between them by using input and output variables. If in the vertex shader we create an output variable, we will be able to read it on the fragment shader as an input variable.
Data is passed from shader to shader by using the in and out keywords. You create an output shader variable by using the out keyword. The out variable in one shader provides the input data to the next shader declared as an in variable. The only condition is that both of these variables must have the same name.
A Fragment Shader is the Shader stage that will process a Fragment generated by the Rasterization into a set of colors and a single depth value. The fragment shader is the OpenGL pipeline stage after a primitive is rasterized. For each sample of the pixels covered by a primitive, a "fragment" is generated.
The difference between vertex and fragment shaders is the process developed in the render pipeline. Vertex shaders could be define as the shader programs that modifies the geometry of the scene and made the 3D projection. Fragment shaders are related to the render window and define the color for each pixel.
This is not surprising, TCS inputs/outputs must be in the form:
in vec4 vs_color [];
out vec4 tcs_color [];
or in input/output blocks that also take the form of unbounded arrays:
in CustomVertex {
vec4 color;
} custom_vs [];
out CustomVertex {
vec4 color;
} custom_tcs [];
For a little bit of context, this is what a TCS / geometry shader sees as the output from vertex shaders:
in gl_PerVertex
{
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance [];
} gl_in [];
To keep things as simple as possible, I will avoid using interface blocks.
Instead, I will introduce the concept of per-patch inputs and outputs, because they will further simplify your shaders considering the color is constant across the entire tessellated surface...
in vec4 vs_color [];
patch out vec4 patch_color;
...
patch_color = vs_color [gl_InvocationID];
patch in vec4 patch_color;
out vec4 tes_color;
...
tes_color = patch_color;
With these changes, you should have a working pass-through and a slightly better understanding of how the TCS and TES stages work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With