• 沒有找到結果。

4.1 One Pass Rendering Algorithm

我們發現網路上相關 Shader 上的光線追蹤(Shader Based Ray Tracing)都是 針對定義球去做各種效果,而比較有在討論關於物體的成像,主要是參考 Timothy 所提的演算法去做改善,但在嘗試過程中,我們發現他所使用的方法是屬於特殊 硬體限定的方法,對於一般硬體皆無法使用,再者演算法中所採用的多次記憶體 讀取與寫入,在使用效率上,也並非理想的方法,但將場景存入 Texture Memory 的想法,的確可以解決場景資訊在 Fragment Shader 無法讀取的問題,所以我們保 留這部分想法,提出一個新的一次執行方式,這次不再將每個步驟分開至不同的 Fragment Shader,減少讀寫 Texture Memory 的時間,另外我們所比對的 Shader,

是採用新版 OpenGL 3.3 之後的 Shader 的光柵化(Shader Based Rasterization)。而 演算法的流程可以由圖 4.1 所示。

圖 4.1:One Pass Rendering Algorithm

4.1.1 環境設定以及資料轉變

在主程式階段,我們必須設定相關的環境參數以及場景資料的存取。主要分

13

為三個步驟要執行。第一步,我們必須決定一個四邊形當作我們的螢幕屏,而之 所以要這麼做的原因,下一節會另外說明。其次,針對基本的環境變數,如眼睛、

光源利用 uniform 變數存入,再來針對新版的 OpenGL 3.3 之後的改變,我們必須 先自行計算投影矩陣以及視角矩陣,原因乃過去所用的 glMatrixMode 以及 glLookAt 相關指令已經無法使用。

圖 4.2:簡化版場景讀取架構圖

最後也是最重要的部分,是我們將場景的面(faces)、頂點(vertices)、顏色

(colors)等資訊讀至一條陣列,再分別將它們各自存放在不同的 Texture Memory 中,而儲存的形態,我們也針對不同的狀況做一些測試。對於存放的記憶體維度,

在一萬片以內的場景,建議存放在一維材質記憶體,原因是存取速度較快,但缺 點是容量較小;而存取二維陣列之所以比較慢的原因是因為我們必須多幾段指令 判斷 Texture Memory 的所在的座標,但其容量倍率為一維寬度的平方。但是大於 萬片三角形以上的場景就建議使用二維材質記憶體。而所有材質的形態,我們建 議統一浮點數的形態,而不要有些是整數、有些是浮點數,是為了讓記憶體的資 料一致性提高。最後我們建議讓所有場景的值事先做正規化,最好使用 16 bit 的 記憶體長度,而盡量不要讓資料用到 32 bit 對於整體的速度又會有極大的影響。

4.1.2 設定視窗螢幕

與光柵化不同的地方,由於我們在 Fragment Shader 必須讀取到各像素的位置 用以與眼睛位置形成光線向量,所以在 Vertex Shader 的步驟中,我們從主程式所 傳入的我們所要畫的視窗四頂點資訊,與我們的投影矩陣和視角矩陣做相乘,透

14

過光柵化,內插計算出各像素的位置,再將當成 Fragment Shader 的輸入資料,用 以生成光線。

4.1.3 產生光線

我們透過主程式利用 uniform 傳入眼睛位置,並且與 Vertex Shader 所傳入的 像素位置形成一個向量,而透過 GPU 平行處理,即可生成與像素個數等量的光 線,在各自的 Fragment Shader 執行緒裡做光線追蹤的動作。

4.1.4 結構拜訪

我們在結構拜訪的這個步驟,並未加入如 Kd-tree 或者 Grid 等加速結構,我 們只單純利用循序的方式一一檢查各個三角片,找出最近的拜訪三角片。

4.1.5 計算相交點

利用 Möller–Trumbore ray-triangle intersection 演算法[MOL 05](詳細可參考附 錄 A)計算打到哪片三角形,並且回傳距離值,取最近的三角片當作其相交點,利 用該點去決定要做成像或者持續產生新的光線。這裡需要注意,我們獲取面以及 頂點的資訊方式是利用查 Texture Memory 的方式,我們必須透過上列圖 4.2 的結 構來抓取資訊,而這裡我們使用的是 texelftech 這個指令,原因是因為只有這個 指令可以正確地抓取精確的浮點數值,另外由於我們為了讓我們的 Texture Memory 一致性較高,我們面的存放型態亦是浮點數,這裡我們就必須轉換資料 型態,而這裡我們無法使用 C 語言的常用的轉換方式,我們必須在查表的時候就 強迫讀進去的是整數型態。轉換方式。有兩種方式:第一個用「ivec3」,即強迫 所宣告變數直接轉換成整數型態的向量;第二個方法,如「(int(faceNo.x))」,利 用括號將其轉換成整數型態。

15

4.1.6 Rendering

利用 Phong lighting[PHO 75]作為基底的成像方法。利用反射光及視角到頂點 的向量作內積,乘上係數,實作出鏡面反射光的效果。如圖 4.3,基本的 Phong reflection model 包含粗糙表面的散射光(diffuse)、光滑表面的鏡面反射光

(specular),並加上了場景當中所收集到少量的環境光(ambient)。

圖 4.3:Phong reflection model 示意圖

散射光的密集度與光源的距離相關,specular 則因視角及光源角度影響,環境光源則為常數。圖 表來源可參見圖片來源(3)。

4.2 Hybrid Rendering Algorithm

在 Shader 中,我們常使用 Image Space 的方法事先去產生一些圖,或者事先 將一些材質先行寫入 Texture Memory,等到顏色計算時,才利用查表方式去得到 相關資訊,用以快速計算最終近似顏色值。其實這個方式也可以混用在我們的 One Pass Rendering Algorithm。經由第一輪的光線追蹤後,我們可以得到精確的 intersection 點,結合事先存放在 Texture Memory 的資訊,我們也可以做近似計算 及查表,這樣的動作可以用來減少追蹤光線的次數,理論上可以加快一些速度。

修改後的演算法如圖 4.4 所示。而這演算法主要用在需要兩輪以上光線追蹤的效 果上,其第一輪與 One Pass Rendering Algorithm 其實是做一樣的事。

16

圖 4.4:Hybrid Rendering Method

我們盡可能只追蹤一次光線,而額外的效果,利用計算出材質座標來查詢 Texture Memory 用以達到同樣效果。不過有一個困難性。以 Cube Mapping 為例,

我們在查詢反射材質時,所使用的指令除了算出的反射光線,還需要結合 Vertex Shader 所傳入的近似點,找出反射的材質資訊。然而我們並無法直接使用這種查 表指令,因為我們使用的點並非這種 intersection 點,我們所得的近似點現在是該 像素的位置,為了克服這個問題,我們可以利用轉換座標方式,利用我們所算的 intersection 點,直接計算對應後的材質坐標位置,利用實際輸入座標查表的方式 取代特殊算出 Cube Mapping 的指令,如表 4.1。這種方法的核心價值是以查表取 代產生新光線,可以節省至少一輪追蹤以上的速度。

1

vec3 ReflectRay = reflect(IncidentRay, normal);

2

vec3 TexelCoord = intersectionPos + EPS* ReflectedRay;

3 Color += texture(CubeMap, TexelCoord);

表 4.1:Cube Mapping 查表 Pseudo Code

17

相關文件