【hotball技術小舖】doom 3的打光系統簡介
(2004-10-21)
陳秉哲】
陰影的產生
經過漫長的等待,id software 終於在今年八月正式推出doom 3。雖然doom 3在遊戲性上,和過去的doom系列遊戲並沒有太大的不同,但是doom 3引擎則是乙個完全不同、全新的設計。doom 3引擎最大的特色,就在於它的打光系統。它結合了完整的陰影和凹凸貼圖,並號稱使用一致的打光模型,對整個場景中的所有物體一視同仁。它產生的效果相當理想,也為3d引擎又設下了乙個新的里程碑。
大家都知道,陰影就是光線沒有照射到的地方。換句話說,如果乙個地方,和光源之間有東西擋住,那它就會在陰影中。從物理的角度來看,其實是剛好相反的:有光線照射到的地方,就會反射光線。因此,它會比沒有被光線照射的地方,要顯得更亮。不管用什麼角度來看,陰影都不是只和某個物體有關,整個場景都會對陰影產生影響。
因此,要在3d繪圖中,產生正確的陰影,就需要考慮到整個場景。這和一般對物體進行打光、著色的動作有很大的差別。一般3d繪圖中,物體的顏色、亮度等等的變化,只和物體本身,以及光源的位置有關係(有時和觀察者的位置也有關係)。它並不會牽扯到其它的物體。因此,它的效果是區域性的。但是,陰影的效果則是整體的,因為隨著光源位置改變,任何物體都有可能遮住另乙個物體,而產生陰影。也因此,要正確地畫出陰影,是乙個相當困難的問題。
障礙物在球體上產生陰影。
使用3d繪圖晶元產生陰影
一般3d繪圖晶元,是針對「區域性」的打光效果設計的。3d晶元上並沒有保留整個場景的三角面資料,它只是對目前送進來的三角面進行著色的動作。因此,在一般的情形下,3d晶元並不能自行判斷出,乙個三角面是否被別的三角面遮住,而使它在陰影中。
不過,雖然如此,3d晶元還是得處理一些「整體性」的工作。最簡單的例子,就是處理隱藏面問題。在進行3d繪圖的時候,離觀察者較近的物體,會遮住較遠的物體。因此,3d晶元需要能判斷出,哪些三角面會被哪些三角面遮住。由於3d晶元並不保留任何三角面的資料,因此,它並不能去檢視之前所畫的三角面是否會遮住目前所畫的三角面。為了解決這個問題,目前的3d晶元,通常是使用z buffer。這樣一來,3d晶元就可以避免以三角面為單位來進行隱藏面的判斷,而是以pixel為單位進行。
可以看出,陰影的問題,和消除隱藏面的問題,其實是十分類似的。如果把觀察者的位置到在光源的位置,把整個場景畫過一次,就可以知道哪些物體是被光源直接照射到的,也就是會反射光線,較亮的物體。相對的,沒有被直接照射到的物體,當然就是在陰影中了。這個方法其實就是shadow map的基本原理。不過,shadow map還有許多麻煩的問題要克服,而且doom 3也不是使用這個方法,因此這裡就不再多做討論。但是shadow map的前景看好,最近推出的3dmark05主要就是使用shadow map來產生陰影。shadow map也有比較簡單的版本,但是它並不能用在整個場景上面。
doom 3使用的是所謂的volumetric shadow,或稱為stencil shadow(因為volumetric shadow通常需要使用到stencil buffer)。volumetric shadow的基本原理,是讓所有的物體「投射」出陰影。被「投射」到的物體,就是在陰影中。相反的,沒有被「投射」到的物體,就是被光源直接照射,會反光的部份。volumetric shadow和shadow map方式最大的不同,是shadow map基本上是由pixel組成,但是volumetric shadow則直接在三角面上進行處理,而不是把物體看成乙個乙個的pixel。
volumetric shadow
volumetric shadow的基本方式,是先找出物體的外框。接著,再從外框延伸出乙個"volume"。這個volume就是陰影的範圍,也可以稱為shadow volume。任何在這個volume內部的pixel,就是在陰影裡面。因此,問題就變成,要如何判斷乙個pixel是否在volume裡面。這就是 stencil buffer發揮作用的地方。
stencil buffer有點類似z buffer,它為每個pixel記錄乙個數字。在畫三角麵時,可以指定要進行某個運算,例如把數字加
一、減一等等。另外,也可以指定在畫三角麵時,只處理stencil數字在某個值的pixel。例如,可以要求只畫在stencil值是0的pixel,其它的pixel則不畫。
volumetric shadow 示意圖。
要利用stencil buffer來判斷哪些pixel在shadow volume中,首先要把每個pixel的stencil值清為0。接著,畫出所有的三角面的shadow volume中,正對著觀察者的部份(上圖的白色部份),同時,把stencil設成「加一」。這樣一來,所有在shadow volume後面的pixel(包括shadow volume裡面),其stencil值都會是正數。接著,再畫出shadow volume中,背對觀察者的部份,但這次把stencil 設成「減一」。這樣一來,在shadow volume後面,但是卻不在shadow volume中的pixel,其stencil值會回到0,但是在shadow volume中的pixel的stencil值則還是正數。這樣一來,就可以用每個pixel的stencil值,來判斷它是否在陰影中了。
雖然volumetric shadow的基本原理就是這樣,但是實際上卻還有很多問題。最明顯的問題,是當觀察者跑到shadow volume裡面的時候,volumetric shadow就會出錯。另外,在3d繪圖時,通常都會設定乙個z clip plane,限制場景繪圖的範圍,但是如果切到shadow volume,則會產生空洞,而造成問題。因此,許多人發展出各種方法,設法解決這些問題。其中,最有效的方法是carmack's reverse,是由id software的john carmack提出的(其中也有許多其他人的貢獻)。這個方法是利用反轉z buffer測試的方式,使觀察者永遠不可能出現在shadow volume裡面。這樣就解決了第乙個問題。第二個問題的解決方法,則可以透過取消遠端的z clip plane來解決,不過這樣可能較缺乏效率。另乙個方法,則是由顯示晶元在硬體上,針對z clip plane進行處理,使shadow volume在z clip plane上可以自動封住shadow volume,使它不會產生空洞。
經過這些改進,volumetric shadow變成乙個相當可靠的方法。由於它是以三角面為基礎,因此它非常精確,不像shadow map等方法會有解析度不足的問題。而且,它並不需要很多特別的硬體支援,只需要stencil buffer。stencil buffer是opengl的標準功能,因此許多3d晶元都有支援。這想必也對id software決定在doom 3中使用volumetric shadow有一定的影響。
不過,volumetric shadow並非全無缺點。它最大的問題,是在繪製shadow volume時,會吃掉大量的fillrate。而且,由於shadow volume是由物體的3d模型的外框所產生的,而要計算外框,就需要處理器進行處理(這個工作並不適合由顯示晶元進行)。這會增加處理器的運算量。它也無法用在利用具有透明區域的貼圖的物體上,有些遊戲使用這樣的貼圖來繪製複雜的物體,像是樹木。最後,voluemtric shadow 產生的陰影都非常銳利,但真實世界中的陰影通常都有些模糊。這是因為真實世界中的光源都不是乙個小點,而是具有某個大小。要使用volumetric shadow產生模糊的陰影,可以用多個靠近的點光源來模擬乙個具有大小的光源,但是這樣當然就會更慢了。這些都是shadow volume的主要問題。
凹凸貼圖
結語doom 3是id software乙個相當大膽的嘗試。id software試圖在doom 3中達到「所有的東西也都產生陰影」的終極目標,因此大量使用了volumetric shadow。另外,幾乎所有的東西都使用凹凸貼圖,其打光效果相當不錯。但是,這也對顯示卡和處理器造成了很大的負擔。由於doom 3本身的遊戲性並不特別出色,因此,其它遊戲公司會不會願意使用doom 3引擎來開發遊戲,就成為doom 3能不能成功的乙個重要關鍵。
另類觀點:什麼是shadow map?
文⊙劉人豪(夜露死苦技術專欄)
裝個電腦玩DOOM3
這幾天準備買電腦,搞的焦頭爛額,雖然這五六年給別人裝的機子也有幾十台了,可是到了自己裝,還是要費些功夫的,主要是用有限的錢換取最大的效能,哈哈 主要考慮到要機子不超過4500,又想嘗試一下doom3,所以這個配置就難了,權衡了很久最後選定了這個配置 配件類別 產品名稱 數量當時 上海 cpuamd ...
DOOM3 命令系統分析
doom3命令系統中,重要的類有ideventdef負責管理命令的註冊宣告,idevent是命令 物件。該命令系統主要資料結構有 eventdeflist freeevents,eventqueue,eventpool 其中eventpool是乙個宣告為 idevent 的 4096個物件的陣列,該...
機器學習 3(k 進鄰演算法簡介)
先簡單介紹一下k 進鄰演算法 採用測量不同特徵值之間的距離方法進行分類,ok,它是屬於監督學習了 優點 精度高,對異常值不敏感,無資料輸入假定 缺點 計算複雜度高,空間複雜度高 適用資料範圍 數值型和標稱型 在介紹這個演算法之前,先介紹一點基礎的數學概念,這個是會在後面用到的,我這裡就盡量用白話給大...