I've started studying C++/OpenGL for a year, I've stumbled on a vague bug with GLSL language. I wonder if someone had got it similarly.
The bug is produced only when I omitted the layout(location = ?)
in the vertex shade and I've to specify the index of the generic vertex attribute for both glVertexAttribPointer
and glEnableVertexArrayAttrib
manually, I mean, by omitting the use of glGetAttribLocation
which will eventually get the index-location for vertex attributes from the vertex shade. The strange part is, to declare the input and output variables in specific order. In my vertex shade, e.g if I have declared them with this order:
gl_Position = vec4(aVertex, 1.0);
color = aColor;
It won't generate the glitch however, if I reversed the declaration order it will become obvious.
Fortunately, I fixed it. But I need more explanation about it especially in GLSL language, why is the variables declaration order a matter. In C/C++, it seems irrelevant.
Here complete example of this bug: [I used SFML/Glew libraries]
#include <SFML/Window.hpp>
#include <GL/GLew.h>
//turn it ON/OFF e.g Enable_Bug [1|0]
#define Enable_Bug 1 // to produce the Bug, we should omit glGetAttribLocation(),
// shader sources
static const GLchar* vert_R = R"(#version 440 core
// We have a Bug!
#define Enable_Bug_GLSL 0 // here the catch, if we turned this OFF by turning [Enable_Bug_GLSL 0]
// and both [Enable_Bug_GLSL_Attrib | Enable_Bug] are ON, it will fix the Bug!! weird
#define Enable_Bug_GLSL_Attrib 1 // to produce the Bug, we should omit layout(location = ?)
#if Enable_Bug_GLSL_Attrib
in vec3 aVertex;
in vec4 aColor;
#else
layout(location = 0) in vec3 aVertex;
layout(location = 1) in vec4 aColor;
#endif
out vec4 color;
void main()
{
#if Enable_Bug_GLSL
color = aColor;
gl_Position = vec4(aVertex, 1.0);
#else
gl_Position = vec4(aVertex, 1.0);
color = aColor;
#endif
}
)";
static const GLchar* frag_R = R"(#version 440 core
in vec4 color;
layout(location = 0) out vec4 FragColor;
void main()
{
FragColor = color;
}
)";
static void checkStatus(GLuint obj)
{
GLint status = GL_FALSE;
if (glIsShader(obj)) glGetShaderiv(obj, GL_COMPILE_STATUS, &status);
if (glIsProgram(obj)) glGetProgramiv(obj, GL_LINK_STATUS, &status);
if (status == GL_TRUE) return;
glDeleteShader(obj);
obj = 0;
}
static void attachShader(GLuint program, GLenum type, const GLchar* src)
{
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, NULL);
glCompileShader(shader);
checkStatus(shader);
glAttachShader(program, shader);
glDeleteShader(shader);
}
static GLuint loadShader(const GLchar* vert, const GLchar* frag, const GLchar* geom = nullptr)
{
GLuint progam = glCreateProgram();
if (vert) attachShader(progam, GL_VERTEX_SHADER, vert);
if (geom) attachShader(progam, GL_GEOMETRY_SHADER, geom);
if (frag) attachShader(progam, GL_FRAGMENT_SHADER, frag);
glLinkProgram(progam);
checkStatus(progam);
return progam;
}
int main()
{
sf::Window window(sf::VideoMode(800, 600), "OpenGL");
//Initialize GLEW
glewExperimental = GL_TRUE;
GLenum err = glewInit();
//If GLEW hasn't initialized
if (err != GLEW_OK)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
throw std::runtime_error("Failed to initialize GLEW\n");
return -1;
}
GLfloat position[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
GLfloat color[] = {
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
};
GLuint program = loadShader(vert_R, frag_R);
glUseProgram(program);
GLint location;
#if Enable_Bug
location = 0;
#else
location = glGetAttribLocation(program, "aVertex");
#endif
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 0, position);
#if Enable_Bug
location = 1;
#else
location = glGetAttribLocation(program, "aColor");
#endif
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, color);
// Initialize clear colors
glClearColor(0.f, 0.f, 0.f, 1.f);
while (window.isOpen())
{
sf::Event windowEvent;
while (window.pollEvent(windowEvent))
{
if (windowEvent.type == sf::Event::Closed)
window.close();
}
// render
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
window.display();
}
return 0;
}
If you do not specify the attributes indices through layout qualifiers, the attribute indexes are not specified and can have any value. There is no guarantee of the order nor that the indices are 0 and 1.
You must get the attribute indexes with glGetAttribLocation
after you link the program, or you must specify the attribute indexes with glBindAttribLocation
before you link the program.