Cuda + OpenGL:如何显示数组的元素

时间:2013-04-04 08:11:26

标签: arrays opengl cuda

让我们说一个数据数组

int data[256][256][256];

包含0和1的值。 此数据将被复制到设备内存(展平)并由cuda内核处理,将一些值从0更改为1,反之亦然。 如何以这样的方式显示数据

if data[x]][y][z]==1
{
//a point of size 1 will be displayed in (x,y,z) coords
}

无需将该阵列复制回主机内存。我想直接从设备(gpu)内存中执行此操作。 一个简单的例子非常有用。

1 个答案:

答案 0 :(得分:2)

首先想到的方法是首先使用简单的流压缩技术,从流中消除所有0值。由于您已经以概念布尔格式获取数据,因此这相当于这些值的 scan / prefix-sum ,因此之后每个数组元素都存储其前面元素的数量。然后使用这些计算的偏移量将数组元素重新定位到一个新的缓冲区(有效地连续存储所有1个项目),但不是仅仅复制(现在不相关的)偏移量,而是存储3D位置(可以从旧的数组索引中轻松计算) )。

您拥有的是缓冲区中的3D点的简单列表,您可以使用OpenGL轻松绘制,而无需复制到主机。如果将最终的1点(扫描的副产品)写入附加缓冲区,您甚至可以使用间接渲染,甚至不需要查询来自的点数。主持人因此可以在没有任何回读的情况下绘制整个内容。

这些只是关于这可能如何工作的一些一般性想法,如果你不知道我在说什么,请随时谷歌搜索个别关键词。如果你不知道如何使用OpenGL绘制任何东西,你需要首先熟悉OpenGL或Direct3D,然后才能从GPU中绘制任何内容(CUDA不会为你做任何事情)。


编辑:嗯,有一种方法可以在CUDA中绘制这一切。如果它真的只是一堆点并且你不需要任何复杂的光栅化,你可以简单地将这些点从3D转换为2D,就像OpenGL一样(OpenGL也不是魔术,只是一堆CUDA内核有一些小的两者之间的专用硬件比特)。因此,每个数据项都有一个线程,如果此项为1,您只需使用通常的模型视图和均匀4D坐标上的投影变换来变换点的3D坐标(由线程ID给出)(但不要忘记自己进行透视分割和视口转换,因为现在没有固定功能的硬件来为你做这件事。并使用此最终2D坐标仅在输出图像中设置单个像素。

当然,这不会让你从OpenGL的其他复杂的东西中获利(不是那么容易或直接),比如光栅化和你能想到的效果。但是它避免了流压缩步骤,你至少可以在已经存在的OpenGL渲染图像(包含你的可视化场景的其余部分,如坐标系或文本或其他)之上渲染这些点,甚至可以使用你自己的深度测试实施。


编辑:避免流压缩的另一种方法是使用几何着色器直接用OpenGL绘制0 s和1 s的整个缓冲区坐标计算和0 - 删除。所以你要做的是绘制所有点,使用整个整数数组来提供单个int属性并将其放入以下着色器中。首先是一个简单的pass-thru顶点着色器:

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的值的点。但是,与前一个流相比,在多大程度上改进了压缩需要进行评估。