I have begun learning GLSL and OpenGL. RIght now I am trying to see how GLSL subroutines work, so I have my fragment shader here:
#version 330 core
out vec4 color;
subroutine vec4 ColorFunc();
subroutine (ColorFunc) vec4 colorBlue() {
return vec4(0.0, 0.0, 1.0, 1.0);
}
subroutine (ColorFunc) vec4 colorGreen() {
return vec4(0.0, 1.0, 0.0, 1.0);
}
subroutine uniform ColorFunc ColorSelector;
void main() {
color = ColorSelector();
}
In the application's source I load, compile link the shader and start the program at the beginning. A triangle is created and the vertex shader doesn't do anything special. The display function (the one sent to glutDisplayFunc
) looks like this:
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(TriangleVAO);
glDrawArrays(GL_TRIANGLES, 0, NumVertices);
GLint ColorSelectorLoc;
GLuint colorBlueIndex;
GLuint colorGreenIndex;
ColorSelectorLoc = glGetSubroutineUniformLocation(program, GL_FRAGMENT_SHADER, "ColorSelector");
if (ColorSelectorLoc < 0)
{
fprintf(stderr, "Error: ColorSelector is not an active subroutine uniform in the shader\n");
exit(EXIT_FAILURE);
}
colorBlueIndex = glGetSubroutineIndex(program, GL_FRAGMENT_SHADER, "colorBlue");
colorGreenIndex = glGetSubroutineIndex(program, GL_FRAGMENT_SHADER, "colorGreen");
GLsizei n;
glGetProgramStageiv(program, GL_FRAGMENT_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, &n);
GLuint *indices = new GLuint[n];
cout << "colorGreen: " << colorBlueIndex;
indices[ColorSelectorLoc] = colorGreenIndex;
glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, n, indices);
delete [] indices;
glFlush();
}
What I expect is the triangles to be green yet they are always blue, no matter the value of ColorSelector
, which is correctly retrieved (its value is 0). colorBlueIndex
is 0 and colorGreenIndex
is 1. I don't know what am I missing.
I found the problem. The subroutine's code must go before glDrawArrays:
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
GLint ColorSelectorLoc;
GLuint colorBlueIndex;
GLuint colorGreenIndex;
ColorSelectorLoc = glGetSubroutineUniformLocation(program, GL_FRAGMENT_SHADER, "ColorSelector");
if (ColorSelectorLoc < 0)
{
fprintf(stderr, "Error: ColorSelector is not an active subroutine uniform in the shader\n");
exit(EXIT_FAILURE);
}
colorBlueIndex = glGetSubroutineIndex(program, GL_FRAGMENT_SHADER, "colorBlue");
colorGreenIndex = glGetSubroutineIndex(program, GL_FRAGMENT_SHADER, "colorGreen");
GLsizei n;
glGetProgramStageiv(program, GL_FRAGMENT_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, &n);
GLuint *indices = new GLuint[n];
cout << "colorGreen: " << colorBlueIndex;
indices[ColorSelectorLoc] = colorGreenIndex;
glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, n, indices);
delete [] indices;
glBindVertexArray(TriangleVAO);
glDrawArrays(GL_TRIANGLES, 0, NumVertices);
glFlush();
}