微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 glBindAttribLocation() 的正确方法是什么?

如何解决使用 glBindAttribLocation() 的正确方法是什么?

我最近一直在努力学习 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);

    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,0f
    };
    float[] colours = {
            0.1f,0.3f,0.7f,0.9f,0.4f,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);
    
    //and one for the colour data
    vboID = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER,colours,GL_STATIC_DRAW);
    glEnabLevertexAttribArray(1);
    glVertexAttribPointer(1,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,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,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,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;
}

在此先感谢您的帮助!

解决方法

你的代码没有意义。如果您尚未链接 shaderProgramID,则无法调用 glGetAttribLocation。如果您已链接 shaderProgramID,则对 glBindAttribLocation 的调用将不起作用,因为它们只会对后续链接操作产生影响。

最后,如果您已经有了属性的位置(即,如果 glGetAttribLocation 有效),则调用 glBindAttribLocation 没有任何意义,因为您已经知道答案。因此,在同一个程序中同时调用 getbind 永远没有任何意义永远。要么您正确地告诉 OpenGL 要使用哪个属性位置(因此以后没有理由询问),要么您想查询属性位置(因此不想指定它)。

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。