第三章 系統實作
3.2 K-D Tree
傳統的光線追蹤演算法中,由於必須計算大量的光線-物體交點測試,若是場 景複雜且由大量的片三角形組成,將會花費絕大部分的計算成本於交點測試上,
嚴重影響其效能,畫出一張畫面可能高達數小時之久。因此,至今已發展了許多
10
將場景以空間切割法儲存於樹狀結構中的加速方法,藉由加速結構大幅度地節省 檢查次數,由於本研究中渲染的場景屬於靜態場景,因此我們針對場景的加速結 構採用了 K-D tree 加速結構。
K-D tree 的演算法可分為兩個步驟探討:建構與走訪。在 GPGPU 上 Real-Time K-D Tree Construction [Zhou 08]已提出於 CUDA 平台上即時地建置 k-d tree 的方法,K-D Tree Acceleration Structure [Foley 05]為了節省頻繁的記憶體使用所 造成的延遲,提出了 k-d restart、k-d backtrack 方法,透過重複走訪大幅度地節省 了記憶體存取次數,Interactive K-D Tree GPU Ray Tracer [Horn 07]使用較不占用 記憶體的 short stack 方法,除了節省記憶體頻寬之外,也省下大量重複檢查的時 間。在 Daniel 等人的實作結果中,可達到每秒鐘追蹤 10-90 百萬條主要光線 (primary rays),在當時的背景下是非常高的資料計算量。
3.2.1 Construction Method
在建構 k-d tree 的部分,我們的實作中使用物件的中心點(object medium)作為 空間描述的分類依據,並以座標軸對稱(Axis-Aligned Bounding Box)的格式切開場 景,以由上而下(top-down)的方式,將場景由三個座標軸依序並遞回地切割,建立 一個有深度限制的樹狀資料結構。
當主機端將 k-d tree 建置完成以後,我們會依循前序(pre-order)搜尋法將樹狀 結構存入一維陣列,此做法是為了避免在裝置端執行時使用指標結構(pointer)會
11
3.2.2 Traversal Function
走訪 k-d tree 時,由根(root)出發,每當走訪到節點(node)時,我們會判斷是否 符 合 繼 續 走 訪 的 條 件 , 並 且 由 光 線 的 方 向 向 量 以 及 Axis Aligned Bounding Box(AABB)的測試結果決定下一次走訪節點的先後順序。而當走到葉節點(leaf node)時,表示已經符合最小的 AABB 切割區塊,我們會對其中包含的所有物體 進行交點測試。
而為了進一步驗證同個 OpenCL 程式在不同裝置架構底下的效能,我們則是 使用標準的方法-利用固定大小的堆疊(stack),記錄等待走訪的節點,藉由這種 方法,我們預期在全域記憶體存取頻率較高的時候,會更加吃重裝置的記憶體頻 寬(memory bandwidth)效能。
圖 3:3000 顆光子可視化之後的畫面效果,採用光線追蹤渲染。
12
3.3 Photon Emission
光子映射圖是藉由發射大量的光子所組成,紀錄光子於場景中儲存的位置與 列(photon map buffer)。而當發散光子內核程式執行完畢,於主機端將讀到一個儲 存光子的陣列,即是光子映射圖,作為之後進行渲染時所需要的主要資訊。
3.4 Final Gathering
在渲染畫面的內核程式中,最終彙集屬於計算顏色貢獻的主要步驟之一,光 子映射圖將透過主機端傳送至裝置端的全域記憶體,並在最終彙集階段提供資訊 進行彙集光子以及光通量的計算,本論文中,我們從基礎的最終彙集進行改良,
於光線交點之處一定的空間範圍內蒐集光子,傳統上的光子會採用樹狀資料結構 儲存,並不斷維護這個樹狀結構,以節省彙集光子的檢查次數,在 SIMT 平行化
13
的架構認知下,我們將維護樹狀結構定義為不適合的方法,因而沒有進行實作,
而近期 GPGPU 的相關研究也多改以空間雜湊(spatial hash table)的方式彙集光子。
下面兩小節我們會就彙集光子的演算法於 GPGPU 上執行的效能進行探討並且研 究方法上改進的可能性。我們也於 OpenCL 平台上進行一種新的嘗試:將最終彙 集的運算以螢幕空間作為區分進行平行化運算,並利用共享記憶體的優勢。在我 們的實驗中,此種方法得到相當大的加速幅度。
3.4.1 Basic Method
傳統的最終彙集步驟,畫面中每一個像素都會根據場景的光線交點位置彙集
3.4.2 Tile Gathering
我們於實作中觀察到最終彙集的效率不彰,在光子數目到達一定程度時,將 長時間且占用大量的記憶體頻寬,進而導致顯示卡停止回應的窘境,而 Photon Mapping [Jensen 01]中是以 balanced k-d tree 儲存光子,以便於最終彙集階段進行 k- nearest neighbor search,然而此種方法必須頻繁地維護 k-d tree,並且存取全域 記憶體,相對不利於在 OpenCL 平台達成互動式的演算法效能,而近年來,這部
14
分計算所採用的方法於 GPGPU 的平台發展越來越趨向螢幕空間(screen space)的 求解方式,因此我們採取了類似 Efficient GPU Density Estimation [Mara 13]中所使 用的 Tiled 演算法,希望能夠利用共享記憶體區塊節省記憶體頻寬,並且於空間 切割的計算上採用螢幕區塊劃分,快速的進行切割,不同的是,由於使用 GPGPU 的方式進行螢幕空間的切割,無法透過其他方法計算出螢幕空間於場景中影響的 座標範圍,在定義其影響之範圍時仍必須藉由光線交點測試的幫助。
在 tile gathering 的方法實作中,我們主要分為兩個部分進行:tile insertion 與 tile gathering。第一部份 tile insertion 將使用採樣光線以找場景交點的方式,對目 前的內核執行緒所在的群組之影響範圍進行採樣,決定此螢幕空間的 tile 區域於 場景中之對應範圍,並將此範圍中所有具有影響之光子複製到該執行緒所在群組 的共享記憶體區域,若是遇到特殊材質的物體產生多層次彈跳光線時,我們會根 據最終打到的交點位置定義出適合的空間大小,並收集影響範圍內的光子,儲存 至共享記憶體中,而 tile gathering 的計算部分每一個像素則只針對共享記憶體區 域中的光子進行彙集以及光通量的計算,如同傳統方法,我們以光子與交點之距 離作為過濾器,計算該像素於此交點的光子數目以及光通量,而差別是我們不需 要再檢查一次所有的光子是否造成影響。
15