遊戲引擎全剖析(3)

 第3部份: 內存使用,特效和API

 


關於內存使用的思考
  讓我們想一想,在今天實際上是如何使用3D 顯卡內存的以及在將來又會如何使用。 如今絕大多數3D顯卡處理32位像素顏色,8位紅色, 8位藍色,8 位綠色,和 8 位透明度。這些組合的紅,藍和綠256個色度,可以組成 16。7 百萬種顏色-- 那是你我可以在一個監視器上看見的所有顏色。 

  那麼,遊戲設計大師John Carmack 爲什麼要求 64 位顏色分辨率呢? 如果我們看不出區別,又有什麼意義呢? 意義是: 比如說, 有十幾個燈光照射模型上的點,顏色顏色各不相同。 我們取模型的最初顏色,然後計算一個燈光的照射,模型顏色值將改變。 然後我們計算另外的一個燈光, 模型顏色值進一步改變。 這裏的問題是,因爲顏色值只有8位,在計算了4個燈光之後,8位的顏色值將不足以給我們最後的顏色較好的分辨率和表現。分辨率的不足是由量化誤差導致的,本質原因是由於位數不足引起的舍入誤差。 

  你能很快地用盡位數,而且同樣地,所有的顏色被清掉。每顏色16 或 32 位,你有一個更高分辨率,因此你能夠反覆着色以適當地表現最後的顏色。這樣的顏色深度很快就能消耗大量的存儲空間。我們也應提到整個顯卡內存與紋理內存。這裏所要說的是,每個3D 顯卡實際只有有限的內存,而這些內存要存儲前端和後端緩衝區,Z 緩衝區,還有所有的令人驚奇的紋理。最初的 Voodoo1 顯卡只有2MB顯存,後來 Riva TNT提高到16MB顯存。然後 GeForce 和 ATI Rage有32MB顯存, 現在一些 GeForce 2 到 4的顯卡和 Radeons 帶有 64MB 到128MB 的顯存。 這爲什麼重要? 好吧,讓我們看一些數字…

  比如你想讓你的遊戲看起來最好,所以你想要讓它以32位屏幕, 1280x1024分辨率和32位 Z- 緩衝跑起來。 好,屏幕上每個像素4個字節,外加每個像素4字節的Z-緩衝,因爲都是每像素32位。我們有1280x1024 個像素 – 也就是 1,310,720個像素。基於前端緩衝區和Z-緩衝區的字節數,這個數字乘以8,是 10,485,760字節。包括一個後端緩衝區,這樣是 1280x1024x12, 也就是 15,728,640 字節, 或 15MB。 在一個 16MB 顯存的顯卡上,就只給我們剩下1MB 來存儲所有的紋理。 現在如果最初的紋理是真32 位或 4字節寬,那麼我們每幀能在顯卡上存儲 1MB/4字節每像素 = 262,144個像素。這大約是4 個 256x256 的紋理頁面。 

  很清楚,上述例子表明,舊的16MB 顯卡沒有現代遊戲表現其絢麗畫面所需要的足夠內存。很明顯,在它繪製畫面的時候,我們每幀都必須重新把紋理裝載到顯卡。實際上,設計AGP總線的目的就是完成這個任務,不過, AGP 還是要比 3D 掀卡的幀緩衝區慢,所以你會受到性能上的一些損失。很明顯,如果紋理由32位降低到16位,你就能夠通過AGP以較低的分辨率傳送兩倍數量的紋理。如果你的遊戲以每個像素比較低的色彩分辨率跑, 那麼就可以有更多的顯示內存用來保存常用的紋理 (稱爲高速緩存紋理) 。 但實際上你永遠不可能預知使用者將如何設置他們的系統。如果他們有一個在高分辨率和顏色深度跑的顯卡,那麼他們將會更可能那樣設定他們的顯卡。



  我們現在開始講霧,它是某種視覺上的效果。如今絕大多數的引擎都能處理霧, 因爲霧非常方便地讓遠處的世界淡出視野,所以當模型和場景地理越過觀察體後平面進入視覺範圍內時,你就不會看見它們突然從遠處跳出來了。 也有一種稱爲體霧的技術。這種霧不是隨物體離照相機的距離而定,它實際上是一個你能看見的真實對象,並且可以穿越它,從另外一側出去 -- 當你在穿越對象的時候,視覺上霧的可見程度隨着變化。想象一下穿過雲團 -- 這是體霧的一個完美例子。體霧的一些好的實現例子是Quake III一些關卡中的紅色霧,或新的Rogue Squadron II 之 Lucas Arts的 GameCube 版本。其中有一些是我曾經見過的最好的雲--大約與你能看見的一樣真實。

  在我們討論霧化的時候,可能是簡短介紹一下 Alpha 測試和紋理Alpha混合的好時機。當渲染器往屏幕上畫一個特定像素時,假定它已經通過 Z- 緩衝測試 (在下面定義),我們可能最後做一些Alpha測試。我們可能發現爲了顯示像素後面的某些東西,像素需要透明繪製。這意味着我們必須取得像素的已有值,和我們新的像素值進行混和,並把混合結果的像素值放回原處。這稱爲讀-修改-寫操作,遠比正常的像素寫操作費時。 

  你可以用不同類型的混合,這些不同的效果被稱爲混合模式。直接Alpha混合只是把背景像素的一些百分比值加到新像素的相反百分比值上面。還有加法混合,將舊像素的一些百分比,和特定數量(而不是百分比)的新像素相加。 這樣效果會更加鮮明。 (Kyle's Lightsaber在 Jedi Knight II 中的效果)。

  每當廠商提供新的顯卡時,我們可以得到硬件支持的更新更復雜的混合模式,從而製作出更多更眩目的效果。GF3+4和最近的Radeon顯卡提供的像素操作,已經到了極限。


模板陰影與深度測試
  用模板產生陰影效果,事情就變得複雜而昂貴了。這裏不討論太多細節(可以寫成一篇單獨的文章了),其思想是,從光源視角繪製模型視圖,然後用這個把多邊形紋理形狀產生或投射到受影響的物體表面。 

  實際上你是在視野中投射將會“落”在其他多邊形上面的光體。最後你得到看似真實的光照,甚至帶有視角在裏面。因爲要動態創建紋理,並對同一場景進行多遍繪製,所以這很昂貴。 

  你能用衆多不同方法產生陰影,情形時常是這樣一來,渲染質量與產生效果所需要的渲染工作成比例。有所謂的硬陰影或軟陰影之分,而後者較好,因爲它們更加準確地模仿陰影通常在真實世界的行爲。 通常有一些被遊戲開發者偏愛的“足夠好”的方法。如要更多的瞭解陰影,請參考 Dave Salvator的 3D 流水線一文。


深度測試
  現在我們開始討論深度測試, 深度測試丟棄隱藏的像素,過度繪製開始起作用。過度繪製非常簡單 – 在一幀中,你數次繪製一個像素位置。它以3D場景中Z(深度)方向上存在的元素數量爲基礎,也被稱爲深度複雜度。如果你常常太多的過度繪製, -- 舉例來說, 符咒的眩目視覺特效,就象Heretic II,能讓你的幀速率變得很糟糕。當屏幕上的一些人們彼此施放符咒時,Heretic II設計的一些最初效果造成的情形是,他們在一幀中對屏幕上每個相同的像素畫了40次! 不用說,這必須調整,尤其是軟件渲染器,除了將遊戲降低到象是滑雪表演外,它根本不能處理這樣的負荷。深度測試是一種用來決定在相同的像素位置上哪些對象在其它對象前面的技術,這樣我們就能夠避免繪製那些隱藏的對象。 

  看着場景並想想你所看不見的。 換句話說,是什麼在其他場景對象前面,或者隱藏了其他場景對象? 是深度測試作出的這個決定。 

  我將進一步解釋深度深度如何幫助提高幀速率。想像一個很瑣細的場景,大量的多邊形 (或像素)位於彼此的後面,在渲染器獲得他們之間沒有一個快速的方法丟棄他們。對非Alpha混合的多邊形分類排序( 在Z- 方向上),首先渲染離你最近的那些多邊形,優先使用距離最近的像素填充屏幕。所以當你要渲染它們後面的像素(由Z或者深度測試決定)時,這些像素很快被丟棄,從而避免了混合步驟並節省了時間。如果你從後到前繪製,所有隱藏的對象將被完全繪製,然後又被其他對象完全重寫覆蓋。場景越複雜,這種情況就越糟糕,所以深度測試是個好東西。


抗鋸齒
  讓我們快速的看一下抗鋸齒。當渲染單個多邊形時,3D 顯卡仔細檢查已經渲染的,並對新的多邊形的邊緣進行柔化,這樣你就不會得到明顯可見的鋸齒形的像素邊緣。兩種技術方法之一通常被用來處理。 第一種方法是單個多邊形層次,需要你從視野後面到前面渲染多邊形,這樣每個多邊形都能和它後面的進行適當的混合。如果不按序進行渲染,最後你會看見各種奇怪的效果。在第二種方法中,使用比實際顯示更大的分辯率來渲染整幅幀畫面,然後在你縮小圖像時,尖銳的鋸齒形邊緣就混合消失了。這第二種方法的結果不錯,但因爲顯卡需要渲染比實際結果幀更多的像素,所以需要大量的內存資源和很高的內存帶寬。

  多數新的顯卡能很好地處理這些,但仍然有多種抗鋸齒模式可以供你選擇,因此你可以在性能和質量之間作出折衷。對於當今流行的各種不同抗鋸齒技術的更詳細討論請參見Dave Salvator 的3D 流水線一文。


頂點與像素着色
  在結束討論渲染技術之前,我們快速的說一下頂點和像素着色,最近它們正引起很多關注。頂點着色是一種直接使用顯卡硬件特徵的方式,不使用API。舉例來說,如果顯卡支持硬件 T & L ,你可以用DirectX或OpenGL編程,並希望你的頂點通過 T & L 單元 (因爲這完全由驅動程序處理,所以沒有辦法確信),或者你直接利用顯卡硬件使用頂點着色。它們允許你根據顯卡自身特徵進行特別編碼,你自己特殊的編碼使用T & L 引擎,以及爲了發揮你的最大優勢,顯卡必須提供的其他別的特徵。 事實上,現在nVidia 和ATI 在他們大量的顯卡上都提供了這個特徵。 

  不幸的是,顯卡之間表示頂點着色的方法並不一致。你不能象使用DirectX或者OpenGL 那樣,爲頂點着色編寫一次代碼就可以在任何顯卡上運行,這可是個壞消息。然而,因爲你直接和顯卡硬件交流,它爲快速渲染頂點着色可能生成的效果提供最大的承諾。( 如同創造很不錯的特效 -- 你能夠使用頂點着色以API沒有提供的方式影響事物)。事實上,頂點着色正在真的將3D 圖形顯示卡帶回到遊戲機的編碼方式,直接存取硬件,最大限度利用系統的必須知識,而不是依靠API來爲你做一切。對一些程序員來說,會對這種編碼方式感到吃驚,但這是進步代價。

  進一步闡述,頂點着色是一些在頂點被送到顯卡渲染之前計算和運行頂點效果程序或者例程。你可以在主CPU上面用軟件來做這些事情,或者使用顯卡上的頂點着色。 爲動畫模型變換網格是頂點程序的主選。

  像素着色是那些你寫的例程,當繪製紋理時,這些例程就逐個像素被執行。你有效地用這些新的例程推翻了顯卡硬件正常情況做的混合模式運算。這允許你做一些很不錯的像素效果, 比如,使遠處的紋理模糊,添加炮火煙霧, 產生水中的反射效果等。一旦 ATI 和 nVidia 能實際上就像素着色版本達成一致( DX9's 新的高級陰影語言將會幫助促進這一目標), 我一點不驚訝DirectX 和OpenGL採用Glide的方式-- 有幫助開始, 但最終不是把任何顯卡發揮到極限的最好方法。我認爲我會有興趣觀望將來。


最後(In Closing...)
  最終,渲染器是遊戲程序員最受評判的地方。在這個行業,視覺上的華麗非常重要,因此它爲知道你正在做的買單。對於渲染器程序員,最壞的因素之一就是3D 顯卡工業界變化的速度。一天,你正在嘗試使透明圖像正確地工作;第二天 nVidia 正在做頂點着色編程的展示。而且發展非常快,大致上,四年以前爲那個時代的 3D 顯卡寫的代碼現在已經過時了,需要全部重寫。 甚至John Carmack 這樣描述過,他知道四年以前爲充分發揮那個時期顯卡的性能所寫的不錯的代碼,如今很平凡 -- 因此他產生了爲每個新的id項目完全重寫渲染器的慾望。Epic 的Tim Sweeney贊同 -- 這裏是去年他給我的評論: 

  我們已經足足花費了9個月時間來更換所有的渲染代碼。最初的 Unreal 被設計爲軟件渲染和後來擴展爲硬件渲染。下一代引擎被設計爲 GeForce 及更好的圖形顯示卡,且多邊形吞吐量是Unreal Tournament的100倍。 

  這需要全部替換渲染器。很幸運,該引擎模塊化程度足夠好,我們可以保持引擎的其餘部分—編輯器,物理學,人工智能,網絡--不改動,儘管我們一直在以許多方式改進這些部分。

  搭配長篇文章的短篇報導(Sidebar):API -- 祝福和詛咒
  那麼什麼是API? 它是應用程序編程接口,將不一致的後端用一致的前端呈現出來。舉例來說,很大程度上每種3D顯示卡的3D實現方式都有所差別。然而,他們全部都呈現一個一致的前端給最終使用者或者程序員,所以他們知道他們爲X 3D顯示卡寫的代碼將會在Y 3D顯示卡上面有相同的結果。好吧,不管怎樣理論上是那樣。 大約在三年以前這可能是相當真實的陳述,但自那以後,在nVidia 公司的引領下,3D顯卡行業的事情發生了變化。 

  如今在PC領域,除非你正計劃建造自己的軟件光柵引擎,使用CPU來繪製你所有的精靈,多邊形和粒子 -- 而且人們仍然在這樣做。跟Unreal一樣,Age of Empires II: Age of Kings有一個優秀的軟件渲染器 – 否則你將使用兩種可能的圖形API,OpenGL或者 DirectX 之一。OpenGL是一種真正的跨平臺API (使用這種API寫的軟件可以在Linux,Windows和MacOS上運行。), 而且有多年的歷史了,爲人所熟知,但也開始慢慢地顯示出它的古老。 大約在四年以前,定義OpenGL驅動特徵集一直是所有顯示卡廠商工作的方向。

  然而,一旦在目標達成以後,沒有預先制定特徵工作方向的路線圖,這時候,所有的顯卡開發商開始在特徵集上分道揚鑣,使用OpenGL擴展。

  3dfx 創造了T- 緩衝。 nVidia 努力尋求硬件變換和光照計算。Matrox努力獲取凹凸貼圖。等等。 我以前說過的一句話,"過去幾年以來,3D顯示卡領域的事情發生了變化。"委婉地說明了這一切。 

  無論如何,另一個可以選擇的API是 DirectX。這受Microsoft公司控制,且在PC 和 Xbox 上被完美地支持。由於明顯的原因,DirectX 沒有Apple或者 Linux 版本。因爲Microsoft控制着 DirectX,大體上它容易更好地集成在Windows裏面。 

  OpenGL和DirectX之間的基本差別是前者由‘社區’擁有,而後者由Microsoft擁有。如果你想要 DirectX 爲你的 3D 顯示卡支持一個新的特徵,那麼你需要遊說微軟,希望採納你的願望,並等待新的 DirectX發行版本。對於OpenGL,由於顯示卡製造商爲3D顯示卡提供驅動程序,你能夠通過OpenGL擴展立即獲得顯示卡的新特徵。這是好,但作爲遊戲開發者,當你爲遊戲編碼的時候,你不能指望它們很普遍。它們可能讓你的遊戲速度提升50%,但你不能要求別人有一塊GeForce 3 來跑你的遊戲。好吧,你可以這麼做,但如果你想來年還在這個行業的話,這是個相當愚蠢的主意。

  這是對這個問題極大的簡單化,對我所有描述的也有各種例外情況,但這裏一般的思想是很確實的。對於DirectX ,在任何既定時間你容易確切地知道你能從顯示卡獲得的特徵,如果一個特徵不能獲得,DirectX 將會用軟件模擬它(也不總是一件好事情,因爲這樣有時侯非常的慢,但那是另外一回事)。對於OpenGL,你可以更加貼近顯示卡的特徵,但代價是不能確定將會獲得的準確特徵。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章