體繪製(Volume Rendering)概述之4:光線投射算法(Ray Casting)實現流程和代碼(基於CPU的實現

摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文 名“GPU編程與CG語言之陽春白雪下里巴人”

算法流程

在這裏插入圖片描述

圖 47 展示了使用光線投射算法進行體繪製的實現流程。

首先要渲染出正向面深度圖和背向面深度圖,這是爲了計算射線穿越的最大距離,做爲循環採樣控制的結束依據;然後在頂點着色程序中計算頂點位置和射線方向,射線方向由視線方向和點的世界座標決定,其實射線方向也可以放在片段着色程序中進行計算。然後到了最關鍵的地方,就是循環紋理採樣、合成。

每一次循環都要計算新的採樣紋理座標和採樣距離,然後進行顏色合成和透明度累加,如果採樣距離超過了最大穿越距離,或者透明度累加到 1 ,則循環結束。將合成得到的顏色值輸出即可。

圖 48 給出了使用光線投射算法進行體繪製的效果圖:

在這裏插入圖片描述

15.4 光線投射算法實現
本節給出光線投射算法的着色程序實現代碼。依然是分爲三個部分:結構體、頂點着色程序和片段着色程序。

代碼 22 光線投射算法結構體

struct VertexIn

{

float4 position : POSITION;

float4 texCoord: TEXCOORD;

};

struct VertexScreen

{

float4 position : POSITION;

float4 worldPos : TEXCOORD0;

float4 projPos : TEXCOORD1;

float4 texCoord : TEXCOORD2;

};

代碼 23 光線投射算法頂點着色程序

VertexScreen main_v(VertexIn posIn,

                    uniform float4x4 world,

              uniform float4x4 worldViewProj,

              uniform float4x4 texViewProj)

{

VertexScreen posOut;



posOut.position = mul(worldViewProj, posIn.position);

posOut.worldPos = mul(world,posIn.position);

posOut.projPos = mul(texViewProj, posOut.worldPos); 

posOut.texCoord = posIn.texCoord;



return posOut;

}

代碼 24 光線投射算法片段着色程序

void main_f(VertexScreen posIn,

       uniform float3 eyePosition,

       uniform sampler3D volumeTex: register(s0),

       uniform sampler2D frontDepthTex: register(s1) ,

       uniform sampler2D backDepthTex: register(s2) ,

    out float4 result        : COLOR)

{

   // 根據視點和當前頂點世界座標計算方向

   float3 dir = posIn.worldPos.xyz-eyePosition;

   dir = normalize(dir);

   float3 deltaDir = float3(0.0, 0.0, 0.0);

  

   // 獲取當前頂點的三維紋理座標

   float3 tex = posIn.texCoord.xyz;

   float2 uvDelta;

   uvDelta.x = 0.0;//ddx( tex ).x;

   uvDelta.y = 0.0;//ddy( tex ).y;

  

   // 取出深度間隔值 , 並設置採樣間隔

   float2 uv= posIn.projPos.xy/posIn.projPos.w;

   float frontDis = tex2D(frontDepthTex,uv).x;

   float backDis = tex2D(backDepthTex,uv).x;

   float len = backDis-frontDis;

  

   // 初始化顏色值、採樣值、透明度

float3 norm_dir = normalize(dir);

float stepsize = 0.01;

float delta = stepsize;

float3 delta_dir = norm_dir * delta;

float delta_dir_len = length(delta_dir);

float3 vec = posIn.texCoord.xyz;

float4 col_acc = float4(0,0,0,0);

float alpha_acc = 0;

float length_acc = 0;

float4 color_sample;

float alpha_sample;

for(int i = 0; i < 800; i++){

   color_sample = tex3D(volumeTex,vec);

  alpha_sample = color_sample.a * stepsize;

  col_acc   += (1.0 - alpha_acc) * color_sample * alpha_sample * 3;

  alpha_acc += alpha_sample;

  vec += delta_dir;

  length_acc += delta_dir_len;

  if(length_acc >= len || alpha_acc > 1.0) break; // 採樣循環控制條件

}

   result.xyz = col_acc.xyz*2.0+float3(0.2,0.2,0.2);

   result.w = col_acc.w;  

}

15.5 本章小結
本書的第14 、15 章闡述了體繪製中光線投射算法的基本原理和實現流程。實際上,在此基礎上可以對光線投射算法加以擴展,例如將光線投射算法和陰影繪製算法相結合,可以渲染出真實感更強的圖像。

此外,有些體數據是中間是空的,在射線方向上進行採樣時需要跳過空區域,這其中也需要額外的算法處理,在英文中稱爲“Object-Order Empty Space Skipping ”。

目前我所發現關於體繪製以及光線投射算法最好的教材是Markus Hadwiger 等人所寫的“Advanced Illumination Techniques for GPU-Based Volume Raycasting ”。此書發表在SIGGRAPH ASIA2008 上,是目前所能找到最新也是非常權威的教材,共166 頁。英文閱讀能力比較好的同學可以嘗試着看一下。

本章已經是此書的最後一章,最後希望中國的計算機科學可以真正上升到科學研究的層次,而不是一直在混沌中熱衷做泥瓦匠的工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章