顶点阴影错误 - 变量声明顺序
The vertex shade bug - variables declaration order
我已经开始学习 C++/OpenGL 一年了,我偶然发现了 GLSL 语言的一个模糊错误。不知道有没有人遇到过类似的。
仅当我在顶点阴影中省略 layout(location = ?)
并且我必须手动为 glVertexAttribPointer
和 glEnableVertexArrayAttrib
指定通用顶点属性的索引时才会产生错误,我的意思是,通过省略 glGetAttribLocation
的使用,它最终将从顶点阴影中获取顶点属性的索引位置。奇怪的是,以特定顺序声明输入和输出变量。在我的顶点阴影中,例如,如果我用这个顺序声明它们:
gl_Position = vec4(aVertex, 1.0);
color = aColor;
它不会产生故障,但是,如果我颠倒声明顺序,它就会变得很明显。
幸运的是,我修复了它。但我需要更多解释,尤其是在 GLSL 语言中,为什么变量声明顺序很重要。在C/C++中,似乎无关紧要。
这里是此错误的完整示例:[我使用了 SFML/Glew 库]
#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;
}
如果您在 GLSL 中省略了位置,OpenGL 将按照它认为合适的方式分配它们。因此,如果您甚至不使用 glGetAttribLocation
查询它们并假设 aVertex
为 0,aColor
为 1,那么如果编译器不同意,当然会出现故障。
GLSL 链接器完全有可能根据第一次使用分配位置,但同样,没有任何保证。我认为明确设置位置没有任何缺点,O
如果不通过layout qualifiers指定属性索引,则不指定属性索引,可以有任何值。不能保证顺序,也不能保证索引是 0 和 1。
在 link 程序之前,您必须使用 glGetAttribLocation
after you link the program, or you must specify the attribute indexes with glBindAttribLocation
获取属性索引。
我已经开始学习 C++/OpenGL 一年了,我偶然发现了 GLSL 语言的一个模糊错误。不知道有没有人遇到过类似的。
仅当我在顶点阴影中省略 layout(location = ?)
并且我必须手动为 glVertexAttribPointer
和 glEnableVertexArrayAttrib
指定通用顶点属性的索引时才会产生错误,我的意思是,通过省略 glGetAttribLocation
的使用,它最终将从顶点阴影中获取顶点属性的索引位置。奇怪的是,以特定顺序声明输入和输出变量。在我的顶点阴影中,例如,如果我用这个顺序声明它们:
gl_Position = vec4(aVertex, 1.0);
color = aColor;
它不会产生故障,但是,如果我颠倒声明顺序,它就会变得很明显。
幸运的是,我修复了它。但我需要更多解释,尤其是在 GLSL 语言中,为什么变量声明顺序很重要。在C/C++中,似乎无关紧要。
这里是此错误的完整示例:[我使用了 SFML/Glew 库]
#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;
}
如果您在 GLSL 中省略了位置,OpenGL 将按照它认为合适的方式分配它们。因此,如果您甚至不使用 glGetAttribLocation
查询它们并假设 aVertex
为 0,aColor
为 1,那么如果编译器不同意,当然会出现故障。
GLSL 链接器完全有可能根据第一次使用分配位置,但同样,没有任何保证。我认为明确设置位置没有任何缺点,O
如果不通过layout qualifiers指定属性索引,则不指定属性索引,可以有任何值。不能保证顺序,也不能保证索引是 0 和 1。
在 link 程序之前,您必须使用 glGetAttribLocation
after you link the program, or you must specify the attribute indexes with glBindAttribLocation
获取属性索引。