GPU-Pragramming Ray Casting

光线投射算法是从视点到“图像序列最表面的外层像素”引射线穿越体数据。

在光照计算中,我们采用吸收和发射模型(Absorption plus emission)。体数据中的体素本身发射光线, 并且可以吸收光线, 但不对光线进行反射和透射。为了增强真实感,也可以加上阴影(包括自阴影)计算。 

1. 几点实现疑惑

光线如何穿越体纹理

首先要明确一点,我们需要一个空间体模型(这通常是一个规则的立方体或圆柱体,以下我用的是一个立方体),这个立方体与体纹理相互结合才能进行体渲染。换句话说,立方体是一个载体,体纹理通过纹理坐标(三维)与模型相互对应,然后由视点向模型上的点引射线,该射线穿越立方体等价于射线穿越了体纹理。

这个图显示了立方体纹理坐标分布,以上的立方体有个更通用的名称:颜色立方体,在我们的实现中有大用,而且是很巧妙的使用,见下面就知。

 

关于三维纹理给出解释:可以类比二维纹理来理解,2d texture指的是纹理只描述了空间的面数据, 而3d texture则是描述了空间中的三维数据。3d texture另一个较为学术化的名称是:volume texture。三维纹理通过三维纹理坐标进行访问。

这三个体纹理数据的描述分别是: 256 x 320 x 128 \0.66, 0.66, 0.66; 512 x 512 x 174\0.8398, 0.8398, 3.2;512 x 512 x 463\0.625, 0.625, 1.0

 

透明度、颜色合成

透明度本质上代表着光穿透物体的能力, 光穿透一个物体会导致波长比例的变化,如果穿越多个物体,则这种变化是累加的。所以,透明物体的渲染,本质上是将透明物体的颜色和其后物体的颜色进行混合,这被称为alpha混合技术。

在光线投射算法中,射线穿越体纹理的同时也就是透明度的排序过程。所以这里存在一个合成的顺序问题。可以将射线穿越纹理的过程作为采样合成过程,这是从前面到背面进行排序,也可以反过来从背面到前面排序,毫无疑问这两种方式得到的效果是不太一样的。我们采用才前到后:

稍做解释,Ci和Ai 分别是在体纹理上采样当前点所得到的颜色值和不透明度,其实也就是体素中蕴含的数据;CΔ和AΔ表示累加的颜色值和不透明度。注意,很多体纹理其实并没有包含透明度,所以有时是自己定义一个初始的透明度,然后进行累加。

 

沿射线进行采样

首先需要一个确定了顶点纹理坐标的三维立方体,光线穿越立方体的过程,就是穿越体纹理的过程,在整个穿越过程中,计算采样体纹理坐标,并进行体纹理采样,这个采样过程直到光线投出立方体或者累加的透明度为1时结束。

如图所示,假定光线从F点投射到立方体中,并从 L 点投出,在立方体中穿越的距离为 m。当光线从F点投射到立方体中,穿越距离为 n(n<m)时进行采样,则存在公式: 

其中 Tstart 表示立方体表面被投射点的体纹理坐标; d 表示投射方向; delta表示采样间隔,随着 n的增加而递增;t为求得的采样纹理坐标。通过求得的采样纹理坐标就可以在体纹理上查询体素数据。直到n>m,或者透明度累加超过 1,一条射线的采样过程才结束。

那么紧接着下一个难题,如何知道光线投射出了立方体?这个问题等价于计算光线在立方体中穿越的距离m。

 

如何判断光线投射出立方体

 还记得上面那个颜色立方体吗?解释下上面两个立方体的由来。我们从前面向后看过去,剔除掉前面所有的遮挡物,提取最后表面就得到了右面的图,这个可以用OpenGL很容易的实现。注意这个是颜色立方体,颜色值代表坐标,那么我们把右面这副图当作一个纹理,进行纹理采样得到颜色值,也就是坐标值,也就是光线投射出去的坐标值,记为exit_position。前表面的点即为光线入射进体立方体点记为start_position。那么想一下,

float3 dir = exit_position - start_position

float len = length(dir.xyz); //这个就是我们费尽千辛万苦求得的最大穿越距离

float3 norm_dir = normalize(dir);//同时也可以得到入射光线方向

 

float2 texc = ((IN.Pos.xy / IN.Pos.w) + 1) / 2; 

float4 exit_position  = tex2D(backface_buffer, texc); 

 

2. 程序实现

首先几点涉及OpenGL的知识点:片段编程,帧缓冲区,纹理,光照

1)OpenGL框架程序,初始化OpenGL扩展、CG环境,

读取裸数据到三维纹理中,分别加载一维不透明度传递函数、颜色传递函数到两个一维纹理中,这三个纹理都会在片段程序中用到

GLuint volume_texture; // the volume texture
GLuint alph_transfer;
GLuint color_texture;

2)

 

 

 

 

 

 

 

 

 

posted @ 2011-10-31 08:41  wangwh0910  阅读(385)  评论(0编辑  收藏  举报