为什么我在屏幕上显示了一半的三角形?
Why am I getting half of the triangles displayed on the screen?
我按照 this tutorial 的要求在屏幕上画了 20 个三角形。但是,在该示例中,位置和颜色数据都存储在一个数组中,并作为单个 glBufferSubData 调用传递。我不确定我是应该始终遵循这种方法还是创建单独的数组来存储顶点属性并为每个属性调用 glBufferSubData
。我试图分别存储位置和颜色,但遇到了一个奇怪的问题。我没有在屏幕上绘制 20 个三角形,而是只有 10 个!
[我使用 glfw 而不是 Qt 来创建 window。]
方法一:
我定义的全局变量如下:
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 个红色三角形。
方法二:
在那之后,我尝试使用多个 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 个三角形。我猜这是由于为步幅和偏移量分配了不正确的值。但是,我想不通。
因此,我想先问问哪种方法比较好,比较安全。
其次,我怎样才能按照第二种方法得到想要的结果?
你有一个基本的误解。如果您已分离顶点坐标和分离颜色,则不会按图元分离属性。
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)));
我按照 this tutorial 的要求在屏幕上画了 20 个三角形。但是,在该示例中,位置和颜色数据都存储在一个数组中,并作为单个 glBufferSubData 调用传递。我不确定我是应该始终遵循这种方法还是创建单独的数组来存储顶点属性并为每个属性调用 glBufferSubData
。我试图分别存储位置和颜色,但遇到了一个奇怪的问题。我没有在屏幕上绘制 20 个三角形,而是只有 10 个!
[我使用 glfw 而不是 Qt 来创建 window。]
方法一:
我定义的全局变量如下:
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 个红色三角形。
方法二:
在那之后,我尝试使用多个 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 个三角形。我猜这是由于为步幅和偏移量分配了不正确的值。但是,我想不通。
因此,我想先问问哪种方法比较好,比较安全。
其次,我怎样才能按照第二种方法得到想要的结果?
你有一个基本的误解。如果您已分离顶点坐标和分离颜色,则不会按图元分离属性。
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)));