想到的第一种方法是首先使用简单的流压缩技术,从流中消除所有 0 值。由于您已经将数据采用了概念上的布尔格式,因此这相当于这些值的 scan/prefix-sum,以便之后每个数组元素存储其前面元素的数量。然后,您使用这些计算的偏移量将数组元素重新定位到新缓冲区(有效地连续存储所有 1 项),但不是仅复制(现在不相关的)偏移量,而是存储 3D 位置(可以从旧数组索引轻松计算) )。
然后,您拥有的是缓冲区中的 3D 点的简单列表,您可以使用 OpenGL 轻松绘制,无需任何副本到主机。如果您将最终的 1 点数(扫描的副产品)写入额外的缓冲区,您甚至可以使用 间接渲染,甚至不需要从主机,因此可以在没有任何回读的情况下绘制整个内容。
这些只是关于这可能如何工作的一些一般想法,如果您不知道我在说什么,请随时在 Google 上搜索各个关键字。如果您不知道如何使用 OpenGL 绘制任何东西,则需要先熟悉 OpenGL 或 Direct3D,然后才能从 GPU 绘制任何东西(CUDA 不会为您做这件事)。
编辑:嗯,有一种方法可以在 CUDA 中绘制整个东西。如果它真的只是一堆点并且你不需要任何复杂的光栅化,你也可以像 OpenGL 那样简单地将这些点从 3D 转换为 2D(OpenGL 也不是魔法,只是一堆 CUDA 内核和一些小的之间的专用硬件位)。因此,每个数据项都有一个线程,如果该项是1,您只需使用通常的模型视图和均匀 4D 坐标上的投影变换来变换点的 3D 坐标(由线程 ID 给出)(但不要忘记自己做透视分割和视口变换,因为现在没有固定功能的硬件可以为你做这件事)。并使用这个最终的 2D 坐标在输出图像中设置一个像素。
当然,这不会让您从 OpenGL 的其他复杂事物中获利(至少不是那么容易或直接),例如光栅化以及您能想到的其他效果。但它避免了流压缩步骤,您至少可以在已经存在的 OpenGL 渲染图像(包含可视化场景的其余部分,如坐标系或文本或其他)之上渲染这些点,甚至可以使用您自己的深度测试实现。
编辑: 避免流压缩的另一种方法是直接使用 OpenGL 绘制 0s 和 1s 的整个缓冲区,使用几何着色器进行坐标计算和0-删除。因此,您所做的是绘制所有点,使用整个整数数组来提供单个 int 属性并将其放入以下着色器。首先是一个简单的直通顶点着色器:
layout(location=0) in int flag; //single integer attribute
out int vFlag; //just passed through
void main()
{
vFlag = flag; //GS does the real work
}
几何着色器决定该点是否有效(值为1),如果是则为它发出一个实际点(如果不是什么都不做,即没有渲染点),从图元计算它的 3D 坐标ID,实际上是数组索引,因为我们只是在绘制点:
layout(points) in;
layout(points,max_vertices=1) out;
uniform mat4 modelViewProj;
in int vFlag[];
void main()
{
if(vFlag[0] == 1)
{
vec3 position = simpleIndexMagic(gl_PrimitiveID);
gl_Position = modelViewProj * vec4(position, 1.0);
EmitVertex();
}
}
片段着色器只是一个普通的着色器。当然,这些着色器可以按照您认为合适的方式进行定制。但是一般的方法很清楚,直接绘制整数值,将数组索引转换为仅在几何着色器中为1 的值的点。但是,与之前的流压缩相比,这在多大程度上会有所改进,需要评估。