第2部份: 3d環境的光照和紋理
世界的燈光
在變換過程中, 通常是在稱為觀察空間的座標空間中, 我們遇到了最重要的運算之一: 光照計算。 它是一種這樣的事情, 當它工作時,你不關注它,但當它不工作時, 你就非常關注它了。有很多不同的光照方法,從簡單的計算多邊形對於燈光的朝向,並根據燈光到多邊形的方向和距離加上燈光顏色的百分比值,一直到產生邊緣平滑的燈光貼圖疊加基本紋理。而且一些 api 實際上提供預先建造的光照方法。舉例來說,opengl 提供了每多邊形,每頂點,和每畫素的光照計算。
在頂點光照中,你要決定乙個頂點被多少個多邊形共享,並計算出共享該頂點的所有多邊形法向量的均值(稱為法向量),並將該法向量賦頂點。乙個給定多邊形的每個頂點會有不同的法向量,所以你需要漸變或插值多邊形頂點的光照顏色以便得到平滑的光照效果。 你沒有必要用這種光照方式檢視每個單獨的多邊形。 這種方式的優點是時常可以使用硬體轉換與光照(t & l)來幫助快速完成。 不足之處是它不能產生陰影。 舉例來說,即使燈光是在模型的右側,左手臂應該在被身體投影的陰影中,而實際上模型的雙臂卻以同樣的方式被照明了。
這些簡單的方法使用著色來達到它們的目標。 當用平面光照繪製乙個多邊形時, 你讓渲染(繪製)引擎把整個多邊形都著上一種指定的顏色。這叫做平面著色光照。 (該方法中,多邊形均對應乙個光強度,表面上所有點都用相同的強度值顯示,渲染繪製時得到一種平面效果,多邊形的邊緣不能精確的顯示出來) 。
對於頂點著色 ( gouraud 著色) ,你讓渲染引擎給每個頂點賦予特定的顏色。 在繪製多邊形上各點投影所對應的畫素時,根據它們與各頂點的距離,對這些頂點的顏色進行插值計算。 (實際上quake iii 模型使用的就是這種方法, 效果好的令人驚奇)。
還有就是 phong 著色。如同 gouraud 著色,通過紋理工作,但不對每個頂點顏色進行插值決定畫素顏色值, 它對每個頂點的法向量進行插值,會為每個頂點投影的畫素做相同的工作。對於 gouraud 著色,你需要知道哪些光投射在每個頂點上。對於 phong 著色,你對每個畫素也要知道這麼多。
一點也不令人驚訝, phong 著色可以得到更加平滑的效果,因為每個畫素都需要進行光照計算,其繪製非常耗費時間。平面光照處理方法很快速, 但比較粗糙。phong 著色比 gouraud 著色計算更昂貴,但效果最好,可以達到鏡面高光效果("高亮")。 這些都需要你在遊戲開發中折衷權衡。
不同的燈光
接著是生成照明對映,你用第二個紋理對映(照明對映)與已有的紋理混合來產生照明效果。這樣工作得很好, 但這本質上是在渲染之前預先生成的一種罐裝效果。如果你使用動態照明 (即,燈光移動, 或者沒有程式的干預而開啟和關閉),你得必須在每一幀重新生成照明對映,按照動態燈光的運動方式修改這些照明對映。燈光對映能夠快速的渲染,但對儲存這些燈光紋理所需的記憶體消耗非常昂貴。你可以使用一些壓縮技巧使它們占用較少的的記憶體空間,或減少其尺寸大小, 甚至使它們是單色的 (這樣做就不會有彩色燈光了),等等。 如果你確實在場景中有多個動態燈光, 重新生成照明對映將以昂貴的cpu週期而告終。
許多遊戲通常使用某種混合照明方式。 以quake iii為例,場景使用照明對映, 動畫模型使用頂點照明。 預先處理的燈光不會對動畫模型產生正確的效果 -- 整個多邊形模型得到燈光的全部光照值 -- 而動態照明將被用來產生正確的效果。 使用混合照明方式是多數的人們沒有注意到的乙個折衷,它通常讓效果看起來"正確"。 這就是遊戲的全部 – 做一切必要的工作讓效果看起來"正確",但不必真的是正確的。
當然,所有這些在新的doom引擎裡面都不復存在了,但要看到所有的效果,至少需要 1ghz cpu 和 geforce 2 顯示卡。是進步了,但一切都是有代價的。
一旦場景經過轉換和照明, 我們就進行裁剪運算。 不進入血淋淋的細節而,剪斷運算決定哪些三角形完全在場景 (被稱為觀察平截頭體) 之內或部份地在場景之內。完全在場景之內的三角形被稱為細節接受,它們被處理。對於只是部分在場景之內的三角形, 位於平截頭體外面的部分將被裁剪掉,餘下位於平截頭體內部的多邊形部分將需要重新閉合,以便其完全位於可見場景之內。 (更多的細節請參考我們的 3d 流水線指導一文)。
場景經過裁剪以後,流水線中的下乙個階段就是三角形生成階段(也叫做掃瞄 線轉換),場景被對映到2d 螢幕座標。到這裡,就是渲染(繪製)運算了。
紋理與mip對映
紋理在使3d場景看起來真實方面異常重要,它們是你應用到場景區域或物件的一些分解成多邊形的小。多重紋理耗費大量的記憶體,有不同的技術來幫助管理它們的尺寸大小。紋理壓縮是在保持資訊的情況下,讓紋理資料更小的一種方法。紋理壓縮占用較少的遊戲cd空間,更重要的是,占用較少記憶體和3d 顯示卡儲存空間。另外,在你第一次要求顯示卡顯示紋理的時候,壓縮的(較小的) 版本經過 agp 介面從 pc 主存送到3d 顯示卡, 會更快一些。紋理壓縮是件好事情。 在下面我們將會更多的討論紋理壓縮。
mip 對映(多紋理對映)
遊戲引擎用來減少紋理記憶體和頻寬需求的另外乙個技術就是 mip 對映。 mip 對映技術通過預先處理紋理,產生它的多個拷貝紋理,每個相繼的拷貝是上乙個拷貝的一半大小。為什麼要這樣做?要回答這個問題,你需要了解 3d 顯示卡是如何顯示紋理的。最壞情況,你選擇乙個紋理,貼到乙個多邊形上,然後輸出到螢幕。我們說這是一對一的關係,最初紋理對映圖的乙個紋素 (紋理元素) 對應到紋理對映物件多邊形的乙個畫素。如果你顯示的多邊形被縮小一半,紋理的紋素就每間隔乙個被顯示。這樣通常沒有什麼問題 -- 但在某些情況下會導致一些視覺上的怪異現象。讓我們看看磚塊牆壁。 假設最初的紋理是一面磚牆,有許多磚塊,磚塊之間的泥漿寬度只有乙個畫素。如果你把多邊形縮小一半, 紋素只是每間隔乙個被應用,這時候,所有的泥漿會突然消失,因為它們被縮掉了。你只會看到一些奇怪的影象。
使用 mip 對映,你可以在顯示卡應用紋理之前,自己縮放影象,因為可以預先處理紋理,你做得更好一些,讓泥漿不被縮掉。當 3d 顯示卡用紋理繪製多邊形時,它檢測到縮放因子,說,"你知道,我要使用小一些的紋理,而不是縮小最大的紋理,這樣看起來會更好一些。" 在這裡, mip 對映為了一切,一切也為了 mip 對映。
多重紋理與凹凸對映
單一紋理對映給整個3d 真實感圖形帶來很大的不同, 但使用多重紋理甚至可以達到一些更加令人難忘的效果。過去這一直需要多遍渲染(繪製),嚴重影響了畫素填充率。 但許多具有多流水線的3d 加速卡,如ati's radeon 和 nvidia's geforce 2及更高階的顯示卡,多重紋理可以在一遍渲染(繪製)過程中完成。 產生多重紋理效果時, 你先用乙個紋理繪製多邊形,然後再用另外乙個紋理透明地繪製在多邊形上面。這讓你可以使紋理看上去在移動,或脈動, 甚至產生陰影效果 (我們在照明一節中描述過)。繪製第乙個紋理對映,然後在上面繪製帶透明的全黑紋理,引起一種是所有的織法黑色的但是有乙個透明分層堆積過它的頂端 , 這就是 -- 即時陰影。 該技術被稱為照明對映 ( 有時也稱為 暗對映),直至新的doom ,一直是id引擎裡關卡照明的傳統方法。
凹凸貼圖是最近湧現出來的一種古老技術。幾年以前 matrox 第乙個在流行的 3d 遊戲中發起使用各種不同形式的凹凸貼圖。就是生成紋理來表現燈光在表面的投射,表現表面的凹凸或表面的裂縫。 凹凸貼圖並不隨著燈光一起移動 -- 它被設計用來表現乙個表面上的細小瑕疵,而不是大的凹凸。 比如說,在飛行模擬器中,你可以使用凹凸貼圖來產生像是隨機的地表細節,而不是重複地使用相同的紋理,看上去一點趣味也沒有。
凹凸貼圖產生相當明顯的表面細節,儘管是很高明的戲法,但嚴格意義上講,凹凸貼圖並不隨著你的觀察角度而變化。比較新的 ati 和 nvidia 顯卡片能執行每畫素運算,這種預設觀察角度的不足就真的不再是有力而快速的法則了。 無論是哪一種方法, 到目前為止,沒有遊戲開發者太多的使用; 更多的遊戲能夠且應該使用凹凸貼圖。
快取記憶體抖動 = 糟糕的事物
遊戲引擎剖析(六)
第6部分 聲音系統,音訊apis 聲音系統 現在有一些很少有處理的聲音空間化問題。我說的是把聲音放在乙個真實的3d世界中。有四個揚聲器在你周圍是乙個很棒的開始,但這仍然只是在二維方向。在你的上方和下方沒有揚聲器,你沒有真正獲得3d聲音。有一些聲音調製過濾器試 決這個問題,但實際上沒有真實東西的代替物...
遊戲引擎剖析(四)
第4部份 模型與動畫,細節級別 角色建模與動畫 你的角色模型在螢幕上看起來怎麼樣,怎樣容易建立它們,紋理,以及動畫對於現代遊戲試圖完成的 消除不可信 因素來說至關重要。角色模型系統逐漸變得複雜起來,包括較高的多邊形數量模型,和讓模型在螢幕上移動的更好方式。如今你需要乙個骨骼模型系統,有骨架和網格細節...
遊戲引擎剖析(七)
第7部份 網路和連線遊戲環境 網路遊戲 我記得一些年前坐在gdc 遊戲開發者大會 聽負責開發x wing vs tie fighter的傢伙們題為 淹沒在internet 的演講,全是關於讓網路遊戲實時地在internet上工作的東西。他們選擇那個題目是多麼的正確啊。當它開始處理資料報的丟失,亂序,...