16

我在正确指向顶点数组时遇到问题:

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

...

glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)16);

glDrawArrays(GL_TRIANGLES, 0, 3);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

我不明白 stride 和 offset 是如何工作的。glVertexAttribPointer()在我的情况下使用的正确方法是什么?

4

2 回答 2

53

由于 glVertexAttribPointer 经常会出问题,所以我在这里尝试进一步解释。

计算属性数组中第 i 个属性的起始位置的公式为:

startPos(i) = offset + i * stride(来自derhass的另一个答案

并在下图中解释: 紧密排列的数组


如果您需要代码示例,请继续阅读。

Formatting VBO Data中,我们知道我们可以以三种格式管理顶点数据。做一个绘制三角形的例子,顶点颜色和纹理颜色混合,这里是准备顶点属性数据的方法:


#way1 每个属性一个 VBO。

这种格式像:(xyzxyz...)(rgbrgb...)(stst....),我们可以让 sride = 0 和 offset = 0。

void prepareVertData_moreVBO(GLuint& VAOId, std::vector<GLuint>& VBOIdVec)
{
    // positon
    GLfloat vertPos[] = {
        -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f,
    };

    // color
    GLfloat vertColor[] = {
      1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
    };

    // texture coordinate
    GLfloat vertTextCoord[] = {
      0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f
    };
    
    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:每个属性都是顺序的,在单个 VBO 中批处理

这种格式就像:(xyzxyzxyz... rgbrgb... ststst...),我们可以让 stride=0 但应该指定偏移量。

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(GLfloat)
    glEnableVertexAttribArray(0);

    // specify color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(9 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    // specify texture coordinate
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(18 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    VBOIdVec.push_back(VBOId);
}

#way3:单个 VBO 中的交错属性

这种格式就像:(xyzrgbstxyzrgbst...),我们必须手动指定偏移量和步幅。

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(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    // specify color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
        8 * sizeof(GLfloat),(GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    // specify texture coordinate
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 
        8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    VBOIdVec.push_back(VBOId);
}

感谢derhass的回答。

于 2016-09-25T08:16:35.173 回答
21

步幅和偏移量以字节为单位。您正在使用位置和颜色均为 4 个浮点数的交错顶点数组。要从特定属性数组中的第 i 个元素到下一个元素,有 8 个浮点数的距离,因此步幅应为 8*sizeof(GLfloat)。偏移量是缓冲区中每个属性数组的第一个元素的字节位置,因此在您的示例中位置为 0,颜色为 4*sizeof(GLfloat)

于 2013-05-05T00:20:20.387 回答