游戲引擎剖析(二)
發(fā)表時(shí)間:2024-06-09 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]原文作者:Jake Simpson 譯者: 向海 Email:GameWorldChina@myway.com 第2部份: 3D環(huán)境的光照和紋理 世界的燈光 在變換過(guò)程中, 通常是在稱為觀察空間的坐標(biāo)空間中, 我們遇到了最重要的運(yùn)算之一: 光照計(jì)算。 它是一種這樣的事情, 當(dāng)它工作時(shí),你不關(guān)...
原文作者:Jake Simpson
譯者: 向海
Email:GameWorldChina@myway.com
第2部份: 3D環(huán)境的光照和紋理
世界的燈光
在變換過(guò)程中, 通常是在稱為觀察空間的坐標(biāo)空間中, 我們遇到了最重要的運(yùn)算之一: 光照計(jì)算。 它是一種這樣的事情, 當(dāng)它工作時(shí),你不關(guān)注它,但當(dāng)它不工作時(shí), 你就非常關(guān)注它了。有很多不同的光照方法,從簡(jiǎn)單的計(jì)算多邊形對(duì)于燈光的朝向,并根據(jù)燈光到多邊形的方向和距離加上燈光顏色的百分比值,一直到產(chǎn)生邊緣平滑的燈光貼圖疊加基本紋理。而且一些 API 實(shí)際上提供預(yù)先建造的光照方法。舉例來(lái)說(shuō),OpenGL 提供了每多邊形,每頂點(diǎn),和每像素的光照計(jì)算。
在頂點(diǎn)光照中,你要決定一個(gè)頂點(diǎn)被多少個(gè)多邊形共享,并計(jì)算出共享該頂點(diǎn)的所有多邊形法向量的均值(稱為法向量),并將該法向量賦頂點(diǎn)。一個(gè)給定多邊形的每個(gè)頂點(diǎn)會(huì)有不同的法向量,所以你需要漸變或插值多邊形頂點(diǎn)的光照顏色以便得到平滑的光照效果。 你沒(méi)有必要用這種光照方式查看每個(gè)單獨(dú)的多邊形。 這種方式的優(yōu)點(diǎn)是時(shí)?梢允褂糜布D(zhuǎn)換與光照(T & L)來(lái)幫助快速完成。 不足之處是它不能產(chǎn)生陰影。 舉例來(lái)說(shuō),即使燈光是在模型的右側(cè),左手臂應(yīng)該在被身體投影的陰影中,而實(shí)際上模型的雙臂卻以同樣的方式被照明了。
這些簡(jiǎn)單的方法使用著色來(lái)達(dá)到它們的目標(biāo)。 當(dāng)用平面光照繪制一個(gè)多邊形時(shí), 你讓渲染(繪制)引擎把整個(gè)多邊形都著上一種指定的顏色。這叫做平面著色光照。 (該方法中,多邊形均對(duì)應(yīng)一個(gè)光強(qiáng)度,表面上所有點(diǎn)都用相同的強(qiáng)度值顯示,渲染繪制時(shí)得到一種平面效果,多邊形的邊緣不能精確的顯示出來(lái)) 。
對(duì)于頂點(diǎn)著色 ( Gouraud 著色) ,你讓渲染引擎給每個(gè)頂點(diǎn)賦予特定的顏色。 在繪制多邊形上各點(diǎn)投影所對(duì)應(yīng)的像素時(shí),根據(jù)它們與各頂點(diǎn)的距離,對(duì)這些頂點(diǎn)的顏色進(jìn)行插值計(jì)算。 (實(shí)際上Quake III 模型使用的就是這種方法, 效果好的令人驚奇)。
還有就是 Phong 著色。如同 Gouraud 著色,通過(guò)紋理工作,但不對(duì)每個(gè)頂點(diǎn)顏色進(jìn)行插值決定像素顏色值, 它對(duì)每個(gè)頂點(diǎn)的法向量進(jìn)行插值,會(huì)為每個(gè)頂點(diǎn)投影的像素做相同的工作。對(duì)于 Gouraud 著色,你需要知道哪些光投射在每個(gè)頂點(diǎn)上。對(duì)于 Phong 著色,你對(duì)每個(gè)像素也要知道這么多。
一點(diǎn)也不令人驚訝, Phong 著色可以得到更加平滑的效果,因?yàn)槊總(gè)像素都需要進(jìn)行光照計(jì)算,其繪制非常耗費(fèi)時(shí)間。平面光照處理方法很快速, 但比較粗糙。Phong 著色比 Gouraud 著色計(jì)算更昂貴,但效果最好,可以達(dá)到鏡面高光效果("高亮")。 這些都需要你在游戲開(kāi)發(fā)中折衷權(quán)衡。
不同的燈光
接著是生成照明映射,你用第二個(gè)紋理映射(照明映射)與已有的紋理混合來(lái)產(chǎn)生照明效果。這樣工作得很好, 但這本質(zhì)上是在渲染之前預(yù)先生成的一種罐裝效果。如果你使用動(dòng)態(tài)照明 (即,燈光移動(dòng), 或者沒(méi)有程序的干預(yù)而打開(kāi)和關(guān)閉),你得必須在每一幀重新生成照明映射,按照動(dòng)態(tài)燈光的運(yùn)動(dòng)方式修改這些照明映射。燈光映射能夠快速的渲染,但對(duì)存儲(chǔ)這些燈光紋理所需的內(nèi)存消耗非常昂貴。你可以使用一些壓縮技巧使它們占用較少的的內(nèi)存空間,或減少其尺寸大小, 甚至使它們是單色的 (這樣做就不會(huì)有彩色燈光了),等等。 如果你確實(shí)在場(chǎng)景中有多個(gè)動(dòng)態(tài)燈光, 重新生成照明映射將以昂貴的CPU周期而告終。
許多游戲通常使用某種混合照明方式。 以Quake III為例,場(chǎng)景使用照明映射, 動(dòng)畫(huà)模型使用頂點(diǎn)照明。 預(yù)先處理的燈光不會(huì)對(duì)動(dòng)畫(huà)模型產(chǎn)生正確的效果 -- 整個(gè)多邊形模型得到燈光的全部光照值 -- 而動(dòng)態(tài)照明將被用來(lái)產(chǎn)生正確的效果。 使用混合照明方式是多數(shù)的人們沒(méi)有注意到的一個(gè)折衷,它通常讓效果看起來(lái)"正確"。 這就是游戲的全部 – 做一切必要的工作讓效果看起來(lái)"正確",但不必真的是正確的。
當(dāng)然,所有這些在新的Doom引擎里面都不復(fù)存在了,但要看到所有的效果,至少需要 1GHZ CPU 和 GeForce 2 顯卡。是進(jìn)步了,但一切都是有代價(jià)的。
一旦場(chǎng)景經(jīng)過(guò)轉(zhuǎn)換和照明, 我們就進(jìn)行裁剪運(yùn)算。 不進(jìn)入血淋淋的細(xì)節(jié)而,剪斷運(yùn)算決定哪些三角形完全在場(chǎng)景 (被稱為觀察平截頭體) 之內(nèi)或部份地在場(chǎng)景之內(nèi)。完全在場(chǎng)景之內(nèi)的三角形被稱為細(xì)節(jié)接受,它們被處理。對(duì)于只是部分在場(chǎng)景之內(nèi)的三角形, 位于平截頭體外面的部分將被裁剪掉,余下位于平截頭體內(nèi)部的多邊形部分將需要重新閉合,以便其完全位于可見(jiàn)場(chǎng)景之內(nèi)。 (更多的細(xì)節(jié)請(qǐng)參考我們的 3D 流水線指導(dǎo)一文)。
場(chǎng)景經(jīng)過(guò)裁剪以后,流水線中的下一個(gè)階段就是三角形生成階段(也叫做掃描 線轉(zhuǎn)換),場(chǎng)景被映射到2D 屏幕坐標(biāo)。到這里,就是渲染(繪制)運(yùn)算了。
紋理與MIP映射
紋理在使3D場(chǎng)景看起來(lái)真實(shí)方面異常重要,它們是你應(yīng)用到場(chǎng)景區(qū)域或?qū)ο蟮囊恍┓纸獬啥噙呅蔚男D片。多重紋理耗費(fèi)大量的內(nèi)存,有不同的技術(shù)來(lái)幫助管理它們的尺寸大小。紋理壓縮是在保持圖片信息的情況下,讓紋理數(shù)據(jù)更小的一種方法。紋理壓縮占用較少的游戲CD空間,更重要的是,占用較少內(nèi)存和3D 顯卡存儲(chǔ)空間。另外,在你第一次要求顯卡顯示紋理的時(shí)候,壓縮的(較小的) 版本經(jīng)過(guò) AGP 接口從 PC 主存送到3D 顯卡, 會(huì)更快一些。紋理壓縮是件好事情。 在下面我們將會(huì)更多的討論紋理壓縮。
MIP 映射(多紋理映射)
游戲引擎用來(lái)減少紋理內(nèi)存和帶寬需求的另外一個(gè)技術(shù)就是 MIP 映射。 MIP 映射技術(shù)通過(guò)預(yù)先處理紋理,產(chǎn)生它的多個(gè)拷貝紋理,每個(gè)相繼的拷貝是上一個(gè)拷貝的一半大小。為什么要這樣做?要回答這個(gè)問(wèn)題,你需要了解 3D 顯卡是如何顯示紋理的。最壞情況,你選擇一個(gè)紋理,貼到一個(gè)多邊形上,然后輸出到屏幕。我們說(shuō)這是一對(duì)一的關(guān)系,最初紋理映射圖的一個(gè)紋素 (紋理元素) 對(duì)應(yīng)到紋理映射對(duì)象多邊形的一個(gè)像素。如果你顯示的多邊形被縮小一半,紋理的紋素就每間隔一個(gè)被顯示。這樣通常沒(méi)有什么問(wèn)題 -- 但在某些情況下會(huì)導(dǎo)致一些視覺(jué)上的怪異現(xiàn)象。讓我們看看磚塊墻壁。 假設(shè)最初的紋理是一面磚墻,有許多磚塊,磚塊之間的泥漿寬度只有一個(gè)像素。如果你把多邊形縮小一半, 紋素只是每間隔一個(gè)被應(yīng)用,這時(shí)候,所有的泥漿會(huì)突然消失,因?yàn)樗鼈儽豢s掉了。你只會(huì)看到一些奇怪的圖像。
使用 MIP 映射,你可以在顯示卡應(yīng)用紋理之前,自己縮放圖像,因?yàn)榭梢灶A(yù)先處理紋理,你做得更好一些,讓泥漿不被縮掉。當(dāng) 3D 顯卡用紋理繪制多邊形時(shí),它檢測(cè)到縮放因子,說(shuō),"你知道,我要使用小一些的紋理,而不是縮小最大的紋理,這樣看起來(lái)會(huì)更好一些。" 在這里, MIP 映射為了一切,一切也為了 MIP 映射。
多重紋理與凹凸映射
單一紋理映射給整個(gè)3D 真實(shí)感圖形帶來(lái)很大的不同, 但使用多重紋理甚至可以達(dá)到一些更加令人難忘的效果。過(guò)去這一直需要多遍渲染(繪制),嚴(yán)重影響了像素填充率。 但許多具有多流水線的3D 加速卡,如ATI's Radeon 和 nVidia's GeForce 2及更高級(jí)的顯卡,多重紋理可以在一遍渲染(繪制)過(guò)程中完成。 產(chǎn)生多重紋理效果時(shí), 你先用一個(gè)紋理繪制多邊形,然后再用另外一個(gè)紋理透明地繪制在多邊形上面。這讓你可以使紋理看上去在移動(dòng),或脈動(dòng), 甚至產(chǎn)生陰影效果 (我們?cè)谡彰饕还?jié)中描述過(guò))。繪制第一個(gè)紋理映射,然后在上面繪制帶透明的全黑紋理,引起一種是所有的織法黑色的但是有一個(gè)透明分層堆積過(guò)它的頂端 , 這就是 -- 即時(shí)陰影。 該技術(shù)被稱為照明映射 ( 有時(shí)也稱為 暗映射),直至新的Doom ,一直是Id引擎里關(guān)卡照明的傳統(tǒng)方法。
凹凸貼圖是最近涌現(xiàn)出來(lái)的一種古老技術(shù)。幾年以前 Matrox 第一個(gè)在流行的 3D 游戲中發(fā)起使用各種不同形式的凹凸貼圖。就是生成紋理來(lái)表現(xiàn)燈光在表面的投射,表現(xiàn)表面的凹凸或表面的裂縫。 凹凸貼圖并不隨著燈光一起移動(dòng) -- 它被設(shè)計(jì)用來(lái)表現(xiàn)一個(gè)表面上的細(xì)小瑕疵,而不是大的凹凸。 比如說(shuō),在飛行模擬器中,你可以使用凹凸貼圖來(lái)產(chǎn)生像是隨機(jī)的地表細(xì)節(jié),而不是重復(fù)地使用相同的紋理,看上去一點(diǎn)趣味也沒(méi)有。
凹凸貼圖產(chǎn)生相當(dāng)明顯的表面細(xì)節(jié),盡管是很高明的戲法,但嚴(yán)格意義上講,凹凸貼圖并不隨著你的觀察角度而變化。比較新的 ATI 和 nVidia 顯卡片能執(zhí)行每像素運(yùn)算,這種缺省觀察角度的不足就真的不再是有力而快速的法則了。 無(wú)論是哪一種方法, 到目前為止,沒(méi)有游戲開(kāi)發(fā)者太多的使用; 更多的游戲能夠且應(yīng)該使用凹凸貼圖。
高速緩存抖動(dòng) = 糟糕的事物
紋理高速緩存的管理游戲引擎的速度至關(guān)重要。 和任何高速緩存一樣,緩存命中很好,而不命中將很糟糕。如果遇到紋理在圖形顯示卡內(nèi)存被頻繁地?fù)Q入換出的情況,這就是紋理高速緩存抖動(dòng)。發(fā)生這種情況時(shí),通常API將會(huì)廢棄每個(gè)紋理,結(jié)果是所有的紋理在下一幀將被重新加載,這非常耗時(shí)和浪費(fèi)。對(duì)游戲玩家來(lái)說(shuō),當(dāng)API重新加載紋理高速緩存時(shí),會(huì)導(dǎo)致幀速率遲鈍。
在紋理高速緩存管理中,有各種不同的技術(shù)將紋理高速緩存抖動(dòng)減到最少 – 這是確保任何 3D 游戲引擎速度的一個(gè)決定性因素。 紋理管理是件好事情 – 這意味著只要求顯卡使用紋理一次,而不是重復(fù)使用。這聽(tīng)起來(lái)有點(diǎn)自相矛盾,但效果是它意謂著對(duì)顯卡說(shuō),"看, 所有這些多邊形全部使用這一個(gè)紋理,我們能夠僅僅加載這個(gè)紋理一次而不是許多次嗎?" 這阻止API ( 或圖形驅(qū)動(dòng)軟件) 上傳多次向顯卡加載紋理。象OpenGL這樣的API實(shí)際上通常處理紋理高速緩存管理,意謂著,根據(jù)一些規(guī)則,比如紋理存取的頻率,API決定哪些紋理儲(chǔ)存在顯卡上,哪些紋理存儲(chǔ)在主存。 真正的問(wèn)題來(lái)了:a) 你時(shí)常無(wú)法知道API正在使用的準(zhǔn)確規(guī)則。 b)你時(shí)常要求在一幀中繪制更多的紋理,以致超出了顯卡內(nèi)存空間所能容納的紋理。
另外一種紋理高速緩存管理技術(shù)是我們?cè)缦扔懻摰募y理壓縮。很象聲音波形文件被壓縮成 MP3 文件,盡管無(wú)法達(dá)到那樣的壓縮比率,但紋理可以被壓縮。 從聲音波形文件到MP3的壓縮可以達(dá)到 11:1的壓縮比率,而絕大多數(shù)硬件支持的紋理壓縮運(yùn)算法則只有 4:1 的壓縮比率,盡管如此,這樣能產(chǎn)生很大的差別。 除此之外,在渲染(繪制)過(guò)程中,只有在需要時(shí),硬件才動(dòng)態(tài)地對(duì)紋理進(jìn)行解壓縮。這一點(diǎn)非常棒,我們僅僅擦除即將可能用到的表面。
如上所述,另外一種技術(shù)確保渲染器要求顯卡對(duì)每個(gè)紋理只繪制一次。確定你想要渲染(繪制)的使用相同紋理的所有多邊形同時(shí)送到顯卡,而不是一個(gè)模型在這里,另一個(gè)模型在那里,然后又回到最初的紋理論。僅僅繪制一次,你也就通過(guò)AGP接口傳送一次。Quake III 在其陰影系統(tǒng)就是這么做的。處理多邊形時(shí),把它們加入到一個(gè)內(nèi)部的陰影列表,一旦所有的多邊形處理完畢,渲染器遍歷紋理列表,就將紋理及所有使用這些紋理的多邊形同時(shí)傳送出去。
上述過(guò)程在使用顯卡的硬件 T & L(如果支持的話)時(shí),并不怎么有效。你面臨的結(jié)局是,滿屏幕都是使用相同紋理的大量的多邊形小群組,所有多邊形都使用不同的變換矩陣。這意謂著更多的時(shí)間花在建立顯卡的硬件 T & L 引擎 ,更多的時(shí)間被浪費(fèi)了。 無(wú)論如何,因?yàn)樗麄冇兄趯?duì)整個(gè)模型使用統(tǒng)一的紋理,所以它對(duì)實(shí)際屏幕上的模型可以有效地工作。但是因?yàn)樵S多多邊形傾向使用相同的墻壁紋理,所以對(duì)于世界場(chǎng)景的渲染,它常常就是地獄。通常它沒(méi)有這么嚴(yán)重,因?yàn)榇篌w而言,世界的紋理不會(huì)有那么大,這樣一來(lái)API的紋理緩存系統(tǒng)將會(huì)替你處理這些,并把紋理保留在顯卡以備再次使用。
在游戲機(jī)上,通常沒(méi)有紋理高速緩存系統(tǒng)(除非你寫(xiě)一個(gè))。在 PS2 上面,你最好是遠(yuǎn)離"一次紋理" 的方法。在 Xbox 上面, 這是不重要的,因?yàn)樗旧頉](méi)有圖形內(nèi)存(它是 UMA 體系結(jié)構(gòu)),且所有的紋理無(wú)論如何始終保留在主存之中。
事實(shí)上,在今天的現(xiàn)代PC FPS 游戲中,試圖通過(guò)AGP接口傳送大量紋理是第二個(gè)最通常的瓶頸。最大的瓶頸是實(shí)際幾何處理,它要使東西出現(xiàn)在它應(yīng)該出現(xiàn)的地方。在如今的3D FPS 游戲中,最耗費(fèi)時(shí)間的工作,顯然是那些計(jì)算模型中每個(gè)頂點(diǎn)正確的世界位置的數(shù)學(xué)運(yùn)算。如果你不把場(chǎng)景的紋理保持在預(yù)算之內(nèi),僅居其次的就是通過(guò)AGP接口傳送大量的紋理了。然而,你確實(shí)有能力影響這些。 通過(guò)降低頂層的 MIP 級(jí)別(還記得系統(tǒng)在哪里不斷地為你細(xì)分紋理嗎?), 你就能夠把系統(tǒng)正在嘗試送到顯卡的紋理大小減少一半。你的視覺(jué)質(zhì)量會(huì)有所下降-- 尤其是在引人注目的電影片斷中--但是你的幀速率上升了。這種方式對(duì)網(wǎng)絡(luò)游戲尤其有幫助。實(shí)際上,Soldier of Fortune II和Jedi Knight II: Outcast這兩款游戲在設(shè)計(jì)時(shí)針對(duì)的顯卡還不是市場(chǎng)上的大眾主流顯卡。為了以最大大小觀看他們的紋理,你的3D 顯卡至少需要有128MB的內(nèi)存。這兩種產(chǎn)品在思想上都是給未來(lái)設(shè)計(jì)的。
上面就是第 2 部份。在下面章節(jié)中,我們將介紹許多主題,包括內(nèi)存管理,霧效果,深度測(cè)試, 抗鋸齒,頂點(diǎn)著色,API等。