为什么我会在屏幕上显示一半的三角形?

问题描述 投票:0回答:1

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

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

方法1:

我将全局变量定义如下:

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个回答
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)));
© www.soinside.com 2019 - 2024. All rights reserved.