|
第1部分: 游戲引擎介紹, 渲染和構(gòu)造3D世界
介紹 自Doom游戲時(shí)代以來我們已經(jīng)走了很遠(yuǎn)。 DOOM不只是一款偉大的游戲,它同時(shí)也開創(chuàng)了一種新的游戲編程模式: 游戲 "引擎"。 這種模塊化,可伸縮和擴(kuò)展的設(shè)計(jì)觀念可以讓游戲玩家和程序設(shè)計(jì)者深入到游戲核心,用新的模型,場景和聲音創(chuàng)造新的游戲, 或向已有的游戲素材中添加新的東西。大量的新游戲根據(jù)已經(jīng)存在的游戲引擎開發(fā)出來,而大多數(shù)都以ID公司的Quake引擎為基礎(chǔ), 這些游戲包括Counter Strike, Team Fortress, Tac Ops, Strike Force, 以及Quake Soccer。Tac Ops 和Strike Force 都使用了Unreal Tournament 引擎。事實(shí)上, "游戲引擎" 已經(jīng)成為游戲玩家之間交流的標(biāo)準(zhǔn)用語,但是究竟引擎止于何處,而游戲又從哪里開始呢?像素的渲染,聲音的播放,怪物的思考以及游戲事件的觸發(fā),游戲中所有這一切的幕后又是什么呢? 如果你曾經(jīng)思考過這些問題, 而且想要知道更多驅(qū)動(dòng)游戲進(jìn)行的東西,那么這篇文章正好可以告訴你這些。 本文分多個(gè)部分深入剖析了游戲引擎的內(nèi)核, 特別是Quake引擎,因?yàn)槲易罱ぷ鞯墓綬aven Software已經(jīng)在Quake引擎的基礎(chǔ)上開發(fā)出了多款游戲,其中包括著名的Soldier of Fortune 。
開始 讓我們首先來看看一個(gè)游戲引擎和游戲本身之間的主要區(qū)別。 許多人們會(huì)混淆游戲引擎和整個(gè)游戲 。這有點(diǎn)像把一個(gè)汽車發(fā)動(dòng)機(jī)和整個(gè)汽車混淆起來一樣 。 你能夠從汽車?yán)锩嫒〕霭l(fā)動(dòng)機(jī), 建造另外一個(gè)外殼,再使用發(fā)動(dòng)機(jī)一次。 游戲也像那。 游戲引擎被定義為所有的非游戲特有的技術(shù)。 游戲部份是被稱為 '資產(chǎn)' 的所有內(nèi)容 (模型,動(dòng)畫,聲音,人工智能和物理學(xué))和為了使游戲運(yùn)行或者控制如何運(yùn)行而特別需要的程序代碼, 比如說AI--人工智能。
對于曾經(jīng)看過 Quake 游戲結(jié)構(gòu)的人來說, 游戲引擎就是 Quake。exe ,而游戲部分則是 QAGame。dll 和 CGame。dll 。 如果你不知道這是什么意思, 也沒有什么關(guān)系;在有人向我解釋它以前, 我也不知道是什么意思。 但是你將會(huì)完全明白它的意思。 這篇游戲引擎指導(dǎo)分為十一個(gè)部份。 是的, 從數(shù)量上來說,總共是十一個(gè)部份! 每個(gè)部分大概3000字左右?,F(xiàn)在就從第一部分開始我們的探索吧,深入我們所玩游戲的內(nèi)核,在這里我們將了解一些基本的東西, 為后面的章節(jié)作鋪墊。。。
渲染器 讓我們從渲染器來開始游戲引擎設(shè)計(jì)的探討吧, 我們將從游戲開發(fā)者(本文作者的背景)的角度來探討這些問題。事實(shí)上,在本文的各個(gè)段落,我們將常常從游戲開發(fā)者的角度探討, 也讓您像我們一樣思考問題!
什么是渲染器,為什么它又這么重要呢?好吧,如果沒有它,你將什么也看不到。它讓游戲場景可視化,讓玩家/觀眾可以看見場景,從而讓玩家能夠根據(jù)屏幕上所看到的東西作出適當(dāng)?shù)臎Q斷。 盡管我們下面的探討可能讓新手感到有些恐懼,先別去理會(huì)它。 渲染器做些什么?為什么它是必須的?我們將會(huì)解釋這些重要問題。
當(dāng)構(gòu)造一個(gè)游戲引擎的時(shí)候, 你通常想做的第一件事情就是建造渲染器。 因?yàn)槿绻床灰娙魏螙|西 – 那么你又如何知道你的程序代碼在工作呢? 超過 50% 的 CPU 處理時(shí)間花費(fèi)在渲染器上面; 通常也是在這個(gè)部分,游戲開發(fā)者將會(huì)受到最苛刻的評判。 如果我們在這個(gè)部分表現(xiàn)很差,事情將會(huì)變得非常糟糕, 我們的程序技術(shù),我們的游戲和我們的公司將在 10 天之內(nèi)變成業(yè)界的笑話。 它也是我們最依賴于外部廠商和力量的地方,在這里他們將處理最大限度的潛在操作目標(biāo)。 如此說來, 建造一個(gè)渲染器確實(shí)不象聽起來那么吸引人(事實(shí)如此), 但如果沒有一個(gè)好的渲染器, 游戲或許永遠(yuǎn)不會(huì)躋身于排行榜前10 名。
如今,在屏幕上生成像素,涉及到 3D 加速卡, API ,三維空間數(shù)學(xué), 對 3D 硬件如何工作的理解等等。對於主機(jī)(游戲機(jī))游戲來說,也需要相同類型的知識(shí),但是至少對于主機(jī), 你不必去嘗試擊中一個(gè)移動(dòng)中的目標(biāo)。 因?yàn)橐慌_(tái)主機(jī)的硬件配置是固定的 "時(shí)間快照", 和PC(個(gè)人計(jì)算機(jī))不同, 在一臺(tái)主機(jī)的生命期中,它的硬件配置不會(huì)改變。
在一般意義上,渲染器的工作就是要?jiǎng)?chuàng)造出游戲的視覺閃光點(diǎn),實(shí)際上達(dá)到這個(gè)目標(biāo)需要大量的技巧。3D圖形本質(zhì)上是用最少的努力創(chuàng)造出最大效果的一門藝術(shù), 因?yàn)轭~外的 3D 處理在處理器時(shí)間和和內(nèi)存帶寬方面都是極為昂貴的。 它也是一種預(yù)算, 要弄清楚你想在什么地方花費(fèi)處理器時(shí)間,而你寧愿在什么地方節(jié)省一些從而達(dá)到最好的整體效果。 接下來我們將會(huì)介紹一些這方面的工具,以及怎樣更好的用它們讓游戲引擎工作。
建造3D世界 最近,當(dāng)我和一位從事計(jì)算機(jī)圖形方面工作長達(dá)數(shù)年之久的人會(huì)談時(shí),她向我吐露道, 當(dāng)她第一次看到實(shí)時(shí)操縱計(jì)算機(jī) 3D 圖象時(shí), 她不知道這是怎么實(shí)現(xiàn)的, 也不知道計(jì)算機(jī)如何能夠存儲(chǔ) 3D 圖象。 今天這對于在大街上的普通人來說或許是真實(shí)的,即使他們時(shí)常玩 PC 游戲, 游戲機(jī)游戲, 或街機(jī)游戲。
下面我們將從游戲設(shè)計(jì)者的角度討論創(chuàng)造 3D 世界的一些細(xì)節(jié),你也應(yīng)該看一看 Dave Salvator 所寫的“3D 管線導(dǎo)論“,以便對3D 圖象生成的主要過程有一個(gè)整體的了解。
3D 物體(對象)被儲(chǔ)存成 3D 世界中的一系列點(diǎn)(被稱為頂點(diǎn)), 彼此之間有相互關(guān)系,所以計(jì)算機(jī)知道如何在世界中的這些點(diǎn)之間畫線或者是填充表面。 一個(gè)立方體由8個(gè)點(diǎn)組成,每個(gè)角一個(gè)點(diǎn)。立方體有6個(gè)表面, 分別代表它的每一個(gè)面。 這就是 3D 對象儲(chǔ)存的基礎(chǔ)。 對于一些比較復(fù)雜的 3D 物體, 比如說一個(gè) Quake 的關(guān)卡,將有數(shù)以千計(jì)(有時(shí)數(shù)以十萬計(jì))的頂點(diǎn), 和數(shù)以千計(jì)的多邊形表面。
參見上圖的線框表示(注:原文在這里有一幅圖)。 本質(zhì)上與上面的立方體例子類似, 它僅僅是由許許多多的小多邊形組成的一些復(fù)雜場景。模型和世界如何儲(chǔ)存是渲染器的一部份功能, 而不屬于應(yīng)用程序/游戲部份。 游戲邏輯不需要知道對象在內(nèi)存中如何表示, 也不需要知道渲染器將怎樣把他們顯示出來。 游戲只是需要知道渲染器將使用正確的視野去表示對象, 并將在正確的動(dòng)畫幀中把正確的模型顯示出來。
在一個(gè)好的引擎中,渲染器應(yīng)該是可以完全被一個(gè)新的渲染器替換掉, 并且不需要去改動(dòng)游戲的一行代碼。許多跨平臺(tái)引擎, 而且許多自行開發(fā)的游戲機(jī)引擎就是這樣的,如 Unreal 引擎, --舉例來說, 這個(gè)游戲 GameCube 版本的渲染器就可以被你任意的替換掉。
讓我們再看看內(nèi)部的表示方法—除了使用坐標(biāo)系統(tǒng),還有其他方法可以在計(jì)算機(jī)內(nèi)存里表示空間的點(diǎn)。在數(shù)學(xué)上,你可以使用一個(gè)方程式來描述直線或曲線, 并得到多邊形, 而幾乎所有的 3D 顯示卡都使用多邊形來作為它們的最終渲染圖元。 一個(gè)圖元就是你在任何顯示卡上面所能使用的最低級的繪制(渲染)單位,幾乎所有的硬件都是使用三個(gè)頂點(diǎn)的多邊形(三角形)。 新一代的 nVidia 和 ATI 顯卡可以允許你以數(shù)學(xué)方式渲染(被稱為高次表面), 但因?yàn)檫@不是所有圖形卡的標(biāo)準(zhǔn), 你還不能靠它作為渲染策略。
從計(jì)算的角度來看,這通常有些昂貴,但它時(shí)常是新的實(shí)驗(yàn)技術(shù)的基礎(chǔ),例如,地表的渲染,或者對物件銳利的邊緣進(jìn)行柔化。 我們將會(huì)在下面的曲面片小節(jié)中更進(jìn)一步介紹這些高次表面。
剔除概觀 問題來了。 我現(xiàn)在有一個(gè)由幾十萬個(gè)頂點(diǎn)/多邊形描述的世界。 我以第一人稱視角位于我們這個(gè) 3D 世界的一邊。 在視野中可以看見世界的一些多邊形, 而另外一些則不可見, 因?yàn)橐恍┪矬w, 比如一面看得見的墻壁, 遮擋住了它們。 即使是最好的游戲編碼人員, 在目前的 3D 顯卡上, 在一個(gè)視野中也不能處理 300,000個(gè)三角形且仍然維持 60fps (一個(gè)主要目標(biāo))。 顯卡不能處理它, 因此我們必須寫一些代碼,在把它們交給顯卡處理之前除去那些看不見的多邊形。 這個(gè)過程被稱為剔除。
有許多不同的剔除方法。 在深入了解這些之前,讓我們探討一下為什么圖形顯示卡不能處理超高數(shù)量的多邊形。 我是說,最新的圖形卡每秒鐘不能處理幾百萬個(gè)多邊形嗎?它不應(yīng)該能夠處理嗎? 首先,你必須理解市場銷售宣稱的多邊形生成率和真實(shí)世界的多邊形生成率。 行銷上宣稱的多邊形生成率是圖形顯示卡理論上能夠達(dá)到的多邊形生成率。
如果全部多邊形都在屏幕上, 相同的紋理,相同的尺寸大小, 正在往顯示卡上傳送多邊形的應(yīng)用程序除了傳送多邊形以外什么也不做, 這時(shí)顯卡能處理多少多邊形數(shù)量, 就是圖形芯片廠商呈現(xiàn)給你的數(shù)字。
然而,在真實(shí)的游戲情形中,應(yīng)用程序時(shí)常在后臺(tái)做著許多其他的事情 -- 多邊形的 3D 變換, 光照計(jì)算, 拷貝較多的紋理到顯卡內(nèi)存, 等等。 不僅紋理要送到顯示卡, 而且還有每個(gè)多邊形的細(xì)節(jié)。一些比較新的顯卡允許你實(shí)際上在顯卡內(nèi)存本身里面儲(chǔ)存模型/世界幾何細(xì)節(jié), 但這可能是昂貴的,將會(huì)耗光紋理正常可以使用的空間,所以你最好能確定每一幀都在使用這些模型的頂點(diǎn), 否則你只是在浪費(fèi)顯示卡上的存儲(chǔ)空間。 我們就說到這里了。 重要的是,在實(shí)際使用顯卡時(shí),并不必然就能達(dá)到你在顯卡包裝盒上所看到的那些指標(biāo),如果你有一個(gè)比較慢速的CPU , 或沒有足夠的內(nèi)存時(shí),這種差異就尤為真實(shí)。
基本的剔除方法 最簡單的剔除方式就是把世界分成區(qū)域, 每個(gè)區(qū)域有一個(gè)其他可見區(qū)域的列表。 那樣, 你只需要顯示針對任何給定點(diǎn)的可見部分。 如何生成可見視野區(qū)域的列表是技巧所在。 再者, 有許多方法可以用來生成可見區(qū)域列表, 如 BSP 樹, 窺孔等等。
可以肯定,當(dāng)談?wù)?DOOM 或 QUAKE 時(shí),你已經(jīng)聽到過使用 BSP 這個(gè)術(shù)語了。 它表示二叉空間分割。
BSP 是一種將世界分成小區(qū)域的的方法,通過組織世界的多邊形,容易確定哪些區(qū)域是可見的而哪些是不可見的 – 從而方便了那些不想做太多繪制工作的基于軟件的渲染器。它同時(shí)也以一種非常有效的方式讓你知道你位于世界中的什么地方。
在基于窺孔的引擎 ( 最早由 3D Realms 已經(jīng)取消的 Prey 項(xiàng)目引入游戲世界 )里,每個(gè)區(qū)域 ( 或房間) 都建造有自己的模型, 通過每個(gè)區(qū)域的門 ( 或窺孔 )能夠看見另外的區(qū)段。 渲染器把每個(gè)區(qū)域作為獨(dú)立的場景單獨(dú)繪制。 這就是它的大致原理。 足以說這是任何一個(gè)渲染器的必需部份,而且非常重要。
盡管一些這樣的技術(shù)歸類在 "遮擋剔除"之下,但是他們?nèi)慷加型瑯拥哪康? 盡早消除不必要的工作。 對於一個(gè)FPS游戲(第一人稱射擊游戲) 來說,視野中時(shí)常有許多三角形,而且游戲玩家承擔(dān)視野的控制,丟棄或者剔除不可見的三角形就是絕對必要的了。 對空間模擬來說也是這樣的, 你可以看見很遠(yuǎn)很遠(yuǎn)的地方 – 剔除超過視覺范圍外面的東西就非常重要。 對于視野受到限制的游戲來說 – 比如 RTS (即時(shí)戰(zhàn)略類游戲)--通常比較容易實(shí)現(xiàn)。 通常渲染器的這個(gè)部份還是由軟件來完成, 而不是由顯卡完成, 由顯卡來做這部分工作只是一個(gè)時(shí)間問題。
基本的圖形管線流程 一個(gè)簡單的例子,從游戲到多邊形繪制的圖形管線過程大致是這樣: · 游戲決定在游戲中有哪些對象, 它們的模型, 使用的紋理, 他們可能在什么動(dòng)畫幀,以及它們在游戲世界里的位置。 游戲也決定照相機(jī)的位置和方向。
· 游戲把這些信息傳遞給渲染器。以模型為例 ,渲染器首先要查看模型的大小 ,照相機(jī)的位置, 然後決定模型在屏幕上是否全部可見, 或者在觀察者 (照相機(jī)視野) 的左邊,在觀察者的后面,或距離很遠(yuǎn)而不可見。它甚至?xí)褂靡恍┦澜鐪y定方式來計(jì)算出模型是否是可見的。 (參見下面這條)
· 世界可視化系統(tǒng)決定照相機(jī)在世界中的位置,并根據(jù)照相機(jī)視野決定世界的哪些區(qū)域 / 多邊形是可見的。有許多方法可以完成這個(gè)任務(wù), 包括把世界分割成許多區(qū)域的暴力方法,每個(gè)區(qū)域直接為"我能從區(qū)域 D 看見區(qū)域 AB & C", 到更精致的 BSP(二叉空間分割)世界。 所有通過這些剔除測試的多邊形被傳遞給多邊形渲染器進(jìn)行繪制。
· 對於每一個(gè)被傳遞給渲染器的多邊形, 渲染器依照局部數(shù)學(xué) ( 也就是模型動(dòng)畫) 和世界數(shù)學(xué)(相對于照相機(jī)的位置?)對多邊形進(jìn)行變換,并檢查決定多邊形是不是背對相機(jī) (也就是遠(yuǎn)離照相機(jī))。背面的多邊形被丟棄。 非背面的多邊形由渲染器根據(jù)發(fā)現(xiàn)的附近燈光照亮。然后渲染器要看多邊形使用的紋理,并且確定 API/ 圖形卡正在使用那種紋理作為它的渲染基礎(chǔ)。 在這里,多邊形被送到渲染 API,然后再送給顯卡。
很明顯這有些過分簡單化了,但你大概理解了。 下面的圖表摘自Dave Salvator's 3D 管線一文,可以給你多一些具體細(xì)節(jié):
3D 管線 - 高層的概觀 1. 應(yīng)用程序/ 場景 ·場景/ 幾何數(shù)據(jù)庫遍歷 ·對象的運(yùn)動(dòng),觀察相機(jī)的運(yùn)動(dòng)和瞄準(zhǔn) ·對象模型的動(dòng)畫運(yùn)動(dòng) ·3D 世界內(nèi)容的描述 ·對象的可見性檢查,包括可能的遮擋剔除 ·細(xì)節(jié)層次的選擇 (LOD)
2. 幾何 ·變換 (旋轉(zhuǎn),平移, 縮放) ·從模型空間到世界空間的變換 (Direct3D) ·從世界空間到觀察空間變換 ·觀察投影 ·細(xì)節(jié)接受/ 拒絕 剔除 ·背面剔除 (也可以在后面的屏幕空間中做) 光照 ·透視分割 - 變換到裁剪空間 ·裁剪 ·變換到屏幕空間
3. 三角形生成 ·背面剔除 ( 或者在光照計(jì)算之前的觀察空間中完成) ·斜率/ 角度計(jì)算 ·掃瞄線變換
4. 渲染 / 光柵化 ·著色 ·紋理 ·霧 ·Alpha 透明測試 ·深度緩沖 ·抗鋸齒 (可選擇的) ·顯示
通常你會(huì)把所有的多邊形放到一些列表內(nèi), 然後根據(jù)紋理對這個(gè)列表排序(這樣你只需要對顯卡傳送一次紋理, 而不是每個(gè)多邊形都傳送一次), 等等。在過去,會(huì)把多邊形按照它們到相機(jī)的距離進(jìn)行排序,首先繪制那些距離相機(jī)最遠(yuǎn)的多邊形, 但現(xiàn)在由于 Z 緩沖的出現(xiàn),這種方法就不是那么重要了。 當(dāng)然那些透明的多邊形要除外,它們要在所有的非半透明多邊形繪制之后才能夠繪制 ,這樣一來,所有在它們后面的多邊形就能正確地在場景中顯現(xiàn)出來。 當(dāng)然,象那樣,實(shí)際上你必須得從后到前地繪制那些多邊形。 但時(shí)常在任何給定的 FPS 游戲場景中, 通常沒有太多透明的多邊形。 它可能看起來像有,但實(shí)際上與那些不透明的多邊形相比,其比率是相當(dāng)?shù)偷摹?
一旦應(yīng)用程序?qū)鼍皞鬟f到 API, API 就能利用硬件加速的變換和光照處理 (T&L), 這在如今的 3D 顯卡中是很平常的事情。 這里不討論涉及到的矩陣數(shù)學(xué)(參見Dave的 3D 管線導(dǎo)論),幾何變換允許 3D 顯卡按照你的嘗試,根據(jù)相機(jī)在任何時(shí)間的位置和方向,在世界的正確角度和位置繪制多邊形。
對于每個(gè)點(diǎn)或頂點(diǎn)都有大量的計(jì)算, 包括裁剪運(yùn)算,決定任何給定的多邊形實(shí)際上是否可見,在屏幕上完全不可見或部分可見。 光照運(yùn)算,計(jì)算紋理色彩明亮程度,這取決于世界的燈光從什么角度如何投射到頂點(diǎn)上。 過去,處理器處理這些計(jì)算,但現(xiàn)在,當(dāng)代圖形硬件就能為你做這些事情, 這意謂著你的處理器可以去做其他的事情了。很明顯這是件好事情 (tm) ,由于不能指望市面上所有的 3D 顯卡板上都有T & L, 所以無論如何你自己將必須寫所有的這些例程 (再一次從游戲開發(fā)者角度來說)。 你將在本文各處的不同段落看到 "好事情 ( tm)" 這個(gè)詞匯。 我認(rèn)為,這些特征為使游戲看起來更好作出了非常有用的貢獻(xiàn)。 毫不令人吃驚,你也將會(huì)看見它的對立面;你猜到了,那就是“壞事情 (tm)”。 我正在嘗試爭取這些詞匯的版權(quán), 你要使用他們就得支付一筆小小的費(fèi)用喲。
曲面片(高次表面) 除了三角形,曲面片的使用現(xiàn)在正變得更普遍。 因?yàn)樗麄兡苡脭?shù)學(xué)表達(dá)式來描述幾何 ( 通常涉及某種曲線的幾何形體) ,而不僅僅只是列出大量的多邊形以及在游戲世界中的位置, 所以曲面片 ( 高次表面的另一個(gè)名稱) 非常好。 這樣,你實(shí)際上就能夠動(dòng)態(tài)地根據(jù)方程式來建立( 和變形 )多邊形網(wǎng)格, 并決定你實(shí)際想要從曲面片上看到的多邊形數(shù)量。 因此,舉例來說,你可以描述一個(gè)管道, 然后在世界中就可以有這種管道的許多樣例。 在一些房間中, 你已經(jīng)顯示了 10,000個(gè)多邊形,你可以說,"因?yàn)槲覀円呀?jīng)顯示了大量的多邊形,而且任何更多的多邊形將會(huì)使幀速率下降, 所以這個(gè)管道應(yīng)該只有 100 個(gè)多邊形"。 但在另外一個(gè)房間中, 視野中只有 5,000個(gè)可見的多邊形,你可以說,"因?yàn)槲覀冞€沒有達(dá)到預(yù)算可以顯示的多邊形數(shù)量 , 所以,現(xiàn)在這個(gè)管道能有 500 個(gè)多邊形"。 非常美妙的東西 --但你必須首先知道所有這些,并建立網(wǎng)格,這不是無足輕重的。 通過 AGP 傳送同一個(gè)對象的曲面方程確實(shí)要比傳送其大量頂點(diǎn)節(jié)省成本。 SOF2 就使用了這個(gè)方法的一種變體來建立它的地表系統(tǒng)。
事實(shí)上現(xiàn)在的 ATI 顯卡具有 TruForm, 它能帶一個(gè)以三角形為基礎(chǔ)的模型,并將該模型轉(zhuǎn)換為基于高次表面的模型,使其平滑 — 接著再用十倍三角形數(shù)量把模型轉(zhuǎn)換回基于大量三角形的模型 (被稱為retesselation)。然后模型送往管線做進(jìn)一步的處理。 實(shí)際上 ATI 僅僅在 T & L 引擎之前增加了一個(gè)階段來處理這個(gè)過程。這里的缺點(diǎn)是,要控制哪些模型需要被平滑處理而哪些又不需要。你常常想要一些邊緣比較尖銳, 比如鼻子,但它卻被不恰當(dāng)?shù)钠交^了。 這仍然是一種很好的技術(shù),而且我能預(yù)見它在將來會(huì)被更多的應(yīng)用。
這就是第一部份 -- 我們將會(huì)在第二部分繼續(xù)介紹光照和紋理,下面的章節(jié)會(huì)更加深入。
第2部份: 3D環(huán)境的光照和紋理
世界的燈光 在變換過程中, 通常是在稱為觀察空間的坐標(biāo)空間中, 我們遇到了最重要的運(yùn)算之一: 光照計(jì)算。 它是一種這樣的事情, 當(dāng)它工作時(shí),你不關(guān)注它,但當(dāng)它不工作時(shí), 你就非常關(guān)注它了。有很多不同的光照方法,從簡單的計(jì)算多邊形對于燈光的朝向,并根據(jù)燈光到多邊形的方向和距離加上燈光顏色的百分比值,一直到產(chǎn)生邊緣平滑的燈光貼圖疊加基本紋理。而且一些 API 實(shí)際上提供預(yù)先建造的光照方法。舉例來說,OpenGL 提供了每多邊形,每頂點(diǎn),和每像素的光照計(jì)算。
在頂點(diǎn)光照中,你要決定一個(gè)頂點(diǎn)被多少個(gè)多邊形共享,并計(jì)算出共享該頂點(diǎn)的所有多邊形法向量的均值(稱為法向量),并將該法向量賦頂點(diǎn)。一個(gè)給定多邊形的每個(gè)頂點(diǎn)會(huì)有不同的法向量,所以你需要漸變或插值多邊形頂點(diǎn)的光照顏色以便得到平滑的光照效果。 你沒有必要用這種光照方式查看每個(gè)單獨(dú)的多邊形。 這種方式的優(yōu)點(diǎn)是時(shí)??梢允褂糜布D(zhuǎn)換與光照(T & L)來幫助快速完成。 不足之處是它不能產(chǎn)生陰影。 舉例來說,即使燈光是在模型的右側(cè),左手臂應(yīng)該在被身體投影的陰影中,而實(shí)際上模型的雙臂卻以同樣的方式被照明了。
這些簡單的方法使用著色來達(dá)到它們的目標(biāo)。 當(dāng)用平面光照繪制一個(gè)多邊形時(shí), 你讓渲染(繪制)引擎把整個(gè)多邊形都著上一種指定的顏色。這叫做平面著色光照。 (該方法中,多邊形均對應(yīng)一個(gè)光強(qiáng)度,表面上所有點(diǎn)都用相同的強(qiáng)度值顯示,渲染繪制時(shí)得到一種平面效果,多邊形的邊緣不能精確的顯示出來) 。
對于頂點(diǎn)著色 ( Gouraud 著色) ,你讓渲染引擎給每個(gè)頂點(diǎn)賦予特定的顏色。 在繪制多邊形上各點(diǎn)投影所對應(yīng)的像素時(shí),根據(jù)它們與各頂點(diǎn)的距離,對這些頂點(diǎn)的顏色進(jìn)行插值計(jì)算。 (實(shí)際上Quake III 模型使用的就是這種方法, 效果好的令人驚奇)。
還有就是 Phong 著色。如同 Gouraud 著色,通過紋理工作,但不對每個(gè)頂點(diǎn)顏色進(jìn)行插值決定像素顏色值, 它對每個(gè)頂點(diǎn)的法向量進(jìn)行插值,會(huì)為每個(gè)頂點(diǎn)投影的像素做相同的工作。對于 Gouraud 著色,你需要知道哪些光投射在每個(gè)頂點(diǎn)上。對于 Phong 著色,你對每個(gè)像素也要知道這么多。
一點(diǎn)也不令人驚訝, Phong 著色可以得到更加平滑的效果,因?yàn)槊總€(gè)像素都需要進(jìn)行光照計(jì)算,其繪制非常耗費(fèi)時(shí)間。平面光照處理方法很快速, 但比較粗糙。Phong 著色比 Gouraud 著色計(jì)算更昂貴,但效果最好,可以達(dá)到鏡面高光效果("高亮")。 這些都需要你在游戲開發(fā)中折衷權(quán)衡。
不同的燈光 接著是生成照明映射,你用第二個(gè)紋理映射(照明映射)與已有的紋理混合來產(chǎn)生照明效果。這樣工作得很好, 但這本質(zhì)上是在渲染之前預(yù)先生成的一種罐裝效果。如果你使用動(dòng)態(tài)照明 (即,燈光移動(dòng), 或者沒有程序的干預(yù)而打開和關(guān)閉),你得必須在每一幀重新生成照明映射,按照動(dòng)態(tài)燈光的運(yùn)動(dòng)方式修改這些照明映射。燈光映射能夠快速的渲染,但對存儲(chǔ)這些燈光紋理所需的內(nèi)存消耗非常昂貴。你可以使用一些壓縮技巧使它們占用較少的的內(nèi)存空間,或減少其尺寸大小, 甚至使它們是單色的 (這樣做就不會(huì)有彩色燈光了),等等。 如果你確實(shí)在場景中有多個(gè)動(dòng)態(tài)燈光, 重新生成照明映射將以昂貴的CPU周期而告終。
許多游戲通常使用某種混合照明方式。 以Quake III為例,場景使用照明映射, 動(dòng)畫模型使用頂點(diǎn)照明。 預(yù)先處理的燈光不會(huì)對動(dòng)畫模型產(chǎn)生正確的效果 -- 整個(gè)多邊形模型得到燈光的全部光照值 -- 而動(dòng)態(tài)照明將被用來產(chǎn)生正確的效果。 使用混合照明方式是多數(shù)的人們沒有注意到的一個(gè)折衷,它通常讓效果看起來"正確"。 這就是游戲的全部 – 做一切必要的工作讓效果看起來"正確",但不必真的是正確的。
當(dāng)然,所有這些在新的Doom引擎里面都不復(fù)存在了,但要看到所有的效果,至少需要 1GHZ CPU 和 GeForce 2 顯卡。是進(jìn)步了,但一切都是有代價(jià)的。
一旦場景經(jīng)過轉(zhuǎn)換和照明, 我們就進(jìn)行裁剪運(yùn)算。 不進(jìn)入血淋淋的細(xì)節(jié)而,剪斷運(yùn)算決定哪些三角形完全在場景 (被稱為觀察平截頭體) 之內(nèi)或部份地在場景之內(nèi)。完全在場景之內(nèi)的三角形被稱為細(xì)節(jié)接受,它們被處理。對于只是部分在場景之內(nèi)的三角形, 位于平截頭體外面的部分將被裁剪掉,余下位于平截頭體內(nèi)部的多邊形部分將需要重新閉合,以便其完全位于可見場景之內(nèi)。 (更多的細(xì)節(jié)請參考我們的 3D 流水線指導(dǎo)一文)。
場景經(jīng)過裁剪以后,流水線中的下一個(gè)階段就是三角形生成階段(也叫做掃描 線轉(zhuǎn)換),場景被映射到2D 屏幕坐標(biāo)。到這里,就是渲染(繪制)運(yùn)算了。
紋理與MIP映射 紋理在使3D場景看起來真實(shí)方面異常重要,它們是你應(yīng)用到場景區(qū)域或?qū)ο蟮囊恍┓纸獬啥噙呅蔚男D片。多重紋理耗費(fèi)大量的內(nèi)存,有不同的技術(shù)來幫助管理它們的尺寸大小。紋理壓縮是在保持圖片信息的情況下,讓紋理數(shù)據(jù)更小的一種方法。紋理壓縮占用較少的游戲CD空間,更重要的是,占用較少內(nèi)存和3D 顯卡存儲(chǔ)空間。另外,在你第一次要求顯卡顯示紋理的時(shí)候,壓縮的(較小的) 版本經(jīng)過 AGP 接口從 PC 主存送到3D 顯卡, 會(huì)更快一些。紋理壓縮是件好事情。 在下面我們將會(huì)更多的討論紋理壓縮。
MIP 映射(多紋理映射) 游戲引擎用來減少紋理內(nèi)存和帶寬需求的另外一個(gè)技術(shù)就是 MIP 映射。 MIP 映射技術(shù)通過預(yù)先處理紋理,產(chǎn)生它的多個(gè)拷貝紋理,每個(gè)相繼的拷貝是上一個(gè)拷貝的一半大小。為什么要這樣做?要回答這個(gè)問題,你需要了解 3D 顯卡是如何顯示紋理的。最壞情況,你選擇一個(gè)紋理,貼到一個(gè)多邊形上,然后輸出到屏幕。我們說這是一對一的關(guān)系,最初紋理映射圖的一個(gè)紋素 (紋理元素) 對應(yīng)到紋理映射對象多邊形的一個(gè)像素。如果你顯示的多邊形被縮小一半,紋理的紋素就每間隔一個(gè)被顯示。這樣通常沒有什么問題 -- 但在某些情況下會(huì)導(dǎo)致一些視覺上的怪異現(xiàn)象。讓我們看看磚塊墻壁。 假設(shè)最初的紋理是一面磚墻,有許多磚塊,磚塊之間的泥漿寬度只有一個(gè)像素。如果你把多邊形縮小一半, 紋素只是每間隔一個(gè)被應(yīng)用,這時(shí)候,所有的泥漿會(huì)突然消失,因?yàn)樗鼈儽豢s掉了。你只會(huì)看到一些奇怪的圖像。
使用 MIP 映射,你可以在顯示卡應(yīng)用紋理之前,自己縮放圖像,因?yàn)榭梢灶A(yù)先處理紋理,你做得更好一些,讓泥漿不被縮掉。當(dāng) 3D 顯卡用紋理繪制多邊形時(shí),它檢測到縮放因子,說,"你知道,我要使用小一些的紋理,而不是縮小最大的紋理,這樣看起來會(huì)更好一些。" 在這里, MIP 映射為了一切,一切也為了 MIP 映射。
多重紋理與凹凸映射 單一紋理映射給整個(gè)3D 真實(shí)感圖形帶來很大的不同, 但使用多重紋理甚至可以達(dá)到一些更加令人難忘的效果。過去這一直需要多遍渲染(繪制),嚴(yán)重影響了像素填充率。 但許多具有多流水線的3D 加速卡,如ATI's Radeon 和 nVidia's GeForce 2及更高級的顯卡,多重紋理可以在一遍渲染(繪制)過程中完成。 產(chǎn)生多重紋理效果時(shí), 你先用一個(gè)紋理繪制多邊形,然后再用另外一個(gè)紋理透明地繪制在多邊形上面。這讓你可以使紋理看上去在移動(dòng),或脈動(dòng), 甚至產(chǎn)生陰影效果 (我們在照明一節(jié)中描述過)。繪制第一個(gè)紋理映射,然后在上面繪制帶透明的全黑紋理,引起一種是所有的織法黑色的但是有一個(gè)透明分層堆積過它的頂端 , 這就是 -- 即時(shí)陰影。 該技術(shù)被稱為照明映射 ( 有時(shí)也稱為 暗映射),直至新的Doom ,一直是Id引擎里關(guān)卡照明的傳統(tǒng)方法。
凹凸貼圖是最近涌現(xiàn)出來的一種古老技術(shù)。幾年以前 Matrox 第一個(gè)在流行的 3D 游戲中發(fā)起使用各種不同形式的凹凸貼圖。就是生成紋理來表現(xiàn)燈光在表面的投射,表現(xiàn)表面的凹凸或表面的裂縫。 凹凸貼圖并不隨著燈光一起移動(dòng) -- 它被設(shè)計(jì)用來表現(xiàn)一個(gè)表面上的細(xì)小瑕疵,而不是大的凹凸。 比如說,在飛行模擬器中,你可以使用凹凸貼圖來產(chǎn)生像是隨機(jī)的地表細(xì)節(jié),而不是重復(fù)地使用相同的紋理,看上去一點(diǎn)趣味也沒有。
凹凸貼圖產(chǎn)生相當(dāng)明顯的表面細(xì)節(jié),盡管是很高明的戲法,但嚴(yán)格意義上講,凹凸貼圖并不隨著你的觀察角度而變化。比較新的 ATI 和 nVidia 顯卡片能執(zhí)行每像素運(yùn)算,這種缺省觀察角度的不足就真的不再是有力而快速的法則了。 無論是哪一種方法, 到目前為止,沒有游戲開發(fā)者太多的使用; 更多的游戲能夠且應(yīng)該使用凹凸貼圖。
高速緩存抖動(dòng) = 糟糕的事物 紋理高速緩存的管理游戲引擎的速度至關(guān)重要。 和任何高速緩存一樣,緩存命中很好,而不命中將很糟糕。如果遇到紋理在圖形顯示卡內(nèi)存被頻繁地?fù)Q入換出的情況,這就是紋理高速緩存抖動(dòng)。發(fā)生這種情況時(shí),通常API將會(huì)廢棄每個(gè)紋理,結(jié)果是所有的紋理在下一幀將被重新加載,這非常耗時(shí)和浪費(fèi)。對游戲玩家來說,當(dāng)API重新加載紋理高速緩存時(shí),會(huì)導(dǎo)致幀速率遲鈍。
在紋理高速緩存管理中,有各種不同的技術(shù)將紋理高速緩存抖動(dòng)減到最少 – 這是確保任何 3D 游戲引擎速度的一個(gè)決定性因素。 紋理管理是件好事情 – 這意味著只要求顯卡使用紋理一次,而不是重復(fù)使用。這聽起來有點(diǎn)自相矛盾,但效果是它意謂著對顯卡說,"看, 所有這些多邊形全部使用這一個(gè)紋理,我們能夠僅僅加載這個(gè)紋理一次而不是許多次嗎?" 這阻止API ( 或圖形驅(qū)動(dòng)軟件) 上傳多次向顯卡加載紋理。象OpenGL這樣的API實(shí)際上通常處理紋理高速緩存管理,意謂著,根據(jù)一些規(guī)則,比如紋理存取的頻率,API決定哪些紋理儲(chǔ)存在顯卡上,哪些紋理存儲(chǔ)在主存。 真正的問題來了:a) 你時(shí)常無法知道API正在使用的準(zhǔn)確規(guī)則。 b)你時(shí)常要求在一幀中繪制更多的紋理,以致超出了顯卡內(nèi)存空間所能容納的紋理。
另外一種紋理高速緩存管理技術(shù)是我們早先討論的紋理壓縮。很象聲音波形文件被壓縮成 MP3 文件,盡管無法達(dá)到那樣的壓縮比率,但紋理可以被壓縮。 從聲音波形文件到MP3的壓縮可以達(dá)到 11:1的壓縮比率,而絕大多數(shù)硬件支持的紋理壓縮運(yùn)算法則只有 4:1 的壓縮比率,盡管如此,這樣能產(chǎn)生很大的差別。 除此之外,在渲染(繪制)過程中,只有在需要時(shí),硬件才動(dòng)態(tài)地對紋理進(jìn)行解壓縮。這一點(diǎn)非常棒,我們僅僅擦除即將可能用到的表面。
如上所述,另外一種技術(shù)確保渲染器要求顯卡對每個(gè)紋理只繪制一次。確定你想要渲染(繪制)的使用相同紋理的所有多邊形同時(shí)送到顯卡,而不是一個(gè)模型在這里,另一個(gè)模型在那里,然后又回到最初的紋理論。僅僅繪制一次,你也就通過AGP接口傳送一次。Quake III 在其陰影系統(tǒng)就是這么做的。處理多邊形時(shí),把它們加入到一個(gè)內(nèi)部的陰影列表,一旦所有的多邊形處理完畢,渲染器遍歷紋理列表,就將紋理及所有使用這些紋理的多邊形同時(shí)傳送出去。
上述過程在使用顯卡的硬件 T & L(如果支持的話)時(shí),并不怎么有效。你面臨的結(jié)局是,滿屏幕都是使用相同紋理的大量的多邊形小群組,所有多邊形都使用不同的變換矩陣。這意謂著更多的時(shí)間花在建立顯卡的硬件 T & L 引擎 ,更多的時(shí)間被浪費(fèi)了。 無論如何,因?yàn)樗麄冇兄趯φ麄€(gè)模型使用統(tǒng)一的紋理,所以它對實(shí)際屏幕上的模型可以有效地工作。但是因?yàn)樵S多多邊形傾向使用相同的墻壁紋理,所以對于世界場景的渲染,它常常就是地獄。通常它沒有這么嚴(yán)重,因?yàn)榇篌w而言,世界的紋理不會(huì)有那么大,這樣一來API的紋理緩存系統(tǒng)將會(huì)替你處理這些,并把紋理保留在顯卡以備再次使用。
在游戲機(jī)上,通常沒有紋理高速緩存系統(tǒng)(除非你寫一個(gè))。在 PS2 上面,你最好是遠(yuǎn)離"一次紋理" 的方法。在 Xbox 上面, 這是不重要的,因?yàn)樗旧頉]有圖形內(nèi)存(它是 UMA 體系結(jié)構(gòu)),且所有的紋理無論如何始終保留在主存之中。
事實(shí)上,在今天的現(xiàn)代PC FPS 游戲中,試圖通過AGP接口傳送大量紋理是第二個(gè)最通常的瓶頸。最大的瓶頸是實(shí)際幾何處理,它要使東西出現(xiàn)在它應(yīng)該出現(xiàn)的地方。在如今的3D FPS 游戲中,最耗費(fèi)時(shí)間的工作,顯然是那些計(jì)算模型中每個(gè)頂點(diǎn)正確的世界位置的數(shù)學(xué)運(yùn)算。如果你不把場景的紋理保持在預(yù)算之內(nèi),僅居其次的就是通過AGP接口傳送大量的紋理了。然而,你確實(shí)有能力影響這些。 通過降低頂層的 MIP 級別(還記得系統(tǒng)在哪里不斷地為你細(xì)分紋理嗎?), 你就能夠把系統(tǒng)正在嘗試送到顯卡的紋理大小減少一半。你的視覺質(zhì)量會(huì)有所下降-- 尤其是在引人注目的電影片斷中--但是你的幀速率上升了。這種方式對網(wǎng)絡(luò)游戲尤其有幫助。實(shí)際上,Soldier of Fortune II和Jedi Knight II: Outcast這兩款游戲在設(shè)計(jì)時(shí)針對的顯卡還不是市場上的大眾主流顯卡。為了以最大大小觀看他們的紋理,你的3D 顯卡至少需要有128MB的內(nèi)存。這兩種產(chǎn)品在思想上都是給未來設(shè)計(jì)的。
上面就是第 2 部份。在下面章節(jié)中,我們將介紹許多主題,包括內(nèi)存管理,霧效果,深度測試, 抗鋸齒,頂點(diǎn)著色,API等。
第3部份: 內(nèi)存使用,特效和API
關(guān)于內(nèi)存使用的思考 讓我們想一想,在今天實(shí)際上是如何使用3D 顯卡內(nèi)存的以及在將來又會(huì)如何使用。 如今絕大多數(shù)3D顯卡處理32位像素顏色,8位紅色, 8位藍(lán)色,8 位綠色,和 8 位透明度。這些組合的紅,藍(lán)和綠256個(gè)色度,可以組成 16。7 百萬種顏色-- 那是你我可以在一個(gè)監(jiān)視器上看見的所有顏色。
那么,游戲設(shè)計(jì)大師John Carmack 為什么要求 64 位顏色分辨率呢? 如果我們看不出區(qū)別,又有什么意義呢? 意義是: 比如說, 有十幾個(gè)燈光照射模型上的點(diǎn),顏色顏色各不相同。 我們?nèi)∧P偷淖畛躅伾?,然后?jì)算一個(gè)燈光的照射,模型顏色值將改變。 然后我們計(jì)算另外的一個(gè)燈光, 模型顏色值進(jìn)一步改變。 這里的問題是,因?yàn)轭伾抵挥?位,在計(jì)算了4個(gè)燈光之后,8位的顏色值將不足以給我們最后的顏色較好的分辨率和表現(xiàn)。分辨率的不足是由量化誤差導(dǎo)致的,本質(zhì)原因是由于位數(shù)不足引起的舍入誤差。
你能很快地用盡位數(shù),而且同樣地,所有的顏色被清掉。每顏色16 或 32 位,你有一個(gè)更高分辨率,因此你能夠反復(fù)著色以適當(dāng)?shù)乇憩F(xiàn)最后的顏色。這樣的顏色深度很快就能消耗大量的存儲(chǔ)空間。我們也應(yīng)提到整個(gè)顯卡內(nèi)存與紋理內(nèi)存。這里所要說的是,每個(gè)3D 顯卡實(shí)際只有有限的內(nèi)存,而這些內(nèi)存要存儲(chǔ)前端和后端緩沖區(qū),Z 緩沖區(qū),還有所有的令人驚奇的紋理。最初的 Voodoo1 顯卡只有2MB顯存,后來 Riva TNT提高到16MB顯存。然后 GeForce 和 ATI Rage有32MB顯存, 現(xiàn)在一些 GeForce 2 到 4的顯卡和 Radeons 帶有 64MB 到128MB 的顯存。 這為什么重要? 好吧,讓我們看一些數(shù)字…
比如你想讓你的游戲看起來最好,所以你想要讓它以32位屏幕, 1280x1024分辨率和32位 Z- 緩沖跑起來。 好,屏幕上每個(gè)像素4個(gè)字節(jié),外加每個(gè)像素4字節(jié)的Z-緩沖,因?yàn)槎际敲肯袼?2位。我們有1280x1024 個(gè)像素 – 也就是 1,310,720個(gè)像素?;谇岸司彌_區(qū)和Z-緩沖區(qū)的字節(jié)數(shù),這個(gè)數(shù)字乘以8,是 10,485,760字節(jié)。包括一個(gè)后端緩沖區(qū),這樣是 1280x1024x12, 也就是 15,728,640 字節(jié), 或 15MB。 在一個(gè) 16MB 顯存的顯卡上,就只給我們剩下1MB 來存儲(chǔ)所有的紋理。 現(xiàn)在如果最初的紋理是真32 位或 4字節(jié)寬,那么我們每幀能在顯卡上存儲(chǔ) 1MB/4字節(jié)每像素 = 262,144個(gè)像素。這大約是4 個(gè) 256x256 的紋理頁面。
很清楚,上述例子表明,舊的16MB 顯卡沒有現(xiàn)代游戲表現(xiàn)其絢麗畫面所需要的足夠內(nèi)存。很明顯,在它繪制畫面的時(shí)候,我們每幀都必須重新把紋理裝載到顯卡。實(shí)際上,設(shè)計(jì)AGP總線的目的就是完成這個(gè)任務(wù),不過, AGP 還是要比 3D 掀卡的幀緩沖區(qū)慢,所以你會(huì)受到性能上的一些損失。很明顯,如果紋理由32位降低到16位,你就能夠通過AGP以較低的分辨率傳送兩倍數(shù)量的紋理。如果你的游戲以每個(gè)像素比較低的色彩分辨率跑, 那么就可以有更多的顯示內(nèi)存用來保存常用的紋理 (稱為高速緩存紋理) 。 但實(shí)際上你永遠(yuǎn)不可能預(yù)知使用者將如何設(shè)置他們的系統(tǒng)。如果他們有一個(gè)在高分辨率和顏色深度跑的顯卡,那么他們將會(huì)更可能那樣設(shè)定他們的顯卡。
霧 我們現(xiàn)在開始講霧,它是某種視覺上的效果。如今絕大多數(shù)的引擎都能處理霧, 因?yàn)殪F非常方便地讓遠(yuǎn)處的世界淡出視野,所以當(dāng)模型和場景地理越過觀察體后平面進(jìn)入視覺范圍內(nèi)時(shí),你就不會(huì)看見它們突然從遠(yuǎn)處跳出來了。 也有一種稱為體霧的技術(shù)。這種霧不是隨物體離照相機(jī)的距離而定,它實(shí)際上是一個(gè)你能看見的真實(shí)對象,并且可以穿越它,從另外一側(cè)出去 -- 當(dāng)你在穿越對象的時(shí)候,視覺上霧的可見程度隨著變化。想象一下穿過云團(tuán) -- 這是體霧的一個(gè)完美例子。體霧的一些好的實(shí)現(xiàn)例子是Quake III一些關(guān)卡中的紅色霧,或新的Rogue Squadron II 之 Lucas Arts的 GameCube 版本。其中有一些是我曾經(jīng)見過的最好的云--大約與你能看見的一樣真實(shí)。
在我們討論霧化的時(shí)候,可能是簡短介紹一下 Alpha 測試和紋理Alpha混合的好時(shí)機(jī)。當(dāng)渲染器往屏幕上畫一個(gè)特定像素時(shí),假定它已經(jīng)通過 Z- 緩沖測試 (在下面定義),我們可能最后做一些Alpha測試。我們可能發(fā)現(xiàn)為了顯示像素后面的某些東西,像素需要透明繪制。這意味著我們必須取得像素的已有值,和我們新的像素值進(jìn)行混和,并把混合結(jié)果的像素值放回原處。這稱為讀-修改-寫操作,遠(yuǎn)比正常的像素寫操作費(fèi)時(shí)。
你可以用不同類型的混合,這些不同的效果被稱為混合模式。直接Alpha混合只是把背景像素的一些百分比值加到新像素的相反百分比值上面。還有加法混合,將舊像素的一些百分比,和特定數(shù)量(而不是百分比)的新像素相加。 這樣效果會(huì)更加鮮明。 (Kyle's Lightsaber在 Jedi Knight II 中的效果)。
每當(dāng)廠商提供新的顯卡時(shí),我們可以得到硬件支持的更新更復(fù)雜的混合模式,從而制作出更多更眩目的效果。GF3+4和最近的Radeon顯卡提供的像素操作,已經(jīng)到了極限。
模板陰影與深度測試 用模板產(chǎn)生陰影效果,事情就變得復(fù)雜而昂貴了。這里不討論太多細(xì)節(jié)(可以寫成一篇單獨(dú)的文章了),其思想是,從光源視角繪制模型視圖,然后用這個(gè)把多邊形紋理形狀產(chǎn)生或投射到受影響的物體表面。
實(shí)際上你是在視野中投射將會(huì)“落”在其他多邊形上面的光體。最后你得到看似真實(shí)的光照,甚至帶有視角在里面。因?yàn)橐獎(jiǎng)討B(tài)創(chuàng)建紋理,并對同一場景進(jìn)行多遍繪制,所以這很昂貴。
你能用眾多不同方法產(chǎn)生陰影,情形時(shí)常是這樣一來,渲染質(zhì)量與產(chǎn)生效果所需要的渲染工作成比例。有所謂的硬陰影或軟陰影之分,而后者較好,因?yàn)樗鼈兏訙?zhǔn)確地模仿陰影通常在真實(shí)世界的行為。 通常有一些被游戲開發(fā)者偏愛的“足夠好”的方法。如要更多的了解陰影,請參考 Dave Salvator的 3D 流水線一文。
深度測試 現(xiàn)在我們開始討論深度測試, 深度測試丟棄隱藏的像素,過度繪制開始起作用。過度繪制非常簡單 – 在一幀中,你數(shù)次繪制一個(gè)像素位置。它以3D場景中Z(深度)方向上存在的元素?cái)?shù)量為基礎(chǔ),也被稱為深度復(fù)雜度。如果你常常太多的過度繪制, -- 舉例來說, 符咒的眩目視覺特效,就象Heretic II,能讓你的幀速率變得很糟糕。當(dāng)屏幕上的一些人們彼此施放符咒時(shí),Heretic II設(shè)計(jì)的一些最初效果造成的情形是,他們在一幀中對屏幕上每個(gè)相同的像素畫了40次! 不用說,這必須調(diào)整,尤其是軟件渲染器,除了將游戲降低到象是滑雪表演外,它根本不能處理這樣的負(fù)荷。深度測試是一種用來決定在相同的像素位置上哪些對象在其它對象前面的技術(shù),這樣我們就能夠避免繪制那些隱藏的對象。
看著場景并想想你所看不見的。 換句話說,是什么在其他場景對象前面,或者隱藏了其他場景對象? 是深度測試作出的這個(gè)決定。
我將進(jìn)一步解釋深度深度如何幫助提高幀速率。想像一個(gè)很瑣細(xì)的場景,大量的多邊形 (或像素)位于彼此的后面,在渲染器獲得他們之間沒有一個(gè)快速的方法丟棄他們。對非Alpha混合的多邊形分類排序( 在Z- 方向上),首先渲染離你最近的那些多邊形,優(yōu)先使用距離最近的像素填充屏幕。所以當(dāng)你要渲染它們后面的像素(由Z或者深度測試決定)時(shí),這些像素很快被丟棄,從而避免了混合步驟并節(jié)省了時(shí)間。如果你從后到前繪制,所有隱藏的對象將被完全繪制,然后又被其他對象完全重寫覆蓋。場景越復(fù)雜,這種情況就越糟糕,所以深度測試是個(gè)好東西。
抗鋸齒 讓我們快速的看一下抗鋸齒。當(dāng)渲染單個(gè)多邊形時(shí),3D 顯卡仔細(xì)檢查已經(jīng)渲染的,并對新的多邊形的邊緣進(jìn)行柔化,這樣你就不會(huì)得到明顯可見的鋸齒形的像素邊緣。兩種技術(shù)方法之一通常被用來處理。 第一種方法是單個(gè)多邊形層次,需要你從視野后面到前面渲染多邊形,這樣每個(gè)多邊形都能和它后面的進(jìn)行適當(dāng)?shù)幕旌?。如果不按序進(jìn)行渲染,最后你會(huì)看見各種奇怪的效果。在第二種方法中,使用比實(shí)際顯示更大的分辯率來渲染整幅幀畫面,然后在你縮小圖像時(shí),尖銳的鋸齒形邊緣就混合消失了。這第二種方法的結(jié)果不錯(cuò),但因?yàn)轱@卡需要渲染比實(shí)際結(jié)果幀更多的像素,所以需要大量的內(nèi)存資源和很高的內(nèi)存帶寬。
多數(shù)新的顯卡能很好地處理這些,但仍然有多種抗鋸齒模式可以供你選擇,因此你可以在性能和質(zhì)量之間作出折衷。對於當(dāng)今流行的各種不同抗鋸齒技術(shù)的更詳細(xì)討論請參見Dave Salvator 的3D 流水線一文。
頂點(diǎn)與像素著色 在結(jié)束討論渲染技術(shù)之前,我們快速的說一下頂點(diǎn)和像素著色,最近它們正引起很多關(guān)注。頂點(diǎn)著色是一種直接使用顯卡硬件特征的方式,不使用API。舉例來說,如果顯卡支持硬件 T & L ,你可以用DirectX或OpenGL編程,并希望你的頂點(diǎn)通過 T & L 單元 (因?yàn)檫@完全由驅(qū)動(dòng)程序處理,所以沒有辦法確信),或者你直接利用顯卡硬件使用頂點(diǎn)著色。它們允許你根據(jù)顯卡自身特征進(jìn)行特別編碼,你自己特殊的編碼使用T & L 引擎,以及為了發(fā)揮你的最大優(yōu)勢,顯卡必須提供的其他別的特征。 事實(shí)上,現(xiàn)在nVidia 和ATI 在他們大量的顯卡上都提供了這個(gè)特征。
不幸的是,顯卡之間表示頂點(diǎn)著色的方法并不一致。你不能象使用DirectX或者OpenGL 那樣,為頂點(diǎn)著色編寫一次代碼就可以在任何顯卡上運(yùn)行,這可是個(gè)壞消息。然而,因?yàn)槟阒苯雍惋@卡硬件交流,它為快速渲染頂點(diǎn)著色可能生成的效果提供最大的承諾。( 如同創(chuàng)造很不錯(cuò)的特效 -- 你能夠使用頂點(diǎn)著色以API沒有提供的方式影響事物)。事實(shí)上,頂點(diǎn)著色正在真的將3D 圖形顯示卡帶回到游戲機(jī)的編碼方式,直接存取硬件,最大限度利用系統(tǒng)的必須知識(shí),而不是依靠API來為你做一切。對一些程序員來說,會(huì)對這種編碼方式感到吃驚,但這是進(jìn)步代價(jià)。
進(jìn)一步闡述,頂點(diǎn)著色是一些在頂點(diǎn)被送到顯卡渲染之前計(jì)算和運(yùn)行頂點(diǎn)效果程序或者例程。你可以在主CPU上面用軟件來做這些事情,或者使用顯卡上的頂點(diǎn)著色。 為動(dòng)畫模型變換網(wǎng)格是頂點(diǎn)程序的主選。
像素著色是那些你寫的例程,當(dāng)繪制紋理時(shí),這些例程就逐個(gè)像素被執(zhí)行。你有效地用這些新的例程推翻了顯卡硬件正常情況做的混合模式運(yùn)算。這允許你做一些很不錯(cuò)的像素效果, 比如,使遠(yuǎn)處的紋理模糊,添加炮火煙霧, 產(chǎn)生水中的反射效果等。一旦 ATI 和 nVidia 能實(shí)際上就像素著色版本達(dá)成一致( DX9's 新的高級陰影語言將會(huì)幫助促進(jìn)這一目標(biāo)), 我一點(diǎn)不驚訝DirectX 和OpenGL采用Glide的方式-- 有幫助開始, 但最終不是把任何顯卡發(fā)揮到極限的最好方法。我認(rèn)為我會(huì)有興趣觀望將來。
最后(In Closing...) 最終,渲染器是游戲程序員最受評判的地方。在這個(gè)行業(yè),視覺上的華麗非常重要,因此它為知道你正在做的買單。對于渲染器程序員,最壞的因素之一就是3D 顯卡工業(yè)界變化的速度。一天,你正在嘗試使透明圖像正確地工作;第二天 nVidia 正在做頂點(diǎn)著色編程的展示。而且發(fā)展非常快,大致上,四年以前為那個(gè)時(shí)代的 3D 顯卡寫的代碼現(xiàn)在已經(jīng)過時(shí)了,需要全部重寫。 甚至John Carmack 這樣描述過,他知道四年以前為充分發(fā)揮那個(gè)時(shí)期顯卡的性能所寫的不錯(cuò)的代碼,如今很平凡 -- 因此他產(chǎn)生了為每個(gè)新的id項(xiàng)目完全重寫渲染器的欲望。Epic 的Tim Sweeney贊同 -- 這里是去年他給我的評論:
我們已經(jīng)足足花費(fèi)了9個(gè)月時(shí)間來更換所有的渲染代碼。最初的 Unreal 被設(shè)計(jì)為軟件渲染和后來擴(kuò)展為硬件渲染。下一代引擎被設(shè)計(jì)為 GeForce 及更好的圖形顯示卡,且多邊形吞吐量是Unreal Tournament的100倍。
這需要全部替換渲染器。很幸運(yùn),該引擎模塊化程度足夠好,我們可以保持引擎的其余部分—編輯器,物理學(xué),人工智能,網(wǎng)絡(luò)--不改動(dòng),盡管我們一直在以許多方式改進(jìn)這些部分。
搭配長篇文章的短篇報(bào)導(dǎo)(Sidebar):API -- 祝福和詛咒 那么什么是API? 它是應(yīng)用程序編程接口,將不一致的后端用一致的前端呈現(xiàn)出來。舉例來說,很大程度上每種3D顯示卡的3D實(shí)現(xiàn)方式都有所差別。然而,他們?nèi)慷汲尸F(xiàn)一個(gè)一致的前端給最終使用者或者程序員,所以他們知道他們?yōu)閄 3D顯示卡寫的代碼將會(huì)在Y 3D顯示卡上面有相同的結(jié)果。好吧,不管怎樣理論上是那樣。 大約在三年以前這可能是相當(dāng)真實(shí)的陳述,但自那以后,在nVidia 公司的引領(lǐng)下,3D顯卡行業(yè)的事情發(fā)生了變化。
如今在PC領(lǐng)域,除非你正計(jì)劃建造自己的軟件光柵引擎,使用CPU來繪制你所有的精靈,多邊形和粒子 -- 而且人們?nèi)匀辉谶@樣做。跟Unreal一樣,Age of Empires II: Age of Kings有一個(gè)優(yōu)秀的軟件渲染器 – 否則你將使用兩種可能的圖形API,OpenGL或者 DirectX 之一。OpenGL是一種真正的跨平臺(tái)API (使用這種API寫的軟件可以在Linux,Windows和MacOS上運(yùn)行。), 而且有多年的歷史了,為人所熟知,但也開始慢慢地顯示出它的古老。 大約在四年以前,定義OpenGL驅(qū)動(dòng)特征集一直是所有顯示卡廠商工作的方向。
然而,一旦在目標(biāo)達(dá)成以后,沒有預(yù)先制定特征工作方向的路線圖,這時(shí)候,所有的顯卡開發(fā)商開始在特征集上分道揚(yáng)鑣,使用OpenGL擴(kuò)展。
3dfx 創(chuàng)造了T- 緩沖。 nVidia 努力尋求硬件變換和光照計(jì)算。Matrox努力獲取凹凸貼圖。等等。 我以前說過的一句話,"過去幾年以來,3D顯示卡領(lǐng)域的事情發(fā)生了變化。"委婉地說明了這一切。
無論如何,另一個(gè)可以選擇的API是 DirectX。這受Microsoft公司控制,且在PC 和 Xbox 上被完美地支持。由于明顯的原因,DirectX 沒有Apple或者 Linux 版本。因?yàn)镸icrosoft控制著 DirectX,大體上它容易更好地集成在Windows里面。
OpenGL和DirectX之間的基本差別是前者由‘社區(qū)’擁有,而后者由Microsoft擁有。如果你想要 DirectX 為你的 3D 顯示卡支持一個(gè)新的特征,那么你需要游說微軟,希望采納你的愿望,并等待新的 DirectX發(fā)行版本。對于OpenGL,由于顯示卡制造商為3D顯示卡提供驅(qū)動(dòng)程序,你能夠通過OpenGL擴(kuò)展立即獲得顯示卡的新特征。這是好,但作為游戲開發(fā)者,當(dāng)你為游戲編碼的時(shí)候,你不能指望它們很普遍。它們可能讓你的游戲速度提升50%,但你不能要求別人有一塊GeForce 3 來跑你的游戲。好吧,你可以這么做,但如果你想來年還在這個(gè)行業(yè)的話,這是個(gè)相當(dāng)愚蠢的主意。
這是對這個(gè)問題極大的簡單化,對我所有描述的也有各種例外情況,但這里一般的思想是很確實(shí)的。對于DirectX ,在任何既定時(shí)間你容易確切地知道你能從顯示卡獲得的特征,如果一個(gè)特征不能獲得,DirectX 將會(huì)用軟件模擬它(也不總是一件好事情,因?yàn)檫@樣有時(shí)侯非常的慢,但那是另外一回事)。對于OpenGL,你可以更加貼近顯示卡的特征,但代價(jià)是不能確定將會(huì)獲得的準(zhǔn)確特征。
|