簡體   English   中英

在openGL的頂點着色器中設置屬性

[英]Setting attributes in the vertex shader in 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, 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,-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
        };
    
    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, 0);
    //unbind currently bound vbo
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    
    //and one for the colour data
    vboID = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBufferData(GL_ARRAY_BUFFER, colours, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 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,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);
        
        //enables the position attribute in the vertex shader
        glEnableVertexAttribArray(0);
        //enables the colour attribute in the vertex shader
        glEnableVertexAttribArray(1);
        
        glDrawArrays(GL_TRIANGLES, 0, 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, 0);

您告訴 OpenGL 位置為 0 的屬性(第一個glVertexAttribPointer調用中的第一個參數)應該從vboID讀取前三個浮點數。

glBindAttribLocation負責將某個屬性綁定到特定位置。 由於這必須在鏈接着色器之前完成,因此它們不會在您的代碼中執行任何操作。 更重要的是,因為這段代碼告訴屬性使用它已經擁有的位置:

int positionAttribute = glGetAttribLocation(shaderProgramID, "position");
glEnableVertexAttribArray(positionAttribute);
glBindAttribLocation(shaderProgramID, positionAttribute, "position");

您基本上是查詢位置,然后再次將位置分配給屬性。

兩個邊注:

  • 目前,您的代碼完全靠運氣。 你假設在glVertexAttribPointer(0, 3, GL_FLOAT, false, 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, 3, GL_FLOAT, false, 0, 0);

使成為:

glBindVertexArray(vaoID);
glDrawArrays(GL_TRIANGLES, 0, vertexPoints.length);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM