OpenGL 3/4 glVertexAttribPointer stride and offset miscalculation

前端 未结 2 688
说谎
说谎 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<GLuint>& 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<GLuint>& 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<GLuint>& 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.

    0 讨论(0)
  • 2021-02-01 08:14

    Stride and offset are specified in bytes. You are using an interleaved vertex array with position and color both as 4 floats. To get from th i-th element in a particular attribute array to the next one, there is the distance of 8 floats, so stride should be 8*sizeof(GLfloat). The offset is the byte position of the first element of each attribute array in the buffer, so in your example for position it is 0, and for color, it is 4*sizeof(GLfloat)

    0 讨论(0)
提交回复
热议问题