如何解决在openGL的顶点着色器中设置属性
我最近一直在学习 OpenGL,但对着色器和 VBO 有点困惑。
基本上,我对顶点着色器如何知道 VBO 中的颜色和位置数据感到困惑。
据我所知,glBindAttribLocation(program,attribute,variable);
是在着色器中设置属性的原因,但是当我注释掉该代码时,三角形的颜色仍然可以很好地呈现。
这是我的代码:
public static void main(String[] args) {
String vertexSource = "#version 400 core\n"
+ "in vec3 position;\n"
+ "in vec3 colour;\n"
+ "out vec3 vertexColour;\n"
+ "uniform mat4 model;\n"
+ "uniform mat4 view;\n"
+ "uniform mat4 projection;\n"
+ "void main() {\n"
+ "vertexColour = colour;\n"
+ "mat4 mvp = projection * view * model;\n"
+ "gl_Position = vec4(position,1.0);\n"
+ "}\n";
String fragmentSource = "#version 400 core\n"
+ "in vec3 vertexColour;\n"
+ "out vec4 colours;\n"
+ "void main()\n"
+ "{\n"
+ " colours = vec4(vertexColour,1);\n"
+ "}";
glfwSetErrorCallback(errorCallBack);
if (!glfwInit()) {
throw new IllegalStateException("Unable to initialize GLFW");
}
glfwDefaultwindowHints();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MInor,3);
glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GLFW_TRUE);
glfwWindowHint(GLFW_VISIBLE,GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE,GL_FALSE);
long window = glfwCreateWindow(640,480,"my window!",0);
glfwSetKeyCallback(window,keyCallback);
if (window == 0) {
glfwTerminate();
throw new RuntimeException("Failed to create the GLFW window");
}
glfwMakeContextCurrent(window);
GL.createCapabilities();
float[] vertexPoints = {
0f,0.5f,0f,-0.5f,0f
};
float[] colours = {
0.1f,0.3f,0.7f,0.9f,0.4f,0.1f
};
ArrayList<Integer> vaos = new ArrayList<Integer>();
ArrayList<Integer> vbos = new ArrayList<Integer>();
int vaoID = glGenVertexArrays();
vaos.add(vaoID);
glBindVertexArray(vaoID);
FloatBuffer vertices = BufferUtils.createFloatBuffer(vertexPoints.length);
vertices.put(vertexPoints);
vertices.flip();
int vboID = GL33.glGenBuffers();
vbos.add(vboID);
glBindBuffer(GL_ARRAY_BUFFER,vboID);
glBufferData(GL_ARRAY_BUFFER,vertices,GL_STATIC_DRAW);
//add it to the vao at position 0,size 3,with data types of float,normalised = false,glVertexAttribPointer(0,3,GL_FLOAT,false,0);
//unbind currently bound vbo
glBindBuffer(GL_ARRAY_BUFFER,0);
//and one for the colour data
vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER,colours,GL_STATIC_DRAW);
glVertexAttribPointer(1,0);
glBindBuffer(GL_ARRAY_BUFFER,0);
//finished with vao Now unbind it
glBindVertexArray(0);
//vao and vbo stuff is Now finished with
//Now for the shader stuff
int vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderID,vertexSource);
glCompileShader(vertexShaderID);
if (!checkForSuccess(vertexShaderID)) {
glfwTerminate();
throw new IllegalStateException("vertex shader Failed: " + glGetShaderInfoLog(vertexShaderID));
}
int fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShaderID,fragmentSource);
glCompileShader(fragmentShaderID);
if (!checkForSuccess(vertexShaderID)) {
glGetShaderInfoLog(vertexShaderID);
glfwTerminate();
throw new IllegalStateException("fragment shader Failed");
}
//shader program
int shaderProgramID = glCreateProgram();
glAttachShader(shaderProgramID,vertexShaderID);
glAttachShader(shaderProgramID,fragmentShaderID);
glLinkProgram(shaderProgramID);
//error test
int status = glGetProgrami(shaderProgramID,GL_LINK_STATUS);
if (status != GL_TRUE) {
glfwTerminate();
throw new RuntimeException(glGetProgramInfoLog(shaderProgramID));
}
gluseProgram(shaderProgramID);
//setting position attribute in the shader:
int positionAttribute = glGetAttribLocation(shaderProgramID,"position");
glEnabLevertexAttribArray(positionAttribute);
glBindAttribLocation(shaderProgramID,positionAttribute,"position");
//setting colour attribute in the shader:
int colourAttribute = glGetAttribLocation(shaderProgramID,"colour");
glEnabLevertexAttribArray(colourAttribute);
glBindAttribLocation(shaderProgramID,colourAttribute,"colour");
glClearColor(0.5f,1f);
//this will create a wire frame view
//glpolygonMode(GL_FRONT_AND_BACK,GL_LINE);
glfwShowWindow(window); //optional
while (!glfwWindowShouldClose(window)) {
double time = glfwGetTime();
glfwPollEvents();
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vaoID);
//enables the position attribute in the vertex shader
glEnabLevertexAttribArray(0);
//enables the colour attribute in the vertex shader
glEnabLevertexAttribArray(1);
glDrawArrays(GL_TRIANGLES,vertexPoints.length);
//disables the position and colour attribute in the vertex shader
gldisabLevertexAttribArray(0);
gldisabLevertexAttribArray(1);
glfwSwapBuffers(window);
}
//clear vaos and vbos
for (int vao : vaos) {
glDeleteVertexArrays(vao);
}
for (int vbo : vbos) {
glDeleteBuffers(vbo);
}
//delete shaders
glDetachShader(shaderProgramID,vertexShaderID);
glDetachShader(shaderProgramID,fragmentShaderID);
glDeleteShader(vertexShaderID);
glDeleteShader(fragmentShaderID);
glDeleteProgram(shaderProgramID);
Callbacks.glfwFreeCallbacks(window);
glfwDestroyWindow(window);
glfwTerminate();
}
我在 github 上提供了我的完整代码文件(250 行):https://github.com/OneEgg42/opengl
有人会这么好心向我解释这是如何工作的吗?
提前致谢!
解决方法
VBO 和着色器之间的关系不是由 glBindAttribLocation
建立的。
相关行实际上是
glBindBuffer(GL_ARRAY_BUFFER,vboID);
glVertexAttribPointer(0,3,GL_FLOAT,false,0);
告诉 OpenGL 位置为 0 的属性(第一个 glVertexAttribPointer
调用中的第一个参数)应该从 vboID
读取前三个浮点数。
glBindAttribLocation
负责将某个属性绑定到特定位置。由于这必须在链接着色器之前完成,因此它们不会在您的代码中执行任何操作。更重要的是,因为这段代码告诉属性使用它已经拥有的位置:
int positionAttribute = glGetAttribLocation(shaderProgramID,"position");
glEnableVertexAttribArray(positionAttribute);
glBindAttribLocation(shaderProgramID,positionAttribute,"position");
您基本上是查询位置,然后再次将位置分配给属性。
附注:
-
目前您的代码完全靠运气。您假设在
glVertexAttribPointer(0,0);
行中“位置”属性位于位置 0,只要它是着色器中写入的第一个属性,它就可能位于该位置。颜色也一样。当您在着色器中交换两个属性定义的顺序时,您的代码很可能会中断。 使用glGetAttribLocation
查询属性位置并使用结果而不是 0 和 1,或者在链接之前使用glBindAttribLocation
以确保属性位于您期望的位置。 -
对
glEnableVertexAttribArray
的调用应该在 VAO 设置代码中,而不是在渲染循环中。
设置:
glBindBuffer(GL_ARRAY_BUFFER,vboID);
glBufferData(GL_ARRAY_BUFFER,vertices,GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,0);
渲染:
glBindVertexArray(vaoID);
glDrawArrays(GL_TRIANGLES,vertexPoints.length);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。