OpenGL 3/4 glVertexAttribPointer stride and offset miscalculation

前端 未结 2 690
说谎
说谎 2021-02-01 07:55

I am having a problem getting my vertex array pointed to properly:

const float vertices[] = {
/* position */ 0.75f, 0.75f, 0.0f, 1.0f, /* color */ 1         


        
2条回答
  •  无人及你
    2021-02-01 08:12

    Since glVertexAttribPointer often make troubles, I try to further explain it here.

    The formula to calculate the start pos of the i-th attribute in attributes array is :

    startPos(i) = offset + i * stride (From derhass' another answer)

    And explained in the graph below :


    If you need code example, continue reading.

    From Formatting VBO Data, we know we can manage our vertex data in three format. Make a example of drawing a triangle , with vert color and texture color mixed, here is the way to prepare vert attribute data:


    #way1 Each attribute a VBO.

    this format like : (xyzxyz...)(rgbrgb...)(stst....), and we can let both sride = 0 and offset = 0.

    void prepareVertData_moreVBO(GLuint& VAOId, std::vector& VBOIdVec)
    {
        GLfloat vertPos[] = {
            -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f,  // positon
        };
        GLfloat vertColor[] = {
          1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,   // color
        };
       GLfloat vertTextCoord[] = {
          0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f     // texture coordinate
       };
    
        GLuint VBOId[3];
    
        glGenVertexArrays(1, &VAOId);
        glBindVertexArray(VAOId);
        glGenBuffers(3, VBOId);
        // specify position attribute
        glBindBuffer(GL_ARRAY_BUFFER, VBOId[0]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertPos), vertPos, GL_STATIC_DRAW);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
        glEnableVertexAttribArray(0);
        // specify color attribute
        glBindBuffer(GL_ARRAY_BUFFER, VBOId[1]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertColor), vertColor, GL_STATIC_DRAW);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
        glEnableVertexAttribArray(1);
        // specify texture coordinate attribute
        glBindBuffer(GL_ARRAY_BUFFER, VBOId[2]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertTextCoord), vertTextCoord, GL_STATIC_DRAW);
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, NULL);
        glEnableVertexAttribArray(2);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    
        VBOIdVec.push_back(VBOId[0]);
        VBOIdVec.push_back(VBOId[1]);
        VBOIdVec.push_back(VBOId[2]);
    }
    

    #way2: Each attribute is sequential, batched in a single VBO.

    this format is like: (xyzxyzxyz... rgbrgb... ststst...), we can let stride=0 but offset should be specified.

    void prepareVertData_seqBatchVBO(GLuint& VAOId, std::vector& VBOIdVec)
    {
    
        GLfloat vertices[] = {
         -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f,  // position
         1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,   // color
         0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f     // texture coordinate
        };
    
        GLuint VBOId;
        glGenVertexArrays(1, &VAOId);
        glBindVertexArray(VAOId);
    
        glGenBuffers(1, &VBOId);
        glBindBuffer(GL_ARRAY_BUFFER, VBOId);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        // specifiy position attribute
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // stride can aslo be 3 * sizeof(GL_FLOAT)
        glEnableVertexAttribArray(0);
        // specify color attribute
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(9 * sizeof(GL_FLOAT)));
        glEnableVertexAttribArray(1);
        // specify texture coordinate
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(18 * sizeof(GL_FLOAT)));
        glEnableVertexAttribArray(2);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    
        VBOIdVec.push_back(VBOId);
    }
    

    #way3: Interleaved attribute in a single VBO

    this format is like: (xyzrgbstxyzrgbst...),we have to manually specify the offset and stride .

    void prepareVertData_interleavedBatchVBO(GLuint& VAOId, std::vector& VBOIdVec)
    {
        // interleaved data
        GLfloat vertices[] = {
           -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,  // 0
           0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,  // 1
           0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,  // 2
        };
    
        GLuint VBOId;
        glGenVertexArrays(1, &VAOId);
        glBindVertexArray(VAOId);
        glGenBuffers(1, &VBOId);
        glBindBuffer(GL_ARRAY_BUFFER, VBOId);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        // specify position attribute
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,8 * sizeof(GL_FLOAT), (GLvoid*)0);
        glEnableVertexAttribArray(0);
        // specify color attribute
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
            8 * sizeof(GL_FLOAT),(GLvoid*)(3 * sizeof(GL_FLOAT)));
        glEnableVertexAttribArray(1);
        // specify texture coordinate
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 
            8 * sizeof(GL_FLOAT), (GLvoid*)(6 * sizeof(GL_FLOAT)));
        glEnableVertexAttribArray(2);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    
        VBOIdVec.push_back(VBOId);
    }
    

    And thanks for derhass's answer.

提交回复
热议问题