我目前正在研究光线投射和体素,这是一个很好的组合。Sebastian Scholz 的 Voxelrenderer 很好地实现了这一点,但也使用了 OpenGL。我想知道他的公式是如何工作的;如何将 OpenGL 与光线投射和体素一起使用?光线投射的想法不是为每个像素(或线条,即 Doom 中的线)投射光线,然后绘制结果吗?
2 回答
提到的光线投射器是体素渲染器,即一种可视化体积数据的方法,例如存储在 3D 纹理中的不透明度。Doom 的光线投射算法还有另一个目的:为屏幕上的每个像素找到地图的第一个平面并在那里绘制颜色。现代 GPU 的光栅化功能已经淘汰了光线投射器的这种使用。
实时可视化体积数据仍然是由特殊硬件完成的任务,通常在医学和测地线成像系统中找到。基本上,这些都是大量的 RAM(几十 GB),用于保存体积 RGBA 数据。然后对于屏幕上的每个像素,都会投射一条光线穿过体积,并将 RGBA 数据集成在该光线上。GPU Voxelrenderer 通过片段着色器执行相同的操作;伪代码:
vec4f prev_color;
for(i=0; i<STEPS; i++) {
p = ray_direction * i*STEP_DELTA;
voxel = texture3D(volumedata, p);
prev_color = combine(voxel, prev_color);
}
final_color = finalize(prev_color);
finalize
并combine
取决于数据的类型和您想要可视化的内容。例如,如果您想整合密度(如在 X 射线图像中),combine
将是求和操作并最终确定归一化。如果要可视化云,则需要在体素之间进行 alpha 混合。
体素空间中的光线投射不会使用像素,这将是低效的。
您已经有一个数组来说明哪些空间是空的,哪些空间是体素立方体。
因此,一个快速版本是跟踪一条线,该线检查该线方向上每个体素的空时间,直到它达到一个完整的体素。
这将需要从内存中进行几百次读取操作,并且每次读取操作需要 2-3 次射线矢量乘法。
读取十亿个体素的内存位置大约需要 1 秒,所以几百个会非常快并且总是在一帧内。
光线投射通常使用优化来检测空间中数学公式的小数位置,其中网格顶点基于它的边界框,然后是网格,在体素中,它只是逐步检查整数数组中的一条线,直到你找到一个非空白。