【问题标题】:what is the correct way to use glBindAttribLocation()?使用 glBindAttribLocation() 的正确方法是什么?
【发布时间】:2021-09-23 04:09:56
【问题描述】:

我最近一直在尝试学习 OpenGL。我对glBindAttribLocation 的正确用法非常困惑,因为我认为它将着色器中的属性(例如in vec3 position;)设置为VAO 中的数据(例如VAO 中的属性0)。但是,当我注释掉线(第 136 行)时,三角形的颜色仍然可以很好地渲染,因此着色器必须以其他方式了解位置和颜色数据,但我对如何操作感到困惑。哪一行告诉着色器有关数据的信息,或者着色器只是自动从 VAO 中读取属性?

我在上一个问题中被告知,该行需要在着色器链接之前,所以我移动了它,但该行似乎仍然对我的程序没有影响。

这是我的代码的链接(它的 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;
}

提前感谢您的帮助!

【问题讨论】:

  • 请在问题中提供相关代码作为文本。话虽如此,在链接的代码中,您使用positionAttribute = glGetAttribLocation(...) 查询属性位置,然后执行glBindAttribLocation(shaderProgramID, positionAttribute...)。因此,您所做的只是将属性位置设置为其预先存在的值。
  • 是的,我在上一个问题中已经意识到这一点,这就是我问这个问题的原因,因为我不知道如何使用该功能。我还将提供我的代码作为问题的文本!

标签: opengl glsl shader vbo vao


【解决方案1】:

您的代码实际上没有意义。如果您还没有链接shaderProgramID,那么您不能调用glGetAttribLocation。如果你已经链接了shaderProgramID,那么对glBindAttribLocation 的调用将不起作用,因为它们只会影响后续的链接操作。

最后,如果您已经有了该属性的位置(也就是说,如果glGetAttribLocation 有效),那么调用glBindAttribLocation没有意义,因为您已经知道答案了。所以在同一个程序上调用getbind 从来没有任何意义永远。要么你正确地告诉 OpenGL 使用哪个属性位置(因此没有理由稍后再询问),要么你想查询属性位置(因此不想指定它)。

链接的 GLSL 程序包含属性名称和位置之间的映射。你可以define this mapping in various ways。但是,如果您在链接程序之前 没有提供带有位置的属性,那么OpenGL 将分配该属性一个位置。一旦发生这种情况,您就没有可以为该程序做任何事情。

设置属性位置的最佳方法是在着色器中使用layout(location = #) 说明符。这样,您就不必从glGetAttribLocation 查询任何内容,也无需使用glBindAttribLocation。为属性索引选择一个标准约定,然后从那里开始。例如,您可以说标准颜色都使用属性 2。您无需询问程序其颜色在哪个属性索引中;你知道它是 2。

这最终与命名属性的约定没有什么不同。您上面的代码假定属性名为“位置”和“颜色”。如果着色器的制造者使用了错误的名称,您的代码将无法工作。使用数字代替名称没有什么不同,您可以避免询问属性位置。

【讨论】:

  • 非常感谢您的详细解答!因此,为了澄清,顶点着色器的属性会自动分配,我可以在 vec3 位置使用“布局(位置 = 0);”在顶点着色器中设置位置(颜色相同)?我仍然不太确定的一件事是如果我想使用 glBindAttribLocation() 我会在哪里使用它?正如您在第一段中提到的,这使得它似乎无法在我的代码中使用。
  • @Egg42: "我仍然不太确定的一件事是如果我想使用 glBindAttribLocation() 我会在哪里使用它?" 段落和随附的链接,说“在链接程序之前”。 "自动分配顶点着色器的属性" 不,它会自动分配只有在您没有明确分配它时,例如location = #glBindAttribLocation。请阅读全文。
  • 好的,我明白了。非常感谢您的帮助:)
猜你喜欢
  • 1970-01-01
  • 2021-11-24
  • 2017-04-07
  • 2013-01-09
  • 2013-03-19
  • 2019-05-11
  • 2018-02-17
  • 2022-01-07
  • 2012-05-17
相关资源
最近更新 更多