第三章 系統實作
第二節 API 整合和擷取
本節將會介紹如何把OpenGL 3.0 版本固定功能以及矩陣功能整合至 OpenCL
語言撰寫的光線追蹤,看下圖 4 :傳統光柵化管線步驟。
首先在Matrix Transform 時處於 3D 空間座標的物件會轉換到螢幕坐標系上,
這個轉換階段用到的矩陣是投影(projection)矩陣、視覺(view)矩陣和模型(model)
矩陣的乘積(有固定的運算順序),再來 Lighting 階段會計算 Diffuse、Ambient 和
Specular…等標準光照公式,最後才開始執行光柵化相關作業。
大致敘述了傳統光柵化管線後,可以發現上述點名的步驟共通點都是應用使
用者設定的數值來計算,既然這些數值是由人所決定而不是限定光柵化才有用,
那麼就可以直接擷取數據並由整合系統內的光線追蹤來利用。
以下將會分段來介紹如何完成 API 擷取,而這些工作與光線追蹤 host 端前置
息息相關,並為了轉換成kernel 端設計的格式做準備。
圖 4 :傳統光柵化管線步驟
Geometry Matrix
Transform Clipping
Lighting Perspective division
Rasterize Scanlines
15
The matrix manipulation functions
Legacy OpenGL 提供了矩陣系統用來設定光柵化階段所需要的座標轉換,有
Projection 和 ModelView 兩種型態,後者因為視覺矩陣和模型矩陣可以反向操作
來達成相同目的,所以 OpenGL 將兩者視為相同型態。其他還有針對 3D 空間的
操作呼叫,像是位移(Translate)、旋轉(Rotate)和縮放(Scale)…等,也都是矩陣系統
提供的功能,每次的操作都是對現在指定的矩陣型態才有效果。
矩陣系統的設計是用來描述處於 3D 空間物件的位置,不僅在光柵化流程中
使用,光線追蹤對物件的定義也能套用此系統,最重要的就是上段落所說的兩種
型態的矩陣,而整合系統也必須獲得這些矩陣資訊。
幸運的是 Legacy OpenGL 可以透過呼叫 glGet 函式來取得內部狀態,因此前
面段落提到的矩陣操作不需要再重新實作一遍,換言之不必將這些矩陣操作運算
重新導向到整合系統內,因此唯一需要注意的是何時才要擷取矩陣,這個答案也
呼之欲出,回到圖 3 的整合系統流程圖可以發現繪圖指令對應的是整理資料並放
入統一存放區,並不是執行光線追蹤流程,整合系統這樣的行為是因為一定要確
定該畫面在繪製以前場景內容要全部設定完畢,因此擷取矩陣的真正時機就是每
一次的繪製指令呼叫,並且矩陣將不會被用在光柵化管線而是被整合系統的光線
追蹤作為其中的一筆繪圖數據。
16
除了上頁敘述的矩陣功能,OpenGL Utility Library (GLU)也廣泛地被使用在
OpenGL 應用程式中,譬如說 gluPerspective 以及 gluLookAt,前者的功能是指定
觀察視景體(frustum)並定義出 3D 世界坐標系,而後者是指定觀察位置和方向,雖
然兩者沒有透過矩陣功能來改變數值,但實際上 Projection 和 ModelView 矩陣皆
會因為呼叫兩者函式而受到改變,由於 GLU 提供更方便的呼叫模式,通常被使
用的次數不會少於原本矩陣功能,所以需要整合常用的GLU 函式。
比較特別的地方是 Projection 矩陣對於光線追蹤來說比較沒有用處,但指的
是矩陣本身而不是功能性,其實真正有用的是影響該矩陣的參數,如圖 5 所示,
左邊代表原本未套用 Projection 矩陣示意圖,藍色是物體而紅色是視景體,可以
想像的紅色的範圍即是使用者看到的畫面。接下來再看看右邊套用了 Projection
矩陣的示意圖,物體會受到視景體遠近平面的影響而產生形變,而紅色視景體的
部分則壓縮成螢幕的矩形,也就是說畫面更像真實世界的表現了。
圖 5: Projection 矩陣影響視景體
左邊是原本 3D 空間物件分布,右邊是套用了矩陣後的變化,由於針對視景體做 修正,藍色物件會因距離切平面的遠近而產生形變,有如現實世界中觀察物體的
現象。 圖片引用(3,4)
17
拉回到剛剛提到的矩陣問題,光線追蹤需要的是如何在 3D 場景中定義每個
像素取樣的方式也就是光線出發的方向以及取樣間格的設定,所以 Projection 矩 陣的參數像是視野角度(field of view)、長寬比例(aspect ratio)…等才是擷取的重點。
Client-side vertex arrays
VBO 是 OpenGL 為了更有效率地繪圖而將物件緩衝再送入裝置去運算,藉此
減少來回呼叫延遲,而相對於現今modern OpenGL(3.3 版本以上)將 VBO 應用在 shader,以前 legacy OpenGL 的 VBO 是以 client-side 的概念用在光柵化固定管線。
在 client-side 的概念中必須先呼叫 glEnableClientState 來啟動某類別的服務,
舉個例子來說,若現在VBO 包含了頂點資料以及顏色資料,那麼 client-side 必須
要啟動 GL_VERTEX_ARRAY 和 GL_COLOR_ARRAY 兩個列舉型態,這樣在繪
圖管線進行時此 VBO 才會抓取頂點和顏色作為輸入。
上述提到 client-side 掌控哪些服務狀態要被啟用,而對於整合系統來說也要
獲得這些狀態的資訊,因此採取的作法是重新實作相同功能,唯一改變的僅是從
光柵化管線變成給光線追蹤來做使用。
除了 client-side 系統之外,VBO 也是整合系統要獲取的對象,無論是頂點、
顏色或法向量在固定功能呼叫系統中都有專門處理的函式,換個方式來說,每當 VBO 建立後,OpenGL 不會知道使用者會把它拿來做什麼用途,而且資料設定的
方式也以宣告緩衝區的大小以及起始指標來複製指定記憶體區塊,最後直到呼叫
18
了剛剛提到的專門處理函式像是處理頂點的 glVertexPointer,這樣 VBO 才會被用
來做指定的頂點分析,根據位元的位移長度來抓取每筆頂點資料在記憶體區塊的
位置,另外顏色和法向量設定也是相同的道理。
本整合系統對於 VBO 的處理方式和 client-side 一樣,都是將原本提供給光柵
化管線的功能,轉移到系統內的光線追蹤使用,但並不會立即啟動繪製,而是將
資料放在統一存放區。
Fixed-function lighting
Legacy OpenGL 提供了光照的固定功能,透過 glLightfv 來指定光源的屬性,
最常見的設定是顏色資訊和位置,而根據 GL_LIGHT0 至 GL_LIGHT7 的參數可
以對七個光源做個別設定,原則上系統對光源整合也很直觀,就如前面段落的做
法類似,每當呼叫了光源的設定就將函式導向整合系統做數值紀錄,並作為光線
追蹤前置作業的一環。
Buffer Rendering Capability Lighting GLU Extension
glGenBuffers glVertexPointer glEnableClientState glLightfv gluPerspective rtMaterialEXT glBindBuffer glColorPointer glDisableClientState gluLookAt rtBuildKDTreeEXT glBufferData glNormalPointer glEnable
glDrawArrays glDisable
glFlush
表 1: 整合系統支援呼叫列表
Extension 部分並不是 OpenGL 內建的函式,但由於光線追蹤可依照物體的材質改 變光線的行為,實現反射和折射的效果,因此新增這一類的擴充函式。
19
OpenGL 固定功能支援以及前置準備
上頁表 1 是整合系統目前支援的所有固定功能函式列表,從左至右所列出的
項目在先前的段落皆有詳細介紹,這裡再次強調本篇論文的目標,即是希望能提
供一個光線追蹤整合函式庫使得設計OpenGL 應用程式時可以方便的使用光線追
蹤作為繪製畫面的方法,所以到目前為止的論文內容都是討論如何整合 OpenGL
應用程式中常見的函式,總而言之,整合系統就是為了讓這些函式所提供的參數
以及設定數據都成為光線追蹤kernel 端的輸入,而得到的輸出結果就是顯示在螢
幕上的畫面。另外,上頁表 1 中 Extension 的部分列出的是本整合系統提供的擴
充函式,因兩者繪圖方式的差異勢必會有原本光柵化方法沒有的功能,而這裡提
到的函式後面會再提到更進一步的介紹。
20