glDrawArrays 不渲染整个点云

glDrawArrays does not render entire point cloud

我正在尝试渲染巨大的点云 (~150M),但 OpenGL 只渲染了其中的一部分 (~52M)。渲染较小的数据集(<40M)时一切正常。我正在使用单个 VBO。使用多个 VBO 时,会渲染点,但渲染速度非常慢,这是预期的。我的元素大小为 44 字节,GPU 有 3GB 可用内存。这对于近 7000 万个点应该足够了,但我可以使用多个 VBO 渲染多达 10000 万个点。 每个 VBO 是否有任何我不知道的 OpenGL 特定限制?

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, cloud.size() * sizeof(Point), cloud.data(), GL_STATIC_DRAW);
// lot of other code
glDrawArrays(GL_POINTS, 0, cloud.size());

看起来你的系统的某些部分使用 32 位无符号整数来存储缓冲区的大小,因此传递 148M*44bytes 溢出并转换为大约 54.9M50.4M 取决于您的兆字节是二进制还是十进制。我将从检查您的 OpenGL 绑定库开始,看看它声明的原型是否正确使用 64 位类型。如果是这样,那么 bug 一定是在 OpenGL 驱动程序中。

要将超过 4GB 的数据传输到缓冲区,您可以尝试使用其他可用函数之一:glBufferSubDataglBufferStorage,或者 memory-map 缓冲区 glMapBufferRange,这可能会解决 4GB 的限制。

要考虑的另一件事是使用一个 VAO,但将数据拆分到多个缓冲区。大概您的 Point 由不同的属性组成,例如位置、颜色等...您可以将它们中的每一个都放在一个单独的缓冲区中,并且仍然使用一个 VAO 和一个绘制调用。您还可以优化您使用的属性类型(例如,不要在可以使用短裤或字节的地方使用浮点数)和结构布局(检查字段之间是否没有不必要的填充)。

我认为内存不是问题,事实上我会说您的程序进行了太多绘图调用。您应该尝试使用 glDrawArraysInstanced() 。为此,您需要为顶点着色器中的每个实例提供新位置......也许这会解决您的问题:D。 很抱歉,如果我不能向您提供详细信息,我在 OpenGL 方面的技能有点迟钝,但我正计划尽快恢复 :D 。希望对您有所帮助。