3

我正在尝试可视化非常大的点云(7 亿点),并且在glDrawArrays调用调试器时抛出访问冲突写入位置异常。我正在使用相同的代码来渲染更小的云(1 亿)并且一切正常。我还有足够的 RAM 内存 (32GB) 来存储数据。

要存储点云,我正在使用std::vector<Point3D<float>>Point3D 所在的位置

template <class T>
union Point3D
{
    T data[3];
        struct{
            T x;
            T y;
            T z;
        };
}

顶点数组和缓冲区初始化:

glBindVertexArray(pxCloudHeader.uiVBA);

glBindBuffer(GL_ARRAY_BUFFER, pxCloudHeader.xVBOs.uiVBO_XYZ);
glBufferData(GL_ARRAY_BUFFER, pxCloudHeader.iPointsCount * sizeof(GLfloat) * 3, &p3DfXYZ->data[0], GL_STREAM_DRAW);
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

glBindVertexArray(0);

绘图调用:

glBindVertexArray(pxCloudHeader.uiVBA);
glDrawArrays(GL_POINTS, 0, pxCloudHeader.iPointsCount); // here exception is thrown
glBindVertexArray(0);

我还检查了是否抛出了 OpenGL 错误,但我没有发现任何错误。

4

2 回答 2

0

您可以以较小的批次绘制数据。虽然缓冲区大小没有预定义的上限,但在单个缓冲区中存储 8 GB 的数据是很多的。我并不很惊讶会发生什么事情。

我可能会先在每个缓冲区中存储 100 万个或最多几百万个点。然后使用具有此固定大小的缓冲区池,足以容纳所有数据点。

这甚至可能对您的性能有益,因为它允许您在将所有数据复制到缓冲区之前开始提交绘制调用。这将使您在 CPU 和 GPU 工作之间有更好的重叠。

随着您正在移动的数据量,您可能还想考虑使用glMapBuffer()/glUnmapBuffer()而不是glBufferData(). 这通常避免了对数据的一次复制操作。

于 2014-12-21T00:54:22.030 回答
0

我怀疑你的问题是由于GLsizeiptr.

这是用于表示 OpenGL 缓冲区对象大小的数据类型,通常为 32 位。

700 million vertices * 4-bytes per-component * 3-components = 8,400,000,000 bytes

如果 GL 使用 32 位指针,则尝试在 GL 中分配这么多字节存在一个严重的问题:

8400000000 & 0xFFFFFFFF = 4,105,032,704 (half as many bytes as you actually need)

如果sizeof (GLsizeiptr)您的实现是4,那么您将别无选择,只能拆分您的阵列。32 位GLsizeiptr只允许您存储 4 个连续的 GiB 内存,但如果您使用 3 个单组件数组,则可以解决此问题。使用顶点着色器,您可以重建这 3 个单独的(足够小)数组,如下所示:

#version 330

layout (location = 0) in float x; // Vertex Attrib Ptr. 0
layout (location = 1) in float y; // Vertex Attrib Ptr. 1
layout (location = 2) in float z; // Vertex Attrib Ptr. 2

void main (void)
{
  gl_Position = vec4 (x,y,z,1.0);
}

性能会很糟糕,但这是以最少的努力解决问题的一种方法。


顺便说一句,这里的系统内存量(32 GiB)不是你最大的问题。您应该考虑 GPU 上的 VRAM 数量,因为理想情况下,缓冲区对象被设计为存储在 GPU 上。缓冲区对象的任何太大而无法存储在 GPU 内存中的部分在使用时都必须通过 PCIe(这些天)总线传输。

于 2014-12-21T18:22:45.457 回答