使用 glBindAttribLocation() 的正确方法是什么?
what is the correct way to use glBindAttribLocation()?
我最近一直在努力学习OpenGL。我对 glBindAttribLocation
的正确用法感到很困惑,因为我认为它将着色器中的属性(例如 in vec3 position;
)设置为 VAO 中的数据(例如 VAO 中的属性 0)。但是,当我注释掉该行(第 136 行)时,三角形仍然可以很好地渲染它的颜色,因此着色器必须以其他方式了解位置和颜色数据,但我对如何做到这一点感到困惑。哪一行告诉着色器有关数据的信息,还是着色器只是自动从 VAO 中读取属性?
我在上一个问题中被告知该行需要在着色器 linking 之前,所以我移动了它,但该行似乎仍然没有对我的程序产生影响。
这是我的代码的 link(它的 215 行):https://github.com/OneEgg42/opengl/blob/main/Main.java
我的代码:
public static void main(String[] args) {
//see text file for all the comments
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, 0);
glfwSetKeyCallback(window, keyCallback);
if (window == 0) {
glfwTerminate();
throw new RuntimeException("Failed to create the GLFW window");
}
glfwMakeContextCurrent(window);
GL.createCapabilities();
//the openGL positions
float[] vertexPoints = {
0f,0.5f,0f,
-0.5f,-0.5f,0f,
0.5f,-0.5f,0f
};
float[] colours = {
0.1f,0.5f,0.5f,
0.3f,0.7f,0.9f,
0.4f,0.9f,0.1f
};
//so that we can delete the vbos and vaos later
ArrayList<Integer> vaos = new ArrayList<Integer>();
ArrayList<Integer> vbos = new ArrayList<Integer>();
//creating an empty VAO and it returns the id of that vao
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);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
//and one for the colour data
vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, colours, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 0);
int vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
int fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
int shaderProgramID = glCreateProgram();
int floatSize = 4;//4 bytes
int positionAttribute = glGetAttribLocation(shaderProgramID, "position");
glEnableVertexAttribArray(positionAttribute);
glBindAttribLocation(shaderProgramID, positionAttribute, "position");
//setting colour attribute in the shader:
int colourAttribute = glGetAttribLocation(shaderProgramID, "colour");
glEnableVertexAttribArray(colourAttribute);
//glVertexAttribPointer(colourAttribute, 3, GL_FLOAT, false, 6 * floatSize, 3 * floatSize);
glBindAttribLocation(shaderProgramID, colourAttribute, "colour");
//vertex
glShaderSource(vertexShaderID, vertexSource);
glCompileShader(vertexShaderID);
if (!checkForSuccess(vertexShaderID)) {
glfwTerminate();
throw new IllegalStateException("vertex shader failed: " + glGetShaderInfoLog(vertexShaderID));
}
//fragment
glShaderSource(fragmentShaderID, fragmentSource);
glCompileShader(fragmentShaderID);
if (!checkForSuccess(vertexShaderID)) {
glGetShaderInfoLog(vertexShaderID);
glfwTerminate();
throw new IllegalStateException("fragment shader failed");
}
//shader program
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);
////////////////////////////////////////// ////////////////////////////////
glClearColor(0.5f,0.5f,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);
glDrawArrays(GL_TRIANGLES, 0, vertexPoints.length);
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();
}
public static boolean checkForSuccess(int shaderID) {
int status = glGetShaderi(shaderID, GL_COMPILE_STATUS);
return status == GL_TRUE;
}
在此先感谢您的帮助!
您的代码没有任何意义。如果您还没有 linked shaderProgramID
,那么您不能调用 glGetAttribLocation
。如果您 linked shaderProgramID
,那么调用 glBindAttribLocation
将不会执行任何操作,因为它们只会影响后续的 linking 操作。
最后,如果您已经有了属性的位置(也就是说,如果 glGetAttribLocation
有效),那么调用 glBindAttribLocation
就没有意义 ,因为你已经知道答案了。所以在同一个程序 ever 上调用 get
和 bind
从来没有任何意义。您要么正确地告诉 OpenGL 要使用什么属性位置(因此以后没有理由询问),要么您想要查询属性位置(因此不想指定它)。
linked GLSL 程序包含属性名称和位置之间的映射。你可以define this mapping in various ways。但是,如果在 之前 没有提供带有位置的属性 link 程序,则 OpenGL 将 分配 该属性的位置.一旦发生这种情况,没有什么你可以为那个程序做些什么。
设置属性位置的最佳方法是在着色器中使用 layout(location = #)
说明符。这样,您就不必从 glGetAttribLocation
查询任何内容,也无需使用 glBindAttribLocation
。为属性索引选择一个标准约定,然后从那里开始。例如,您可以说标准颜色都使用属性 2。您无需询问程序它们的颜色在哪个属性索引中;你知道它是 2.
这最终与命名属性的约定没有什么不同。您上面的代码假定属性被命名为“position”和“colour”。如果着色器的制造商使用了错误的名称,您的代码将无法运行。使用数字 而不是 的名称没有什么不同,您可以避免询问属性位置。
我最近一直在努力学习OpenGL。我对 glBindAttribLocation
的正确用法感到很困惑,因为我认为它将着色器中的属性(例如 in vec3 position;
)设置为 VAO 中的数据(例如 VAO 中的属性 0)。但是,当我注释掉该行(第 136 行)时,三角形仍然可以很好地渲染它的颜色,因此着色器必须以其他方式了解位置和颜色数据,但我对如何做到这一点感到困惑。哪一行告诉着色器有关数据的信息,还是着色器只是自动从 VAO 中读取属性?
我在上一个问题中被告知该行需要在着色器 linking 之前,所以我移动了它,但该行似乎仍然没有对我的程序产生影响。
这是我的代码的 link(它的 215 行):https://github.com/OneEgg42/opengl/blob/main/Main.java
我的代码:
public static void main(String[] args) {
//see text file for all the comments
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, 0);
glfwSetKeyCallback(window, keyCallback);
if (window == 0) {
glfwTerminate();
throw new RuntimeException("Failed to create the GLFW window");
}
glfwMakeContextCurrent(window);
GL.createCapabilities();
//the openGL positions
float[] vertexPoints = {
0f,0.5f,0f,
-0.5f,-0.5f,0f,
0.5f,-0.5f,0f
};
float[] colours = {
0.1f,0.5f,0.5f,
0.3f,0.7f,0.9f,
0.4f,0.9f,0.1f
};
//so that we can delete the vbos and vaos later
ArrayList<Integer> vaos = new ArrayList<Integer>();
ArrayList<Integer> vbos = new ArrayList<Integer>();
//creating an empty VAO and it returns the id of that vao
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);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
//and one for the colour data
vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, colours, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 0);
int vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
int fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
int shaderProgramID = glCreateProgram();
int floatSize = 4;//4 bytes
int positionAttribute = glGetAttribLocation(shaderProgramID, "position");
glEnableVertexAttribArray(positionAttribute);
glBindAttribLocation(shaderProgramID, positionAttribute, "position");
//setting colour attribute in the shader:
int colourAttribute = glGetAttribLocation(shaderProgramID, "colour");
glEnableVertexAttribArray(colourAttribute);
//glVertexAttribPointer(colourAttribute, 3, GL_FLOAT, false, 6 * floatSize, 3 * floatSize);
glBindAttribLocation(shaderProgramID, colourAttribute, "colour");
//vertex
glShaderSource(vertexShaderID, vertexSource);
glCompileShader(vertexShaderID);
if (!checkForSuccess(vertexShaderID)) {
glfwTerminate();
throw new IllegalStateException("vertex shader failed: " + glGetShaderInfoLog(vertexShaderID));
}
//fragment
glShaderSource(fragmentShaderID, fragmentSource);
glCompileShader(fragmentShaderID);
if (!checkForSuccess(vertexShaderID)) {
glGetShaderInfoLog(vertexShaderID);
glfwTerminate();
throw new IllegalStateException("fragment shader failed");
}
//shader program
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);
////////////////////////////////////////// //////////////////////////////// glClearColor(0.5f,0.5f,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);
glDrawArrays(GL_TRIANGLES, 0, vertexPoints.length);
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();
}
public static boolean checkForSuccess(int shaderID) {
int status = glGetShaderi(shaderID, GL_COMPILE_STATUS);
return status == GL_TRUE;
}
在此先感谢您的帮助!
您的代码没有任何意义。如果您还没有 linked shaderProgramID
,那么您不能调用 glGetAttribLocation
。如果您 linked shaderProgramID
,那么调用 glBindAttribLocation
将不会执行任何操作,因为它们只会影响后续的 linking 操作。
最后,如果您已经有了属性的位置(也就是说,如果 glGetAttribLocation
有效),那么调用 glBindAttribLocation
就没有意义 ,因为你已经知道答案了。所以在同一个程序 ever 上调用 get
和 bind
从来没有任何意义。您要么正确地告诉 OpenGL 要使用什么属性位置(因此以后没有理由询问),要么您想要查询属性位置(因此不想指定它)。
linked GLSL 程序包含属性名称和位置之间的映射。你可以define this mapping in various ways。但是,如果在 之前 没有提供带有位置的属性 link 程序,则 OpenGL 将 分配 该属性的位置.一旦发生这种情况,没有什么你可以为那个程序做些什么。
设置属性位置的最佳方法是在着色器中使用 layout(location = #)
说明符。这样,您就不必从 glGetAttribLocation
查询任何内容,也无需使用 glBindAttribLocation
。为属性索引选择一个标准约定,然后从那里开始。例如,您可以说标准颜色都使用属性 2。您无需询问程序它们的颜色在哪个属性索引中;你知道它是 2.
这最终与命名属性的约定没有什么不同。您上面的代码假定属性被命名为“position”和“colour”。如果着色器的制造商使用了错误的名称,您的代码将无法运行。使用数字 而不是 的名称没有什么不同,您可以避免询问属性位置。