目 錄
8.1 光線的物理特性與人的感覺
8.2 顏色模擬
8.2.1 非彩色光
8.2.2 顏色模型的三個成分
8.3 照明模擬
8.3.1 環境照明
8.3.2 漫反射
8.3.3 鏡麵反射
8.4 在屏幕到世界中觀察照明
8.5 輻射度
8.6 在世界到屏幕中觀察照明
引言 我們很難對人類對光線的感知能力做出過高的評價。但在我們所擁有的所有的感覺器官中,眼睛無疑是最重要的一個。這或許是因為由眼睛獲得的信息與人體其他器官所獲得的信息相比有更大的帶寬所造成的吧。正是由於這個原因,整個計算機圖形學領域的內容都建立在了開發人類的視覺感知能力上。
在前麵的介紹中,我們已經討論了如何來描繪一個真實場景的大致輪廓。但是,如果我們對同一個場景使用不同類型的燈光的話,那麽這個場景最後表現出來的效果將會大大不同。並且這種不同不僅僅表現在物體的表麵有不同的顏色,也將影響到場景的反射和陰影模式(shadow pattern),它們的效果也是很明顯的。
同時,顏色和光線在計算機圖形學中也是兩個很重要的主題。它們都橫跨了多個領域,這些領域包括:幾何學,光學,物理學等。我們將會討論在計算機圖形學程序中表現顏色的一些基本原理,以及關於光源與被照亮物體之間相互作用的一些話題。這些討論都是基於自然界中實際處理這些情況的過程的基本原理。但是其中大多數都是最基本的,這一點也是可以理解的,主要是因為采用高級的光學和波動理論將會消耗很大的資源。這一點也有一定的缺陷,例如我們采用的反射模型,使用它將無法產生我們在真實世界中所看到的某些效果。但是在某種程度上,我們可以采用合成方法,它與真實情況相比較也是可以接受的。
在下麵的討論中,我們也將討論一些基本的模擬顏色和光線的途徑,特別是如何將世界中的光線處理到屏幕上。
8.1、光線的物理特性與人的感覺
我們使用計算機圖形學方法進行渲染的最終目標就是要能夠通過眼睛的處理。因此,我們就必須要充分考慮人眼是如何觀察物體的。
是什麽能使我們的眼睛區別紅色與藍色呢?在物理上,紅色與藍色又有什麽區別呢?光在本質上一種電磁場,它在電磁特性上的一些參數決定了它的特性。這些電磁波根據頻率或者波長的不同而表現出不同的特性。我們的眼睛隻能看到波長為400到700納米之間範圍內的光線。
我們對兩個眼睛接收的光線進行聚焦,每一個眼睛接收的圖象是有所不同的,並且可以大致估計出物體到我們的距離。如果同一處物體的圖像的投影完全一致的話,那麽這個物體就在離我們無限遠的地方。如果圖象有一定的位移,那麽物體的距離就會離我們近一些。我們交替的閉上眼睛,注視不同距離的物體就會明顯的感覺到這一點。我們可以充分利用這一特點來產生沉浸式(immersive)的具有真實感的三維視覺圖形,具體來說就是要保證我們的兩個眼睛能夠看到同一個場景的不同角度的圖象。使用這種方法,我們就會感受到場景的深度信息。當然,我們的程序還必須依賴一些特殊的硬件才能達到上麵的效果。這些硬件種類很多,從價格昂貴的頭盔式顯示器(head-mounted displays)(兩個眼睛有各自不同的顯示屏幕)到相對便宜的光閘眼鏡(shutter glasses)(交替關閉透鏡,從而使每一隻眼睛能夠同步的接收到計算機屏幕產生的不同的圖象)。
我們所看到的圖象在眼睛裏被投影到視網膜上。視網膜上的視覺神經能夠感受顏色。我們眼睛主要有兩種感受光線的細胞:錐狀細胞和杆狀細胞。杆狀細胞對光線有很強的感應能力而對顏色則沒有直接的感覺。錐狀細胞則對顏色存在感應能力。有三種不同的錐狀細胞,每一種都隻對某一特定的光譜範圍有最強的感知能力。第一種對光譜中的藍光敏感,第二種對綠光敏感,第三種則對紅光敏感。對紅光區域最敏感的細胞對相鄰的光譜區域也有一定的感應能力,隻是隨著距離的增大而逐漸減小。人眼感應藍光的細胞相對來說分布密度較小,因而感應能力也就比紅光和綠光要小一些(見圖8.1) 。這對於我們建立顏色調色板有一定的提示作用。通常我們都隻分配較少的顏色位數來表示藍色。
|
圖8.1 不同顏色受體的敏感性範圍 |
通常,上述三種分布綜合起來決定了我們對不同波長光線的感應能力。對於人眼來說,最敏感的顏色位於光譜範圍的中心附近。
單色光可以通過波長和強度來唯一的進行表示。但是真實的可見光都不是單色光 — 它們都是由不同波長和強度的光線組合而成的。實際光線可以用光線在可見光範圍內的能量分布來表示。略微偏紅的顏色的分布圖會偏向右側一些,而偏藍的顏色會偏向左側一些。
|
圖8.2 某種顏色的能量分布 |
從物理學上來講我們用能量分布來表示顏色,但是在實際的計算機圖形學中我們沒有必要這樣做。考慮到人眼的一些特性,我們可以使用能量分布最大值處的波長 — 主波長(dominant wave length) — 來表示顏色。實際上,我們認為具有不同能量分布而又具有相同主波長的顏色具有相同的色度。而整個分布範圍內能量的總量則涉及到了顏色的飽和度問題,例如,理想白色光的能量分布在整個光譜範圍內是一條直線,它沒有主波長,因此飽和度就是
0%。一個具有
100%飽和度的顏色隻在某一位置上有一個能量衝擊, 而在其他地方的能量均為0。光線的亮度則涉及到了能量的大小問題,特別是能量分布的優勢部分的能量大小。
上麵通過能量分布來描述顏色的假設對我們來說還是有些太複雜,並且也沒有考慮到我們人眼視覺係統的一些特性,接下來,我們就要檢驗一下在計算機圖形學程序中模擬顏色的實際的一些方法。
8.2、顏色模擬 人類為不同的物體再生出顏色的嚐試可以一直追溯到幾個世紀以前。對繪畫顏色的混合以及彩色電視機的出現可能算作使這種嚐試的成功典範了。在所有的嚐試中,我們所使用的方案都要比能量分布來的簡單,並且也都獲得了可以接收的結果。下麵,我們就來討論一下計算機圖形學程序中所使用的幾種方案。
8.2.1 非彩色光(白與黑) 光線的總能量對我們的感覺來說是很重要的。我們在觀察黑白圖象以及將它們聯係到現實生活中時,都間接的證明了這一點。較早的電視機與計算機顯示器都是黑白的。黑白顏色如此受到歡迎主要是因為使用它可以簡單的對任何顏色進行描述和重建。我們需要得到的僅僅是一個與光線能量大小相關的數字罷了。較高的能量轉化為較亮的顏色,較低的能量則轉化為較暗的顏色。
在我們表現光照效果時(例如反射效果,我們很快就會討論到它),我們需要一種顏色的一整套不同的亮度等級。要得到這些亮度等級,我們就要給不同的亮度等級分配一些索引,這樣就可以隨著索引的增長而得到逐漸變亮的亮度等級。
通常,這些索引並不是簡單地與光線的亮度成比例。它們實際上是成對數關係的。當能量較小時,我們需要索引的增量小一些,而當能量較大時,則需要增長得大一些。這主要是因為我們的視覺係統在能量等級較高時不容易區分亮度之間的差別。大多數情況下,計算機顯示設備都會考慮到人眼的這一特性。
為非彩色光的亮度等級設置了索引之後,我們就可以執行某些光線操作了。例如,由於兩個燈光合並起來的效果跟它們能量的和有關,所以我們就可以用它們索引的和來模擬它們合並後的效果。簡單來說,我們可以在索引間進行內插,找到一個適合於已知亮度的索引值。
但是,我們將兩個索引加起來之後得到的值很有可能會超過可用亮度等級的範圍。當可用亮度等級的數量存在上限時,我們就要設計一些方法來保證任何顏色操作的結果都能夠有一個正確的值。
最簡單的方法就是將索引值限製在上限範圍之內,也就是將比上限更亮的光線都用可能的最亮亮度等級來表示。另一種方法是對所有的顏色進行縮放,從而使得到的最亮顏色與可能的最大值對應起來,這樣,其餘的顏色亮度也就相應的減小了。
盡管非彩色光對許多技術仍然非常重要,但是現代的3-D圖形已經開始將彩色作為提高視覺真實感的一個重要的工具了。
8.2.2 顏色模型的三個成分 我們已經認識到光線分布的某些特定屬性對於我們的感覺有更重要的作用 。主波長影響著顏色的色調(hue),而光線的分布區域則影響著顏色的飽和度。能量分布的優勢區域內的能量等級影響著顏色的亮度。這些概念都是很直觀的,因此, 我們就有了一個模擬顏色的方法,那就是通過對顏色的色調(hue)、飽和度(saturation)以及亮度(brightness)進行描述。這就是我們常說的HSB係統,下圖顯示了HSB係統的顏色空間(見圖8.3):
|
圖8.3 HSB顏色空間 |
在這個係統中,色調用角度進行度量,亮度在水平方向上進行度量。這樣,黑色就位於顏色空間的底部,白色則位於頂部。從圖中我們可以看到,飽和度在亮度很小時其大小也是很小的,當亮度增大時,它的範圍也相應增加了。
盡管這個係統在直觀上非常地清晰明了,也允許我們對顏色做進一步的詳細說明,但它仍然不適於在計算機程序內來使用。為此,我們仍然需要尋找一種係統能夠很容易的表示幾個光源之間的相互作用,很容易的表示多個光源的合成效果或者很容易的在兩個已知顏色間進行內插運算。
既然我們已經知道人眼的敏感度集中在三個區域內,那麽我們就可以嚐試著用這三個區域內顏色的加權和來表示一個單獨的顏色。這三個眼色就是紅、綠、藍,也就是我們常說的三原色。這樣,我們就可以用下麵的形式來說明一個顏色了:
式中的R、G、B分別表示紅、綠、藍三種顏色各自的亮度等級。這樣我們隻用三個值就可以表示一個顏色,當然要比用能量分布表示顏色的方法更容易操作。盡管這種方法並不完全正確,並且也不能覆蓋所有的可見顏色範圍,但是它確實十分簡便,並且它的加和性(additive nature)也有很高的應用價值。
這種係統之所以具有加和性,主要是因為我們能夠將純色相加而產生處一個合成顏色。在第一章中,我們已經遇到過采用RGB係統來表示顏色的實際硬件。
由於這個係統的加和性,我們也可以使用矢量加法的形式將兩個光線的效果進行合成,也就是將RGB三個分量分別相加:
從直觀上來講,我們可以認為每一種顏色都位於下圖這樣的一個三維空間中的一個點上,該空間的每一個軸都是一種基色:(見圖8.4)
|
圖8.4 RGB顏色空間 |
通常,我們也要限製每一種基色的亮度範圍,這一點與非彩色光的情況相同。這樣,所有可能的顏色就都位於圖8.5所示的立方體內:
|
圖8.5 顏色立方體 |
在這個立方體中,灰度的亮度位於對角線上,白色表示為(1,1,1)黑色表示為(0,0,0)。立方體所包圍的空間完全對應與HSB係統所表示的錐體空間。如果我們沿著對角線將白色和黑色點連結起來,那麽這條線就正好對應於圖8.3中錐體的軸。
有一個問題與我們在使用非彩色光線時一樣,那就是兩個彩色光線疊加後的效果有可能會超出上圖立方體所表示的範圍。那麽這時最普通的方法就是將超出範圍的三種顏色成分分別鉗製在規定的範圍之內。還有一個方法就是對所有的顏色進行縮放以避免上述溢出情況的發生。由於大多數情況下我們無法預先知道所有光線可能的值也無法知道它們疊加之後情況會如何,所以我們通常還是采用第一種方法來處理溢出情況的發生。
除了上麵提到的幾種顏色模型之外,還有其它許多種模型來描述顏色,如:YIQ,它主要用於描述廣播電視信號;CMY,它多用於hardcopy打印技術。我們在計算機圖形學中主要使用RGB係統,這主要是因為它能將大多數的光照問題分解為三個相互獨立的基色來處理。由於係統的加和性,對於每一種基色單獨進行處理的方案進行合並之後所得到的效果與我們在真實世界中所看到的效果是完全相對應的。例如,當我們要對兩個顏色進行內插時,通過對兩個顏色的三個成分分別進行內插,然後將它們合成起來得到的效果與直接進行內插得到的效果是一樣的。而在這種情況下使用HSB係統有可能無法得到滿意的結果。我們通常會給RGB係統添加第4個分量“
alpha”,它用來描述透明屬性。這種擴展的RGBA係統有助於我們對複雜照明效果進行模擬。
在第一章中,我們已經介紹過顯示硬件可以為描述圖象位圖提供不同方式的支持。其中有一種是像素的顏色直接通過RGB值來進行描述,另一種則是通過一個調色板索引來進行描述。在後一種方式中,調色板中存儲了實際的RGB值,並且調色板的大小也有限製。我們經常要將第一種方式存儲的位圖轉換為後一種方式存儲的位圖,這時就要被迫減少顏色的數目。由於第一種表示方法是連續的,而第二種方法是離散的,因此這一問題就是我們所說的顏色量化(color quantization)。
如果我們要從原始圖象中選擇所有唯一的顏色,我們就必須在顏色空間中找到一些簇(cluster),這樣在一個簇內,顏色間的距離是最近的,然後我們用一個單獨的顏色來代替整個簇。直接解決這一問題的計算量是很大的。但是我們已經有了許多技術可以有效的找到一些近似值,這樣就產生了我們感覺上可以接收的顏色簡化(color reduction)。下麵我們要討論其中的一種叫做
median-cut(中線切割)的算法,它最初於80年代早期由P.S. Heckbert提出
。 這種算法將顏色視為三維空間中的點來看待,它首先要找到圍繞最初顏色的邊界盒,然後沿著最長一邊的中線(median)將邊界盒切割為兩部分, 這樣就可以將問題分解為兩個子問題來解決。圖8.6這時了一個平麵例子的處理步驟,它忽略了B-軸。
|
圖8.6 顏色簡化過程的步驟 |
如圖8.6(a)所示,我們沿著邊界正方形的最長一條邊將它分為兩個部分。然後依此類推計算得到的兩部分中顏色的邊界正方形,並進行分隔(如圖8.6(b)所示)。我們可以看到,一個分隔沿G-軸進行,另一個分隔則沿著R-軸進行。一旦我們達到了所需的數量要求,我們就可以停止進行分隔。例如,如果我們要用四種顏色來代替原先的顏色,那麽經過兩級分隔之後就可以不再進行分隔,接下來就要在每一個部分中分別計算顏色點集合的質心,從而得到我們所要的顏色(如圖8.6(c)所示)。
在進行分隔時有一點要注意,那就是為了提高顏色簡化的質量,還要考慮到原始顏色的點在圖象中出現的頻率問題。這一信息在計算中線以及質心時要予以考慮。該信息在中線和質心計算期間使用,這樣,沿軸的中線被作為沿軸的坐標被這些頻率總和分割開的頻率次數和來計算。質心的坐標被作為各自沿軸的中線來計算。
在下麵的討論中我們將會看到,為了很好的表現出照明效果,我們要求能夠表現出同一顏色不同的亮度等級。當圖象位圖存儲了整個RGB值的時候,這一點並不難做到, 但是如果我們使用調色板來進行描述時就要變得複雜的多了。這時,我們隻有有限的幾種顏色可用,並且位圖存儲的是調色板入口的索引值。這時,為了對應於某些更亮的顏色,可能就要調整顏色板中的顏色以便增加索引值。但是,如果調色板中某些顏色的色調完全不同的話,那麽以任何順序來安排它們都是十分困難的。有時,我們可能要在邏輯上將調色板分割成一些顏色組,這樣在這些組中,增加的索引就能與更亮的亮度等級相對應。
必須要注意的是,這些組可能仍然會共用某些顏色。例如,任何在零照明情況下的顏色都支持黑色。既然我們要考慮顏色數目的限製,那我們就不能允許重複存儲同樣的顏色,這樣就有必要用另外一個調色板來反映這些共用的顏色。為了表現出共用的顏色,我們可以建立一個二維數組,用一維來表示顏色的索引,另一維來表示亮度等級的數目。由於有顏色共用的存在,表格的大小可能會超過調色板的大小。
還應強調的是,增加的索引完全對應於使用非彩色光時的情況。如果我們要使用不同顏色的光源,那就有可能在第二個表格中需要更多的維數。
8.3、照明模擬 在前麵的討論中,我們已經研究了光線的本質、屬性以及在計算機圖形中模擬不同顏色光線的一些方法。然而,由一些光源以及我們周圍物體所發出的光線是有相互作用的。
三維圖形的最終目的就是要描繪出來自於真實世界的圖象。為了這一目的,我們當然要重視對人類視覺有重要作用的光線與物體的相互作用問題。
在光線與物質之間有許多種類的相互作用。例如,物質可以吸收、反射或者是傳播光線。這些效果都可以用光線的粒子屬性來進行解釋和模擬,也就是說,可以把光線模擬作一束很小的粒子。模擬其它的效果,如幹涉、衍射或者是反射,則需要用光的波動理論來進行解釋。總之,充分考慮到光線與物質相互作用的光照模型是很複雜的,同時用計算機處理起來計算量也很大,特別是要在具有交互性的程序中實現計算量就更大了。因此,大多數程序就隻去考慮一些絕對重要的相互作用,如比較顯著的反射效果。在這一部分中,我們將討論在計算機圖形學中廣泛使用的光照模型的一些組成部分。
8.3.1 環境照明 在計算機圖形學程序中,最簡單並且也是最早應用的照明模型恐怕就是環境光模型了。在這個模型中,我們假設隻有很少的光源,且其照明在任何方向都是相等的。
使用這種照明方式,每一個表麵所表現出的都是它固有的反射能力。能夠較好反射光線的物體看起來就會亮一些,而吸收了大部分光線的物體看起來則會暗一些。在日常生活中,我們會發現物體經常都處在一個由太陽發出的統一的白光照射下。很明顯,這與我們通常所說的有材質物體的顏色有關。我們所說的某種有材質物體的顏色實際就是描述了它對白色光的反射能力。通常,反射能力可以用[0,1]範圍內的一個係數來進行描述,0意味著物體將百分之百的吸收一個給定頻率的光線,1則表示完全反射。我們可以看到, 這個係數是與波長有關的 — 大多數物體會吸收某些頻率的光線而反射掉其它頻率的光線。因此,一個有材質物體的反射能力就可以用一個分布來進行描述,在這個分布中,反射係數是入射光線波長的函數。根據前麵對顏色模型的討論,我們知道一個顏色既可以用一個索引值來進行表示(非彩色光情況下),也可以用三基色來進行表示(彩色光情況下)。這樣,我們所說的物質的反射能力也就既可以用一個單獨的係數來表示,也可以用三個係數同時來表示。總的來說,我們用下麵這個簡單的公式來表示光照模型:
使用上麵的公式,我們可以得到在環境光照明情況下光線反射後的亮度值。注意,公式中的
和
在非彩色光模型下均為表亮,在彩色光模型下均為三維矢量。
由於環境光等級保持為常量,這樣我們就可以預先設置場景中每個表麵的
使每個物體都能使用它本身的顏色。下圖中的物體使用了環境光照明模型,我們可以看到,它的真實感是很差的,我們隻能從圖中看到物體的輪廓而已。
|
圖8.7 環境照明 |
為了提高圖象的真實感,我們就需要尋找更複雜的照明模型。但是這種古老的方法至今仍然在廣泛使用,特別是用來執行一些我們不願去計算的效果,例如光線在物體表麵的多重反射。
8.3.2 漫反射 在真實世界中,我們經常見到的光線都是由某些固定的光源發出的,它們總是從某一個方向照射到物體上,而不像我們在討論環境光時那樣不用考慮光線的方向。為了模擬這種情況的反射效果,我們在考慮反射表麵屬性的同時,還要考慮光源的位置和類型。我們將光源分為點光源、聚光源以及方向光。正是這些光源在真實世界中照亮著各種有材質的物體。漫反射模型就是指物體表麵把這些光線均等的反射到各個方向(如圖8.8所時)。
|
圖8.8 漫反射 |
這一個模型主要是針對粗糙表麵而建立的。如上圖所示的粗糙表麵,表麵上每一個小區域內都有大量的朝向各個方向的小的表麵,因此它的反射也是朝向任意方向的。這樣,在任何方向上反射後的光線的亮度就隻依賴於有多少光線照射到表麵上。當然,它是光源與表麵之間方向的函數。如果表麵朝向光源方向,與燈光的方向正交,那麽反射的光線亮度是最大的。
|
圖8.9 漫反射圖示 |
下麵我們來看漫反射公式:
從公式我們可以看出,當入射光線與反射表麵正交時,反射達到最大值,並隨著入射光線與反射麵夾角的減小而逐漸減小。同時要注意,當角度大於
或者小於
時,此光源的光線沒有照射到該表麵上,因此也就沒有反射。但是如果隻從公式來看,我們得到的值將是負值,這是違反物理常識的,因此要將它設為0。
從實際情況來考慮,上麵的情況也會導致一個問題。當環境中隻有一個直射光源時,那麽所有背向它的表麵都將是黑暗無光的。但是在實際情況下,總會有一些光線通過多次反射能夠到達上述表麵。而我們使用的這個漫反射模型隻考慮了由光源發出的光線,沒有考慮到經過其它表麵反射的光線。在實際應用中,我們對上述模型要進行一定的調整,用環境光來模擬多次反射的情況:
得到修正後的模型稱為
Bouknight照明模型, 是根據它的發明者來命名的。圖8.10顯示了使用這個模型來進行渲染所得到的效果:
|
圖8.10 漫反射或Bouknight照明 |
在使用這個模型時,假設已經知道了表麵和光線的屬性,但仍然需要有一個方法來計算
值。在前麵的章節中,我們已經認識到了法向量在描述一個平麵的方向時的作用。那麽現在,讓我們用一個單位向量
來表示光源的方向。根據定義,兩個矢量的標量積(scalar product)公式如下:
式中
和
是矢量的模。假設上述兩個矢量都是單位長度的,那麽我們就可以套用上麵的公式,用光源方向矢量和需要計算反射光亮度的那一點處的麵法向量來計算
值。這樣, Bouknight照明模型就可以用下式來代替
:
公式中,根據我們使用的顏色方案的不同,各項可以是標量(非彩色光情況下),或者是三維矢量(RGB顏色模式下)。
在前麵幾章中,我們已經介紹了法向量的計算方法。但是,直到目前為止,我們還從來沒有要求過法向量必須是單位長度的。實際上,在進行背麵剔除(back-face culling)或者是建立平麵公式時, 矢量的長度是沒有特別要求的。但是在進行照明模擬時,我們就需要用到單位長度的矢量。很明顯,我們隻要用矢量除以它當前的長度就能使它單位化了:
根據定義,一個矢量與它本身的標量積就等於它的長度的平方。這樣,將矢量與它本身的標量積開平方就可以得到該矢量的長度:
在計算單位矢量的過程中,唯一比較困難的地方就是計算平方根了。它的計算量是比較大的。
有一個快速的計算平方根的方法,稱為二分搜索算法(binary search algorithm)。在這個方法中,我們先假設一個結果,然後計算它的平方。如果平方值比我們討論的值大,那麽我們假設的平方根也就要比真實值大。相反,如果平方值比我們討論的值小,那麽我們假設的值也就比真實值小。這樣,我們就可以使用二分搜索技術,每次將兩個假設值之間的距離減小一半,直到它們的距離小於精度要求時,我們也就得到了滿足精度要求的平方根值。盡管這種方法是比較快的,並且隻是一些迭代過程,但是它在每一步迭代時仍然要進行平方運算。在許多情況下,空間中物體的坐標值都是整數的,並且在矢量長度的計算過程中,我們也希望結果能是整數的。這樣,我們就可以充分利用上述算法中的假設來分析應該設置哪些結果位。
利用上述算法,我們先估計一下結果可能的最高位,然後為最高位假設一個值,並計算它的平方。由於隻設置一個位,因此它的值就應該是2的冪,這樣,就可以通過移位的方法來進行平方運算。得到平方值之後,如果它比我們討論的值大,那麽這一位就不是最終結果中的位,相反,如果小於討論值,那麽它就是最終結果中的位。接下來設置次高位。由於這一步中的估計值不止一個位,因此不能使用移位的方法來進行平方運算。我們可以用下麵的公式來計算平方值:
如果
a是第一步得到的估計值,
b是當前位的假設值,那麽
(a+b)就是當前的假設值。這個新的假設值由三個部分之和組成。第一部分是上一步迭代中的平方值, 後麵兩部分都是兩個2的冪相乘得到的值,這樣,這些部分都可以通過移位來進行計算。得到平方值之後,檢查這一位是否是結果中的位。然後我們要處理下一步迭代,同樣,我們會遇到與上一步一樣的情況,我們可以按照相同的方法來處理,這樣就能得到這一步的結果。以此類推,直到計算完所有可能的位之後,我們也就得到了平方根的整數近似值。程序清單8.1列出了這一算法的實現:
|
程序清單8.1 按位迭代計算平方根 |
要注意,在表7.1所列出的代碼中我們認為整數占據了32位,因此,我們在估計最高位時,要保證它的平方值不會超過可能的精度。
8.3.3 鏡麵反射 在真實世界中,不僅要使用漫反射模型,同時還要接觸大量鏡麵反射的情況。通過鏡麵反射,可以看到物體表麵的高光,或者是光源在光亮物體表麵上的反射。
|
圖8.11 鏡麵反射 |
用來描述鏡麵反射的模型需要知道光源和觀察者的位置,以及反射表麵的朝向。當觀察者位於一個合適的角度時,可以看到物體表麵上某個地方的高光。當觀察者移動時,可能還會看到從表麵上其它地方反射的高光。對於大多數的材質來說,鏡麵反射時,光線的波長不會發生很大變化,因此高光的顏色與光源的顏色仍然是一樣的,而不會根據反射表麵的顏色發生變化。
通常,描述光亮物體的反射情況是很複雜的。在計算機圖形學上,我們一般隻使用一種描述鏡麵反射的模型,
Phong照明模型,它是根據其發明者Phong Bui-Tuong來命名的。這一模型適合用來描述不太完美的反射表麵的反射情況。當我們接近反射角度觀察時,根據這一模型得到的鏡麵高光與光源的波長成分是一致的。當觀察者從鏡麵反射的方向逐漸離開時,反射光線的亮度也逐漸減小(如圖8.12所時)。
|
圖8.12 鏡麵反射圖示 |
亮度的減少量大約是
,
是一個標量係數,它表示了入射光線反射的百分率。由於反射光線的波長成分與光源的一樣,因此對於任何顏色模型來說,這個係數都是標量。公式中的
n表示了表麵的光亮屬性,它的範圍可以從1到無窮。不太光滑的表麵需要較小的指數,這樣反射得到的高光亮度衰減就回大一些,高光也就會暗一些。相反的,一個比較理想的反射麵所要求的指數就要很大,這樣高光才會比較強烈。
對於非理想反射麵來說,它的反射中既有鏡麵反射成分,也有漫反射成分。這樣,就要對Phong照明模型進行一定的修改:
注意,我們仍然使用了環境光來模擬多次反射得到的效果。下圖顯示了上麵模型的效果:
|
圖8.13 Phong照明 |
在上麵公式中,我們需要計算
的值。我們可以使用前麵提到的標量積的方法來計算它,這裏要用到兩個單位矢量,一個是表示鏡麵反射方向的
,另一個是指向觀察者方向的
。用表量積的形式我們對上麵的公式進行修改:
但是在這個公式中, 還要使用表示反射光線方向的矢量
。在鏡麵反射模型的圖示(圖8.14)中我們可以找到它與其它角的相等關係。
|
圖8.14 鏡麵反射圖示 |
從圖8.14中可以看到, 矢量
是矢量
和
的和。矢量
又是矢量
在法線方向上的投影。投影的長度可以用
來表示,
可用標量積來進行計算。由於
和
都是單位長度的,所以我們可以用
來表示矢量
的長度。而
本身就可以表示為
。同樣,我們用
來表示矢量
。這樣,鏡麵反射的方向就可以用下是來進行表示了:
將上式代入Phong照明模型的表達式:
這個公式的計算量是很大的,特別是式中有大量的矢量點乘。在實際應用時,我們經常用一個不太嚴格的公式來替代它。當觀察方向接近反射方向時我們不再進行測量,而選擇在表麵的朝向變得能夠對觀察者產生高光時進行測量,這時,我們就要考慮一個新的夾角,即表麵法向量與半程矢量(
half-way)
間的夾角(圖8.15)。
|
圖8.15 鏡麵反射的替代公式 |
矢量
剛好位於光源方向與指向觀察者方向的中間方向上。這樣,當它與法向量一致時,反射方向也就與指向觀察者的方向一致了,我們就可以觀察到鏡麵高光。這時,我們用下式來表示Phong照明模型:
使用這個公式,我們可以減少一些計算量,因為計算
要比計算
相對容易一些。還有一種減少計算量的方法,就是假設光源和觀察者都位於無窮遠處,這樣半程矢量就會近似不變。但是,這樣對於具有交互性的程序來說並不是一件好事,因為鏡麵高光將不會按我們設想的那樣隨著觀察者的移動而發生變化。
我們還應注意到,這兩個公式是不相等的,它們也都無法描述反射的真實物理過程。但是,既然我們的目的隻是要表現出一個足夠真實的虛擬場景的話,那我們也就隻好接收這樣的模型,因為它們的計算量是我們現在的設備所能夠接受的。
對於這個模型,還有許多改進的方法。有一些模型加入了一些對非反射現象的考慮。例如可以考慮光源,還有大氣衰減等。對於光源來說,由於我們使用的是點光源,因此在各個方向上的輻射能量都是相等的,並且形成了一個球麵,這樣,隨著距離的增加,能量也將會隨之衰減,並與距離的平方成反比。對於大氣衰減來說也是一樣,當光線穿過統一的介質時,有一部分會被吸收掉,因此亮度也會隨著距離的增加而減小,並且與距離成反比。我們還可以在公式中考慮光線的傳播問題,這對於模擬透明或半透明物體是非常有用的,例如水或者是玻璃。增加所有這些效果對於更加真實的描繪場景無疑是一件好事,但是我們強調一點,那就是各種效果的使用要通過對實際效果的試驗比較而不是單純的分析來決定。
8.4、在屏幕到世界(screen to world)中觀察照明 迄今為止,我們隻討論了光源與被照亮物體之間的相互作用。然而在實際生活中,經常會有多個光源與多個反射物體,它們彼此之間以各種方式相互作用和影響。因此,處理整個虛擬場景的光線就要使用全局照明模型。在這一部分中,我們將討論如何將一個全局照明模型添加到屏幕到世界以及光線投射過程(ray casting)。當我們以屏幕到世界用於計算可見性和照明時,這種算法經常被稱為光線跟蹤(ray-tracing),以便與僅應用於可見性判斷的光線投射方法相區別。
在屏幕到世界中使用照明模型,它的方法是比較一致的。我們可以回想一下,在這種觀察方法中,每一個像素將有一束光線投射到屏幕上,這樣就可以來表現可見場景了。然後對所有分隔表麵進行檢查並選擇離觀察者最近的一個來進行顯示,完成可見性的判決。
要增加照明信息,就要確定分隔表麵的屬性,例如它的法向量、材質等。這些屬性與光源屬性、位置、亮度等相互結合,向我們提供了應用照明模型的一些信息。在有多個光源時,它們的效果將會相互疊加。在前麵的圖8.7、8.10和8.13中,我們分別對環境光、Bouknight和Phong等區域照明模型分別使用了光線跟蹤算法。
但是上述的區域光照模型隻考慮了一個單獨的對象和光源之間的關係,沒有考慮由於多個物體的存在而產生的效果。例如,一個光源可能不能照射到某個點上,這樣,在這個點上就不會產生陰影。同樣,有一些物體可能不是由光源所照亮的,而是由一些反射的光線照亮的。
幸運的是,我們把應用於可見性判決的光線跟蹤算法進行一些擴展,使它能夠處理全局照明的問題。我們要考慮兩種效果,第一種是在要進行光線照明模擬的點上檢查光源的可見性。我們從這一點到光源投射一束光線,它叫做陰影射線(shadow ray),通過它我們來進行光源的可見性判決。如果這束光線在到達光源之前穿過了幾個表麵,那就表示光源被遮擋住了,也就不用考慮該光源在這一點的照明問題。下圖顯示了這一過程:
|
圖8.16 計算陰影 |
要注意,我們要找的是位於光源和該點間的第一個交匯點。因此,在找到第一個交匯點之後,就可以停止檢查。還有一點要注意,那就是不要考慮陰影射線位於光源和該點之間以外的部分。我們可以構造一個有方向的矢量來完成上述任務, 這個矢量是光源位置與給定點之間的差分。使用這個射線,位於該點之前的交叉點的參數t的值將會是負的,而位於光源之後的交叉點的t值將會大於1。
增加了對陰影的考慮之後,場景的真實感得到明顯的增加。圖8.17中展示了一個使用上述技術的場景:
|
圖8.17 考慮陰影的光線跟蹤 |
觀察圖8.17,我們可以看到,所有的陰影都很明顯,剛好劃分出了照亮區域和陰影區域。但在許多真實環境中,陰影與照亮區之間都有一個過渡區,這主要是由於真實世界中的光源並不是理想點光源所造成的,它們總有一定的麵積。為了更加接近真實環境中的實際陰影效果,在進行計算時不僅要考慮是否能夠照射到,還要考慮有多少光線照射到的問題。這樣,位於陰影邊緣區域的部分就會有一定的過渡效果。
我們已經注意到,一個點的照明不僅要考慮光源的直接照射效果,還要考慮反射光對該點的照明效果。這樣,我們在考慮照明模型時就要將直接照明和反射光照明兩部分都加入進去:
在使用通用的Phong照明模型和特殊的鏡麵反射時,我們可以使用一種被稱為遞歸光線跟蹤(recursive ray-tracing)的方法來找到上述的反射光線對光照模型的影響。在鏡麵反射情況下,總有一個主要的反射方向。以前,我們通過檢查這個方向來判斷一個點是否能產生鏡麵高光。在考慮反射光的情況下,我們還要通過檢查這個方向來判斷是否還有其他光線能夠在這一點產生出鏡麵高光。這樣,通過遞歸使用光線跟蹤算法,我們投射出一個沿著反射光方向的射線,就可以完成反射光線對物體照明的判斷。下麵的圖8.18顯示了上述計算陰影以及反射光線的過程。
|
圖8.18 計算陰影和環境反射 |
當然,這一過程是循環進行的。為了計算正確的光照路線,還要產生出其他的反射射線。在實際使用時,要對光線的反射次數進行一定的限製,不能無限次的反射下去,經過多次反射之後,有些光線就可以忽略不記了。
環境反射還要有一個係數來進行加權,因為物體的反射能力是有所區別的。盡管在實際生活中這一係數對於光源和反射光都是一樣的,但我們通常還是將它們分開來進行考慮,這樣可以對最終的圖象結果進行更好的處理。圖8.19是一個通過遞歸光線跟蹤方法計算的場景的效果:
|
圖8.19 考慮陰影和環境反射的光線跟蹤效果 |
在圖8.19中,反射的效果已經十分接近真實情況了。要注意一點,一些反射所反映的場景圖象是我們所無法直接看到的。既要模擬虛擬世界中的額外物體,又要計算不能直接看到的物體間的光線作用效果是很耗費係統資源的。在這種情況下,我們可以將可見物體放置在一個立方體中,然後把用來描繪不可見環境的靜態圖象以紋理的形式貼附在它的內部多邊形上。這樣一來,既避免了對額外效果的模擬(因為紋理圖象都來自真實環境),又減少了循環的次數。
通常,光線跟蹤算法可以通過很簡單的語句就能實現,它被編製成一個統一的框架,應用於不同的任務,如可見性判斷、陰影、以及光照模型的其他部分。程序清單8.2中列出了一個主跟蹤路徑,用於進行當前的渲染。
|
程序清單8.2 遞歸光線跟蹤算法 |
我們還可以將光線跟蹤算法進行擴展,進行其他光照效果的的計算,例如穿過半透明物體的光線反射。
我們還可以給上麵的算法加入一個計算光線亮度隨距離衰減的函數,這樣就可以考慮光線衰減問題了。我們還經常要對表麵的無規律則性進行模擬。這時,可以給表麵分配一個紋理圖樣,使它的每一部分都有不同的反射係數。為了更好的對表麵的無規律性進行模擬,還可以使用凹凸貼圖(bump-map)。在使用它時,物體表麵的法向量是雜亂無章的,因此反射也就有不同的方向。
我們可以將以上這些效果以及其它可能的效果混合在光線跟蹤框架中,這樣產生出來的效果會十分逼真。
但是,使用遞歸光線跟蹤方法時也會有一些問題出現,它們直接導致了在對一幅光線跟蹤圖象進行觀察時會出現一些問題。首先,我們在處理鏡麵反射時要依賴於不同的光線屬性。在光源方麵,我們通常設置一個近似的函數來產生較強的光線。另一方麵,環境的影響則通過反射射線來進行計算。所有由光源產生的高光的大小最多隻能有一個像素。換句話說,我們在由光源產生高光的情況下對表麵的不理想性進行調整,而不是在由反射光線產生高光時進行調整。結果,反射的效果往往就超出了實際的情況,變得非常的好。
在使用修正的Phong照明模型來計算環境反射的影響時,我們還會遇到另一個基本的問題, 那就是不用考慮漫反射光線對環境反射的影響。所有的漫反射表麵反射的光線都會發散到所有的方向,因此總會有一些光線照射到使用照明模型的點上。對於這些光線,我們的模型將不予考慮。既然漫反射的光線可以照射到一些給定的點上,那我們就應該對所有方向都發射出一束射線來檢測是否對光照效果有作用。由於這一過程也是一個循環進行的過程,因此在計算上是非常難以實現的。在下麵的討論中,我們將主要考慮解決多個漫反射表麵的照明問題。
綜上所述,光線跟蹤算法是計算機圖形學中一個十分重要的方法,它對計算量的要求使得它在一些有較多交互性要求的任務中的可用性大大降低。然而當我們將場景視覺效果放在首要位置,而又沒有交互性存在時,這種方法是非常有效的。
8.5、輻射度 在前麵的討論中,光線跟蹤通常都忽略了漫反射表麵的影響,或者有時又太精確了一些,而我們通常又都使用一個環境光常量來對這種影響進行補充。然而,在許多實際情況下,這些影響又往往是非常重要的。例如,考慮圖8.20中一個完全的漫反射表麵B。它的方向背對著圖中唯一的一個光源,這樣, 根據漫反射照明模型,除非是有環境光存在,否則它將是漆黑的。在表麵B的旁邊還有一個漫反射表麵A,而在實際情況下,A反射的光線總會有一些照射到表麵B上,從而將它照亮。
|
圖8.20 漫反射表麵對照明的作用 |
為了解決這一問題,計算機圖形學借鑒了熱轉移理論的一些內容。它的基本思想是,在一個靠近的環境中,能量分布是平衡的。現在我們假定有一個表麵,它既能發出光線又能反射光線,由一個小麵片發出的光線的量我們稱之為麵片的輻射度(radiosity),它等於麵片本身發出的光線加上由其他麵片反射的光線。可以用下式來表示:
公式中,B表示麵片的輻射通量密度,E是它的輻射強度,K表示反射能力。這樣,當場景由一係列的小麵片組成時,我們假定麵片的大小足夠的小,使得穿過麵片的輻射度為一個常量,那麽上麵的公式就可以用下麵的公式來代替:
公式中,
是一個係數,它表示有多少光線從麵片
j到達麵片
i。正如我們所看到的,輻射度方法允許我們對光源和反射表麵進行統一的處理。一個
為非0值的麵片就是一個光源。係數
被稱為構成因子(form factor),它們本質上表示了場景中的幾何體。為了計算構成因子,我們必須要考慮兩個麵片的方向,它們的範圍以及它們是否被其他麵片所遮擋。這是一個十分複雜的幾何問題,但是一旦計算出了構成因子,場景中每一個麵片的輻射度都可以通過解一個線性方程式來得到。將所有未知的輻射度B組合在一起,我們可以得到下麵的線性等式:
上麵的公式寫成矩陣形式如下:
要注意,如果使用了單色模型,那麽上麵公式中的每一個元素都是標量,如果使用的是RGB模型,那麽每一個元素都是三維矢量,也就是實際上有三個矩陣等式,分別對應於每個顏色分量。通過解上麵的等式,我們可以得到每個表麵麵片的輻射度,接下來,在繪製每一個麵片時,我們就可以根據輻射度數值來進行場景的可見性處理。
還有一點要注意,那就是我們假設通過每一個麵片的輻射度為一個常量,這實際上是放寬了對條件限製。這種對條件的放寬,它的影響隻有在麵片足夠小時才可以被忽略。這樣,每一個實際的場景都必須要分割成許多小的部分,也就增加了矩陣的大小,當然也增加了求解的時間。但是從另一個方麵來考慮,輻射度僅僅考慮了所有方向上的漫反射,並且它對於觀察者的位置是沒有約束的。因此,當場景中的幾何體和燈光都是靜態的時,我們可以再次使用同樣的輻射度方法來進行計算。
總之,輻射度方法對於提高場景的真實感是非常有用的。但是,在定義中我們可以看到,它沒有考慮到鏡麵反射問題,並且也很難在輻射度方法中加入對它們的計算。通常,我們都將輻射度方法作為光線跟蹤算法之前進行的一個預處理過程。而這樣做也並不是沒有價值的,因為某些鏡麵高光正是由漫反射產生的,而鏡麵反射也可能導致漫反射的產生。由於在這兩個處理過程中實現所有的效果時不現實的,因此許多實際的應用往往隻限於一些普通的效果。
8.6、在世界到屏幕(world to screen)中觀察照明中觀察照明 在世界到屏幕中觀察照明與在屏幕到世界中觀察照明是很不一樣的,它們的效果往往會大打折扣。讓我們回顧一下我們所使用的方法,將圖元投影到屏幕空間來創建一幅虛擬世界的圖象,然後將它們光柵化為圖象位圖,這樣我們就得到了一幅虛擬世界的圖像。在進行光線跟蹤處理時,我們將照明模型應用與世界中每一個可見的點上。在世界到屏幕中觀察照明也可以采用類似的方法。當我們在將一個點放置在圖象中之前對一個圖元進行光柵化處理時,我們可以選擇使用照明模型從而調整像素的顏色。有一些問題會立即顯現出來。一般的世界到屏幕算法以及一些特殊的光柵化算法都要求一定的速度和相應的幀速。這些算法都將處理過程定位在對單個像素的處理上。通過對每個像素進行照明計算,提高了計算的複雜性。第二,在使用從後到前(back to front)光柵化處理方法來計算隱藏表麵時,我們可能會對某些像素重新繪製很多此,這樣,大量的計算量就耗費在了一些無用的像素上。在這方麵,有一些隱麵消除算法已經試圖去避免這些情況的發生。但是,基本的問題仍然是按照每個像素進行光柵化,這樣的計算量還是很大,我們還是需要考慮全局照明效果。
處理局部照明的一般方法是隻對圖元的幾個特殊地方進行照明的計算,而在其它地方進行內插運算,這就叫做圖元的明暗處理。我們已經在第三章中看到了使用內插進行明暗處理的多邊形。對於一些全局照明效果,例如陰影和環境反射,在世界到屏幕進行觀察不會在通用的框架中對它們進行處理,這些都要進行特別的處理才能達到,或者不予考慮。
讓我們先來考慮一些明暗處理算法,之後,我們主要將討論用於計算全局照明效果的一些技術。
|
圖8.21 平麵明暗處理 |
很明顯,明暗處理的類型依賴於所使用的照明模型以及我們準備對一些條件所采取的放寬程度。例如,如果我們假設對多邊形采取統一的照明,我們就可以對每一個多邊形隻計算一個點,然後使用得到的顏色進行光柵化處理。這一過程我們成為環境或平麵明暗處理(ambient or flat shading)(見圖8.21)。在環境照明情況下,上述假設一般都可以實現,但是在漫反射表麵和Bouknight照明模型情況下上述假設隻能在多邊形是一個平麵的情況下在能夠實現,也就是說,對於曲麵它是沒有用的,並且在場景中隻有方向光(所有的光源都有一定的作用距離)也是沒有用的。讓我們回憶一下這個照明模型的公式:
照明依賴於表麵法向量(
)和指向光源的方向矢量(
)。當我們用多邊形來對曲麵進行近似時,法向量不再是一個常量(見圖8.19)。如果又一個點光源的話,那麽在多邊形上指向光源的方向也會發生變化。在這種情況下,如果我們還是假設照明是一個常量的話,就會導致錯誤的結果。但是,由於計算機圖形學是對真實環境的一種再現過程,而不是簡單的進行複製,那麽我們當然可以使用這種有一定失真的結果。
這樣,即使在Bouknight和Phong照明模型情況下,我們仍然可以決定使用環境明暗處理。在後一種情況時,如果我們碰巧在鏡麵高光的位置進行了計算,那麽整個多邊形都將是高光,這樣就會嚴重失真。
使用平麵明暗處理方式的多麵體由於人眼的視覺特性會出現一種馬赫帶效應,我們可以在圖8.21中清楚的看到。盡管每一個多邊形都有統一的顏色,但是在多邊形邊緣的地方,我們感覺到較暗的一邊會變得更暗,而較亮的地方會變得更亮。當亮度有限時,人眼在接收光線時會對相鄰的東西有所抑製。這樣,對較暗一邊光線的接收就會被相鄰的較亮的一邊所抑製,因此就會顯得更暗了。而對較亮一邊光線的接收沒有被它的近鄰所抑製,因此有較亮的信號響應。對於平麵明暗處理,就會出現比較明顯的輪廓,這並不是我們所希望的。
因此,我們還有另外一種方法來提高畫麵質量,它就是
Gouraud明暗處理。這種方法對多邊形的頂點計算照明效果,然後對亮度進行內插。圖8.22顯示了這種方法:
|
圖8.22:Gouraud明暗處理 |
這種明暗處理對於描述漫反射的Bouknight照明模型同樣適用。通過對亮度值進行平滑,它可以將曲麵近似時出現的小塊現象避免掉。
為了計算照明效果,我們首先要找到頂點的法向量。當我們用一些小平麵對曲麵進行近似時,頂點的法向量可以通過對小平麵的法向量求平均的方法來獲得,如下圖所示:
|
圖8.23 使用平麵多邊形來近似曲麵 |
這種明暗處理方法還允許我們模擬漫反射表麵在點光源不均允照明情況下的效果。但是,它並不適合於鏡麵反射和Phong照明模型。根據定義,內插明暗處理方法隻允許在多邊形表麵對亮度進行線性的改變。而鏡麵反射的亮度變化卻是非線性的:
這樣,當鏡麵反射出現在多邊形內部時,我們就會將它完全忽略掉,或者當高光出現在多邊形的頂點處時,使用線性內插就會得到錯誤的結果。和環境明暗處理時的情況類似,當多邊形較小或者對品質的要求較低時,這種方法還是可行的。
當我們需要正確的描繪鏡麵反射效果時,我們就要使用Phong明暗處理方法(不要與Phong照明模型相混淆)。隻用這種算法,可以有效的在每一個光柵像素計算照明模型並對模型的一個成分在多邊形上進行內插。讓我們再看一下上麵的照明模型公式。我們可以看到,計算時要用到法向量,這樣,由於我們經常使用多邊形來近似曲麵,就可以對多邊形的方向量進行內插,然後用它來計算每一點的照明。(見圖8.24 (c))。
|
圖8.24 (a)環境、(b)Gouraud及(c)Phong明暗處理 |
法向量的每一個成分被單獨的進行內插,這樣就會得到多邊形上每個點的近似方向亮。我們必須注意,在計算時使用單位法向量是很重要的。在進行內插時,也要將每一點的法向量進行歸一化。但是,在每一點都使用內插法向量來計算照明,計算量還是很大的。然而,正如在我們第一次考慮照明模型時所看到的那樣,可以使用半程矢量來簡化計算並將觀察者的位置置於無窮遠處。我們可以預先計算好
(或者是替代公式中的
),然後在執行時用表格來進行查詢。
前麵介紹的明暗處理方法允許我們在世界到屏幕觀察框架中引入照明模型。但是,場景中多個物體的出現可能會要用到其它的一些照明效果,如陰影、環境反射等。我們還需要解決前麵討論過的漫反射表麵的相互照明問題。輻射度算法可以用於對世界到屏幕進行預先處理。當場景中的幾何體和照明不隨幀的變化而變化時,它還可以在多個幀中多次使用,例如我們要產生一個飛躍的虛擬場景時。通常,當要求場景中的物體有一定的交互性時,在運行期間計算其它全局照明效果將很難實現,因此就需要對它們進行預先的處理。
在所有的全局照明效果中,我們將隻討論陰影和環境反射。計算陰影有許多種算法。我們通常將它們分為兩組。第一組預先計算描繪陰影所需的幾何信息。第二組在場景光柵化時計算動態陰影效果。因此,前一組算法是不能計算變化場景的動態效果的。
有兩種方法來預先計算陰影。最常用的一個是將場景細分為許多部分,使得對於每一個點光源每個圖元都能被完全照亮或者完全隱藏。另一種方法在紋理中存儲陰影信息。後一種方法需要對每一個圖元都設置一幅特殊的紋理,因此在有些情況下時不可行的。
預先計算陰影,我們就要解決可見性問題。在光源處可見的圖元部分是可以被照亮的,而其它部分就應該有陰影存在。圖8.25描繪了一個陰影域。
|
圖8.25 陰影域 |
如圖中所示,被照亮的多邊形在空間中產生了一定的陰影範圍。這個範圍形成了一個多麵體,陰影有它的頂部開始產生,位於這個多麵體內的多邊形部分都是有陰影的。而其它的多邊形都可以被這個多麵體裁剪為兩個部分,一部分完全是陰影,另一部分則完全被照亮。被照亮的多邊形還要標明是被哪個光源照亮的,這樣在進行光柵化處理時,就可以明確知道每個多邊形是由哪個光源照亮的。
這種劃分是非常複雜的,但是我們可以利用合成場景的一些特性來減少計算量。例如,一個多邊形往往都是一個物體中的一部分,這樣,我們就可以直接對這個物體使用陰影範圍來進行分割。減少陰影範圍的數量也可以減少處理量。我們還必須明白,這種方法隻是運行前的一個預處理步驟。這樣,減少分割的數量就要比性能更重要。
使用BSP樹算法來計算陰影範圍是很有效的。使用BSP樹,我們可以很容易得到按照從後到前順序排列的多邊形。同樣,也很容易得到從前到後的順序。我們必須在循環調用時將順序翻轉過來。對於某個光源的一個從前到後的順序顯示了哪個多邊形能夠為其它多邊形產生陰影。很明顯,在前麵的多邊形會對後麵的多邊形產生陰影,這樣,列表中的多邊形會對它後麵的多邊形產生陰影,但是不會影響到其它分支的多邊形。我們可以使用陰影範圍算法並沿著列表執行必要的分割。當我們將任何一個多邊形分為陰影區和照亮區之後,所有的這些區域仍然屬於同一個平麵,並且可以被聯合存儲在樹中原先的地方。
其它產生陰影的算法也包括了解決可見性的問題 。陰影Z-buffer算法(shadow Z-buffer)是對一般隱麵消除算法的擴展。見圖8.26。
|
圖8.26 陰影Z-buffer |
在圖8.26中,有兩個Z-buffer,其中一個稱為光線Z-buffer。如果我們在渲染場景之前計算光線Z-buffer,我們可以調整真正的基於光柵的Z-buffer使它能夠解決陰影。當我們要將一個點放置在屏幕上和Z-buffer中時,我們可以找到它在光源前麵的平麵上的投影,並檢查這個投影的Z坐標是否是存儲在光線Z-buffer中的那個。如果真是這樣的話,這個點對於光源就是可見的, 我們就可以在主圖象中對這個進行照明。例如在圖8.26中的點A。當我們檢查它對光源的可見性時,我們在光線Z-buffer中定位一個比遮擋點的Z坐標較小的位置。這樣,點A就有陰影。另一方麵,點B就不是這樣,我們在對它進行光柵化時就要考慮它的照明問題。
這個算法的一個明顯的缺點是要對每一個光源都定義一個光線Z-buffer。同時,將額外的處理過程引入光柵化的內部循環中,提高了程序的複雜性,但是由於自身的特性,Z-buffer算法經常會覆蓋掉一些像素先前的值。這樣,我們可能會對一些不會在最終的圖象中描繪出來的點來計算它的照明和陰影。解決這一問題的一個方法是先對圖象進行光柵化處理然後加入陰影計算。這樣,我們就隻對出現在最終圖象中的點才計算它的陰影信息。還必須注意,由於照明模型是附加的,我們可以對所有的光源暗中使用同一個光線Z-buffer。
在光線跟蹤部分,我們已經討論過使用正規的光線跟蹤框架來解決環境鏡麵反射問題。本質上,我們在鏡麵反射的方向上解決可見性問題從而找到由一個光亮表麵產生的環境反射。同樣,我們在一個不同的框架中也可以實現世界到屏幕的觀察。見圖8.27。
|
圖8.27 計算環境映射 |
圖8.27描繪了一個鏡麵反射麵片。很明顯,由於它的鏡麵反射能力,這個麵片可以顯現出環境的反射。因為反射方向與入射光線關於法向量成鏡像關係,所以我們可以假想一個觀察者(如圖中所示),根據它來計算一個單獨的圖像,然後將這幅圖象一紋理的形式應用到原始觀察的處理過程中。
觀察算法的多重引用是很耗費計算量的,因此,我們可以預先計算好環境反射並保存在紋理信息中。必須注意,一般的紋理映射是與觀察無關的,而環境映射卻是與觀察有關係的。當觀察方向改變時,我們就要調整紋理映射使它隨之改變,這樣才不會影響場景的真實感。這種方法在幾何關係上不一定是正確的,但卻能使我們感受到環境反射的效果。
在有些情況下,我們可能需要動態的並且幾何關係也是正確的反射效果,比如場景中的一麵鏡子。這樣,才能對場景中的鏡子進行正確的模擬。(見圖8.28)