无法在OpenGL中将id分配给属性

我试图让OpenGL自动为glsl属性分配一个ID,但它失败了。

我的主要计划:

#include  #include  #include  #include "test.h" #include "shader_utils.h" static void error_callback(int error, const char* description) { std::cout << description << std::endl; } static void key_callback(GLFWwindow* window, int a, int b) { if (a == GLFW_KEY_ESCAPE && b == GLFW_PRESS) { glfwSetWindowShouldClose(window, GL_TRUE); } } void test() { std::cout << "Starting up" << std::endl; init(); run(); } GLFWwindow *window; GLuint shaders; GLuint vertexBuffer; int init() { glfwSetErrorCallback(error_callback); if(!glfwInit()) { return -1; } window = glfwCreateWindow(640, 480, "GLFW test", NULL, NULL); if (!window) { glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetKeyCallback(window, key_callback); glewExperimental = true; glewInit(); shaders = LoadShaders("vertex.glsl", "fragment.glsl"); GLuint vao_id; glGenVertexArrays(1, &vao_id); glBindVertexArray(vao_id); static const GLfloat vertex_data[] = { // Bottom -.5f, -.5f, -.5f, 1.f, 0.f, 0.f, -.5f, -.5f, .5f, 1.f, 0.f, 0.f, .5f, -.5f, .5f, 1.f, 0.f, 0.f, }; glGenBuffers(1, &vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); } void checkE() { std::cout << "Checking for errors: "; int err; int a = 0; while((err = glGetError()) != GL_NO_ERROR) { std::cout << "Error: " << err << std::endl; a = 1; } if(a == 0) { std::cout << "no errors" << std::endl; } std::cout.flush(); } int run() { GLfloat angle = 0; while(!glfwWindowShouldClose(window)) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(shaders); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); GLuint attrLocation = glGetAttribLocation(shaders, "location"); GLuint attrColor = glGetAttribLocation(shaders, "color"); std::cout << "AttribLocation('location'): "; std::cout << glGetAttribLocation(shaders, "location") << std::endl; std::cout << "AttribLocation('color'): "; std::cout << glGetAttribLocation(shaders, "color") << std::endl; checkE(); std::cout << std::endl; std::cout << "glEnableVertexAttribArray()" << std::endl; glEnableVertexAttribArray(attrLocation); glEnableVertexAttribArray(attrColor); checkE(); std::cout << std::endl; std::cout << "glVertexAttribPointer();" << std::endl; glVertexAttribPointer( glGetAttribLocation(shaders, "location"), // Attribute 3, // Size GL_FLOAT, // Size GL_FALSE, // Normalized 24, // Stride (GLvoid*) 0 // Offset ); checkE(); std::cout << std::endl; std::cout << "glVertexAttribPointer();" << std::endl; glVertexAttribPointer( glGetAttribLocation(shaders, "color"), 3, GL_FLOAT, GL_FALSE, 24, (GLvoid*) (3*sizeof(GLfloat)) ); checkE(); std::cout << std::endl; glDrawArrays(GL_TRIANGLES, 0, 3); checkE(); std::cout << std::endl; glDisableVertexAttribArray(attrLocation); glDisableVertexAttribArray(attrColor); checkE(); std::cout << std::endl; glfwSwapBuffers(window); glfwPollEvents(); glfwSetWindowShouldClose(window, GL_TRUE); } glfwDestroyWindow(window); glfwTerminate(); } 

程序输出:

 Starting up Compiling shader : vertex.glsl Compiling shader : fragment.glsl Linking program AttribLocation('location'): -1 AttribLocation('color'): -1 Checking for errors: no errors glEnableVertexAttribArray() Checking for errors: Error: 1281 glVertexAttribPointer(); Checking for errors: Error: 1281 glVertexAttribPointer(); Checking for errors: Error: 1281 Checking for errors: no errors Checking for errors: Error: 1281 

着色装载机:

 #include "shader_utils.h" #include  #include  #include  #include  #include "GL/glew.h" #include "GL/glfw3.h" GLuint LoadShaders(const char * vertex_file_path, const char * fragment_file_path){ // Create the shaders GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); // Read the Vertex Shader code from the file std::string VertexShaderCode; std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); if(VertexShaderStream.is_open()) { std::string Line = ""; while(getline(VertexShaderStream, Line)) VertexShaderCode += "\n" + Line; VertexShaderStream.close(); } else { std::cout << "could not open\n"; } // Read the Fragment Shader code from the file std::string FragmentShaderCode; std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); if(FragmentShaderStream.is_open()){ std::string Line = ""; while(getline(FragmentShaderStream, Line)) FragmentShaderCode += "\n" + Line; FragmentShaderStream.close(); } GLint Result = GL_FALSE; int InfoLogLength; // Compile Vertex Shader printf("Compiling shader : %s\n", vertex_file_path); char const * VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); glCompileShader(VertexShaderID); // Check Vertex Shader glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector VertexShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); // Compile Fragment Shader printf("Compiling shader : %s\n", fragment_file_path); char const * FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); glCompileShader(FragmentShaderID); // Check Fragment Shader glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector FragmentShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); // Link the program fprintf(stdout, "Linking program\n"); GLuint ProgramID = glCreateProgram(); glAttachShader(ProgramID, VertexShaderID); glAttachShader(ProgramID, FragmentShaderID); glLinkProgram(ProgramID); // Check the program glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector ProgramErrorMessage( std::max(InfoLogLength, int(1)) ); glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); fprintf(stdout, "%s\n", &ProgramErrorMessage[0]); glDeleteShader(VertexShaderID); glDeleteShader(FragmentShaderID); std::cout.flush(); return ProgramID; } 

顶点着色器:

 #version 130 in vec4 position; in vec3 color; out vec3 f_color; void main() { f_color = color; gl_Position = position * gl_ModelViewProjectionMatrix; } 

片段着色器:

 #version 130 in vec3 color; void main() { gl_FragColor = vec4(color, 1); } 

出于某种原因,我只得到-1作为两个属性的位置。 显然其余的错误是由无效的位置索引引起的?

来自OpenGL文档:
If the named attribute variable is not an active attribute in the specified program object or if name starts with the reserved prefix "gl_", a value of -1 is returned.

名称不以gl_开头,它们在着色器中使用,所以我不应该得到-1的值。 我错过了什么?

您无法获取color的属性位置,因为它未处于活动状态 。 虽然在此示例中确实使用color来计算f_color ,但片段着色器不使用f_color因此链接器确定名为: color的顶点属性处于非活动状态。

解决方案很简单,真的:

片段着色器:

 #version 130 in vec3 f_color; // RENAMED from color, so that this matches the output from the VS. void main() { gl_FragColor = vec4(f_color, 1); } 

在顶点着色器( 输入顶点属性 )和片段着色器( 输入变化 )阶段中为不同目的重用名称color不是错误,因此编译器/链接器不会抱怨。 如果您尝试执行类似于inout color ,那将是一个错误,因此这就是您必须使用不同命名的变量将顶点属性传递给几何/曲面细分/片段着色器的原因。 如果阶段之间的输入/输出名称不匹配,那么原始顶点属性将被视为非活动的可能性非常大。


此外,除非您要移调ModelViewProjection矩阵,否则您的顶点着色器中的矩阵乘法会向后移动。 OpenGL使用的列主矩阵乘法应该从右向左阅读。 也就是说,您从对象空间位置(最右侧)开始并转换为剪辑空间(最左侧)。

换句话说,这是转换顶点的正确方法……

 gl_Position = gl_ModelViewProjectionMatrix * position; ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~ clip space object space to clip space obj space