【问题标题】:Why am I getting half of the triangles displayed on the screen?为什么我会在屏幕上显示一半的三角形?
【发布时间】:2020-02-22 14:27:29
【问题描述】:

我关注了this tutorial,并能够在屏幕上绘制 20 个三角形。但是,在该示例中,位置和颜色数据都存储在单个数组中,并作为单个 glBufferSubData 调用传递。我不确定我是否应该始终遵循这种方法或创建单独的数组来存储顶点属性并为每个属性调用glBufferSubData。我试图分别存储位置和颜色并遇到一个奇怪的问题。而不是在屏幕上绘制 20 个三角形,我只得到了 10 个!

[我使用 glfw 而不是 Qt 来创建窗口。]

方法一:

我定义的全局变量如下:

float dx = 0.1f;
unsigned int triangleCount = 0;

const unsigned int TRIANGLE_MAX_COUNT = 20;
const unsigned int TRIANGLE_VERTEX_COUNT = 3;
const unsigned int VERTEX_FLOAT_COUNT = 8;
const unsigned int TRIANGLE_BYTE_SIZE = TRIANGLE_VERTEX_COUNT * VERTEX_FLOAT_COUNT * sizeof(float);

我的三角形绘制函数定义为

void sendAnotherTriangle()
{
    if (triangleCount == TRIANGLE_MAX_COUNT)
        return;
    const float x = -1 + triangleCount * dx;

    glm::vec4 newTriangle[] = {
        glm::vec4(x, +0.0f, +0.0f,1.0f),
        glm::vec4(+1.0f, +0.0f, +0.0f,1.0f),
        glm::vec4(x + dx, +1.0f, +0.0f,1.0f),
        glm::vec4(+1.0f, +0.0f, +0.0f,1.0f),
        glm::vec4(x, +1.0f, +0.0f,1.0f),
        glm::vec4(+1.0f, +0.0f, +0.0f,1.0f)
    };

    glBufferSubData(GL_ARRAY_BUFFER, triangleCount * sizeof(newTriangle), sizeof(newTriangle), newTriangle);

    triangleCount++;
}

顶点缓冲区布局定义如下:

unsigned int vb;
glGenBuffers(1, &vb);
glBindBuffer(GL_ARRAY_BUFFER, vb);
glBufferData(GL_ARRAY_BUFFER, TRIANGLE_MAX_COUNT*TRIANGLE_BYTE_SIZE, NULL, GL_STATIC_DRAW);


glEnableVertexAttribArray(0);
glVertexAttribPointer(0, glm::vec4::length(), GL_FLOAT, GL_FALSE, 2 * sizeof(glm::vec4), (const void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, glm::vec4::length(), GL_FLOAT, GL_FALSE, 2 * sizeof(glm::vec4), (const void*)(sizeof(glm::vec4)));

根据我的理解,由于位置和颜色属性是交错的,因此这两个属性的步幅都是:2 * sizeof(glm::vec4),因为每个属性的类型都是 glm::vec4。由于位置数据从最开始开始,因此位置偏移量为 0,而颜色偏移量为 sizeof(glm::vec4),因为它从第一个顶点位置开始。

最后,绘图调用如下所示:

while (display.isRunning(window))
{
    glClear(GL_DEPTH_BUFFER_BIT);
    sendAnotherTriangle();
    glDrawArrays(GL_TRIANGLES, 0, triangleCount * TRIANGLE_VERTEX_COUNT);

    display.update();
}

这给了我想要的结果,即在屏幕上绘制了 20 个红色三角形。

方法2:

之后,我尝试使用多个 glBufferSubData 调用来做同样的事情。在这种方法中,修改后的三角形绘制函数为:

void sendAnotherTriangle()
{
    if (triangleCount == TRIANGLE_MAX_COUNT)
        return;
    const float x = -1 + triangleCount * dx;

    glm::vec4 newPositions[] = {
        glm::vec4(x, +0.0f, +0.0f, +1.0f),
        glm::vec4(x + dx, +1.0f, +0.0f, +1.0f),
        glm::vec4(x, +1.0f, +0.0f, +1.0f)
    };


    glm::vec4 newColors[] = {
        glm::vec4(+1.0f, +0.0f, +0.0f, +1.0f),
        glm::vec4(+1.0f, +0.0f, +0.0f, +1.0f),
        glm::vec4(+1.0f, +0.0f, +0.0f, +1.0f)
    };

    glBufferSubData(GL_ARRAY_BUFFER, triangleCount*(sizeof(newPositions) + sizeof(newColors)), sizeof(newPositions), newPositions);
    glBufferSubData(GL_ARRAY_BUFFER, triangleCount*(sizeof(newPositions) + sizeof(newColors)) + sizeof(newPositions), sizeof(newColors), newColors);
triangleCount++;
}

并且顶点缓冲布局修改如下:

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, glm::vec4::length(), GL_FLOAT, GL_FALSE, 0, (const void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, glm::vec4::length(), GL_FLOAT, GL_FALSE, 0, (const void*)(TRIANGLE_VERTEX_COUNT * sizeof(glm::vec4)));

由于位置和颜色数据是分开存储的,我的理解是它们是紧密打包的,因此它们的步幅为 0,并且由于颜色数据在位置数据之后开始,所以颜色偏移量是 TRIANGLE_VERTEX_COUNT * sizeof(glm:: vec4).

使用这个新设置,我希望在屏幕上绘制 20 个三角形。但是,我只在屏幕上绘制了 10 个三角形。我猜这是由于为步幅和偏移量分配了不正确的值。但是,我想不通。

因此,我想先问一下哪种方法更好,更安全。

其次,按照第二种方法,我怎样才能得到想要的结果?

【问题讨论】:

    标签: c++ opengl glfw glm-math


    【解决方案1】:

    你有一个基本的误解。如果您已分离顶点坐标和分离颜色,则不会按图元分离属性。
    20 个三角形的所有顶点坐标必须在缓冲区的连续区域中,并且 20 个三角形的所有颜色必须在缓冲区的连续区域中。

    您必须将三角形的 60 (3*20) 个顶点存储在缓冲区中,然后存储 60 种颜色。颜色的偏移量是20*3*sizeof(glm::vec4)

    glBufferSubData(GL_ARRAY_BUFFER, 
                    triangleCount*sizeof(newPositions),
                    sizeof(newPositions), newPositions);
    glBufferSubData(GL_ARRAY_BUFFER, 
                    triangleCount*sizeof(newPositions) + 20*3*sizeof(glm::vec4), 
                    sizeof(newColors), newColors);
    
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, glm::vec4::length(), GL_FLOAT, GL_FALSE,
                          0, (const void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, glm::vec4::length(), GL_FLOAT, GL_FALSE, 
                          0, (const void*)(20*3*sizeof(glm::vec4)));
    

    【讨论】:

    • 我真的对布局感到困惑。谢谢你的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    相关资源
    最近更新 更多