【问题标题】:OpenGL 3/4 glVertexAttribPointer stride and offset miscalculationOpenGL 3/4 glVertexAttribPointer 步幅和偏移量计算错误
【发布时间】:2013-05-04 23:48:10
【问题描述】:

我无法正确指向我的顶点数组:

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() 的正确方法是什么?

【问题讨论】:

    标签: opengl attributes offset vertex stride


    【解决方案1】:

    由于glVertexAttribPointer经常出问题,这里我尝试进一步说明。

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

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

    并在下图中解释:


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

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


    #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 的回答。

    【讨论】:

    • 哇,在一天的大部分时间里,我一直在努力思考这 3 种方法的差异(主要是交错与其他方法,以及如何正确使用偏移量),然后我看到了这一点,并排,一切都变得清晰起来。谢谢。 ;) 任何想法通常更快?
    • @JamesWilkins 根据我看过的推荐(比如苹果的IOS推荐,交错数据的版本更快。
    • 我想这是有道理的,因为系统可以轻松地将值“blit”到一个结构中,而不是从单独的数组中一个一个地复制。
    • sizeof(GL_FLOAT) 看起来不正确,并且是意外工作。应该是sizeof(GLfloat)
    【解决方案2】:

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

    【讨论】:

    • 我的两个 glVertexAttribPointer 步幅和偏移值应该是多少?
    • @user2350858:正如我已经在答案中写的那样:步幅是 8*sizeof(GLfloat) (通常是 32),位置偏移 0 和颜色偏移 4*sizeof(GLfloat) (你已经做)
    • 偏移量的类型必须是const void*,你将如何实现呢?我考虑过nullptr + offset,但类型错误。我试过(void*)0 + offset,但这对我来说还行不通(不知道还有什么问题。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-13
    • 1970-01-01
    • 2021-01-29
    • 1970-01-01
    相关资源
    最近更新 更多