我试图让OpenGL自动为glsl-attribute分配一个ID,但它失败了。
我的主要计划:
#include <iostream>
#include <GL/glew.h>
#include <GL/glfw3.h>
#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 <string>
#include <iostream>
#include <fstream>
#include <vector>
#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<char> 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<char> 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<char> 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
的值。我错过了什么?
答案 0 :(得分:3)
您未能获得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
并不是错误strong> 输入不同的 )阶段,因此编译器/链接器不会抱怨。如果您尝试执行类似inout color
的操作,那将是一个错误,因此这就是您必须使用不同命名的变量将顶点属性传递给几何/曲面细分/片段着色器的原因。如果阶段之间的输入/输出名称不匹配,那么原始顶点属性将被视为 非活动 的可能性非常大。
此外,除非您要移调ModelViewProjection矩阵,否则您的顶点着色器中的矩阵乘法会向后移动。 OpenGL使用的列主矩阵乘法应从右向左阅读。也就是说,您从对象空间位置(最右侧)开始并转换为剪辑空间(最左侧)。
换句话说,这是转换顶点的正确方法......
gl_Position = gl_ModelViewProjectionMatrix * position;
~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~
clip space object space to clip space obj space