1. 程式人生 > >遊戲引擎剖析

遊戲引擎剖析

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

原文作者:Jake Simpson
譯者: 向海
Email:[email protected] 

第1部分: 遊戲引擎介紹, 渲染和構造3D世界

介紹
  自Doom遊戲時代以來我們已經走了很遠。 DOOM不只是一款偉大的遊戲,它同時也開創了一種新的遊戲程式設計模式: 遊戲 "引擎"。 這種模組化,可伸縮和擴充套件的設計觀念可以讓遊戲玩家和程式設計者深入到遊戲核心,用新的模型,場景和聲音創造新的遊戲, 或向已有的遊戲素材中新增新的東西。大量的新遊戲根據已經存在的遊戲引擎開發出來,而大多數都以ID公司的Quake引擎為基礎, 這些遊戲包括Counter  Strike, Team Fortress, Tac Ops, Strike Force, 以及Quake Soccer。Tac Ops 和Strike Force 都使用了Unreal Tournament 引擎。事實上, "遊戲引擎" 已經成為遊戲玩家之間交流的標準用語,但是究竟引擎止於何處,而遊戲又從哪裡開始呢?畫素的渲染,聲音的播放,怪物的思考以及遊戲事件的觸發,遊戲中所有這一切的幕後又是什麼呢? 如果你曾經思考過這些問題, 而且想要知道更多驅動遊戲進行的東西,那麼這篇文章正好可以告訴你這些。 本文分多個部分深入剖析了遊戲引擎的核心, 特別是Quake引擎,因為我最近工作的公司Raven Software已經在Quake引擎的基礎上開發出了多款遊戲,其中包括著名的Soldier of Fortune 。 


開始
  讓我們首先來看看一個遊戲引擎和遊戲本身之間的主要區別。 許多人們會混淆遊戲引擎和整個遊戲 。這有點像把一個汽車發動機和整個汽車混淆起來一樣 。 你能夠從汽車裡面取出發動機, 建造另外一個外殼,再使用發動機一次。 遊戲也像那。 遊戲引擎被定義為所有的非遊戲特有的技術。 遊戲部份是被稱為 '資產' 的所有內容 (模型,動畫,聲音,人工智慧和物理學)和為了使遊戲執行或者控制如何執行而特別需要的程式程式碼, 比如說AI--人工智慧。 

  對於曾經看過 Quake 遊戲結構的人來說, 遊戲引擎就是 Quake。exe ,而遊戲部分則是 QAGame。dll 和 CGame。dll 。 如果你不知道這是什麼意思, 也沒有什麼關係;在有人向我解釋它以前, 我也不知道是什麼意思。 但是你將會完全明白它的意思。 這篇遊戲引擎指導分為十一個部份。 是的, 從數量上來說,總共是十一個部份! 每個部分大概3000字左右。現在就從第一部分開始我們的探索吧,深入我們所玩遊戲的核心,在這裡我們將瞭解一些基本的東西, 為後面的章節作鋪墊。。。


渲染器
  讓我們從渲染器來開始遊戲引擎設計的探討吧, 我們將從遊戲開發者(本文作者的背景)的角度來探討這些問題。事實上,在本文的各個段落,我們將常常從遊戲開發者的角度探討, 也讓您像我們一樣思考問題! 

  什麼是渲染器,為什麼它又這麼重要呢?好吧,如果沒有它,你將什麼也看不到。它讓遊戲場景視覺化,讓玩家/觀眾可以看見場景,從而讓玩家能夠根據螢幕上所看到的東西作出適當的決斷。 儘管我們下面的探討可能讓新手感到有些恐懼,先別去理會它。 渲染器做些什麼?為什麼它是必須的?我們將會解釋這些重要問題。 

  當構造一個遊戲引擎的時候, 你通常想做的第一件事情就是建造渲染器。 因為如果看不見任何東西 – 那麼你又如何知道你的程式程式碼在工作呢? 超過 50% 的 CPU 處理時間花費在渲染器上面; 通常也是在這個部分,遊戲開發者將會受到最苛刻的評判。 如果我們在這個部分表現很差,事情將會變得非常糟糕, 我們的程式技術,我們的遊戲和我們的公司將在 10 天之內變成業界的笑話。 它也是我們最依賴於外部廠商和力量的地方,在這裡他們將處理最大限度的潛在操作目標。 如此說來, 建造一個渲染器確實不象聽起來那麼吸引人(事實如此), 但如果沒有一個好的渲染器, 遊戲或許永遠不會躋身於排行榜前10 名。 

  如今,在螢幕上生成畫素,涉及到 3D 加速卡, API ,三維空間數學, 對 3D 硬體如何工作的理解等等。對於主機(遊戲機)遊戲來說,也需要相同型別的知識,但是至少對於主機, 你不必去嘗試擊中一個移動中的目標。 因為一臺主機的硬體配置是固定的 "時間快照", 和PC(個人計算機)不同, 在一臺主機的生命期中,它的硬體配置不會改變。 

  在一般意義上,渲染器的工作就是要創造出遊戲的視覺閃光點,實際上達到這個目標需要大量的技巧。3D圖形本質上是用最少的努力創造出最大效果的一門藝術, 因為額外的 3D 處理在處理器時間和和記憶體頻寬方面都是極為昂貴的。 它也是一種預算, 要弄清楚你想在什麼地方花費處理器時間,而你寧願在什麼地方節省一些從而達到最好的整體效果。 接下來我們將會介紹一些這方面的工具,以及怎樣更好的用它們讓遊戲引擎工作。


建造3D世界
  最近,當我和一位從事計算機圖形方面工作長達數年之久的人會談時,她向我吐露道, 當她第一次看到實時操縱計算機 3D 圖象時, 她不知道這是怎麼實現的, 也不知道計算機如何能夠儲存 3D 圖象。 今天這對於在大街上的普通人來說或許是真實的,即使他們時常玩 PC 遊戲, 遊戲機遊戲, 或街機遊戲。

  下面我們將從遊戲設計者的角度討論創造 3D 世界的一些細節,你也應該看一看 Dave Salvator 所寫的“3D 管線導論“,以便對3D 圖象生成的主要過程有一個整體的瞭解。

  3D 物體(物件)被儲存成 3D 世界中的一系列點(被稱為頂點), 彼此之間有相互關係,所以計算機知道如何在世界中的這些點之間畫線或者是填充表面。 一個立方體由8個點組成,每個角一個點。立方體有6個表面, 分別代表它的每一個面。 這就是 3D 物件儲存的基礎。 對於一些比較複雜的 3D 物體, 比如說一個 Quake 的關卡,將有數以千計(有時數以十萬計)的頂點, 和數以千計的多邊形表面。 

  參見上圖的線框表示(注:原文在這裡有一幅圖)。 本質上與上面的立方體例子類似, 它僅僅是由許許多多的小多邊形組成的一些複雜場景。模型和世界如何儲存是渲染器的一部份功能, 而不屬於應用程式/遊戲部份。 遊戲邏輯不需要知道物件在記憶體中如何表示, 也不需要知道渲染器將怎樣把他們顯示出來。 遊戲只是需要知道渲染器將使用正確的視野去表示物件, 並將在正確的動畫幀中把正確的模型顯示出來。

  在一個好的引擎中,渲染器應該是可以完全被一個新的渲染器替換掉, 並且不需要去改動遊戲的一行程式碼。許多跨平臺引擎, 而且許多自行開發的遊戲機引擎就是這樣的,如 Unreal 引擎, --舉例來說, 這個遊戲 GameCube 版本的渲染器就可以被你任意的替換掉。 

  讓我們再看看內部的表示方法—除了使用座標系統,還有其他方法可以在計算機記憶體裡表示空間的點。在數學上,你可以使用一個方程式來描述直線或曲線, 並得到多邊形, 而幾乎所有的 3D 顯示卡都使用多邊形來作為它們的最終渲染圖元。 一個圖元就是你在任何顯示卡上面所能使用的最低階的繪製(渲染)單位,幾乎所有的硬體都是使用三個頂點的多邊形(三角形)。 新一代的 nVidia 和 ATI 顯示卡可以允許你以數學方式渲染(被稱為高次表面), 但因為這不是所有圖形卡的標準, 你還不能靠它作為渲染策略。

  從計算的角度來看,這通常有些昂貴,但它時常是新的實驗技術的基礎,例如,地表的渲染,或者對物件銳利的邊緣進行柔化。 我們將會在下面的曲面片小節中更進一步介紹這些高次表面。


剔除概觀
  問題來了。 我現在有一個由幾十萬個頂點/多邊形描述的世界。 我以第一人稱視角位於我們這個 3D 世界的一邊。 在視野中可以看見世界的一些多邊形, 而另外一些則不可見, 因為一些物體, 比如一面看得見的牆壁, 遮擋住了它們。 即使是最好的遊戲編碼人員, 在目前的 3D 顯示卡上, 在一個視野中也不能處理 300,000個三角形且仍然維持 60fps (一個主要目標)。 顯示卡不能處理它, 因此我們必須寫一些程式碼,在把它們交給顯示卡處理之前除去那些看不見的多邊形。 這個過程被稱為剔除。

  有許多不同的剔除方法。 在深入瞭解這些之前,讓我們探討一下為什麼圖形顯示卡不能處理超高數量的多邊形。 我是說,最新的圖形卡每秒鐘不能處理幾百萬個多邊形嗎?它不應該能夠處理嗎? 首先,你必須理解市場銷售宣稱的多邊形生成率和真實世界的多邊形生成率。 行銷上宣稱的多邊形生成率是圖形顯示卡理論上能夠達到的多邊形生成率。 

  如果全部多邊形都在螢幕上, 相同的紋理,相同的尺寸大小, 正在往顯示卡上傳送多邊形的應用程式除了傳送多邊形以外什麼也不做, 這時顯示卡能處理多少多邊形數量, 就是圖形晶片廠商呈現給你的數字。 

  然而,在真實的遊戲情形中,應用程式時常在後臺做著許多其他的事情 -- 多邊形的 3D 變換, 光照計算, 拷貝較多的紋理到顯示卡記憶體, 等等。 不僅紋理要送到顯示卡, 而且還有每個多邊形的細節。一些比較新的顯示卡允許你實際上在顯示卡記憶體本身裡面儲存模型/世界幾何細節, 但這可能是昂貴的,將會耗光紋理正常可以使用的空間,所以你最好能確定每一幀都在使用這些模型的頂點, 否則你只是在浪費顯示卡上的儲存空間。 我們就說到這裡了。 重要的是,在實際使用顯示卡時,並不必然就能達到你在顯示卡包裝盒上所看到的那些指標,如果你有一個比較慢速的CPU , 或沒有足夠的記憶體時,這種差異就尤為真實。


基本的剔除方法
  最簡單的剔除方式就是把世界分成區域, 每個區域有一個其他可見區域的列表。 那樣, 你只需要顯示針對任何給定點的可見部分。 如何生成可見視野區域的列表是技巧所在。 再者, 有許多方法可以用來生成可見區域列表, 如 BSP 樹, 窺孔等等。 

  可以肯定,當談論 DOOM 或 QUAKE 時,你已經聽到過使用 BSP 這個術語了。 它表示二叉空間分割。 

  BSP 是一種將世界分成小區域的的方法,通過組織世界的多邊形,容易確定哪些區域是可見的而哪些是不可見的 – 從而方便了那些不想做太多繪製工作的基於軟體的渲染器。它同時也以一種非常有效的方式讓你知道你位於世界中的什麼地方。 

  在基於窺孔的引擎 ( 最早由 3D Realms 已經取消的 Prey 專案引入遊戲世界 )裡,每個區域 ( 或房間) 都建造有自己的模型, 通過每個區域的門 ( 或窺孔 )能夠看見另外的區段。 渲染器把每個區域作為獨立的場景單獨繪製。 這就是它的大致原理。 足以說這是任何一個渲染器的必需部份,而且非常重要。 

  儘管一些這樣的技術歸類在 "遮擋剔除"之下,但是他們全部都有同樣的目的: 儘早消除不必要的工作。 對於一個FPS遊戲(第一人稱射擊遊戲) 來說,視野中時常有許多三角形,而且遊戲玩家承擔視野的控制,丟棄或者剔除不可見的三角形就是絕對必要的了。 對空間模擬來說也是這樣的, 你可以看見很遠很遠的地方 – 剔除超過視覺範圍外面的東西就非常重要。 對於視野受到限制的遊戲來說 – 比如 RTS (即時戰略類遊戲)--通常比較容易實現。 通常渲染器的這個部份還是由軟體來完成, 而不是由顯示卡完成, 由顯示卡來做這部分工作只是一個時間問題。


基本的圖形管線流程
  一個簡單的例子,從遊戲到多邊形繪製的圖形管線過程大致是這樣:
    · 遊戲決定在遊戲中有哪些物件, 它們的模型, 使用的紋理, 他們可能在什麼動畫幀,以及它們在遊戲世界裡的位置。 遊戲也決定照相機的位置和方向。

    · 遊戲把這些資訊傳遞給渲染器。以模型為例 ,渲染器首先要檢視模型的大小 ,照相機的位置, 然後決定模型在螢幕上是否全部可見, 或者在觀察者 (照相機視野) 的左邊,在觀察者的後面,或距離很遠而不可見。它甚至會使用一些世界測定方式來計算出模型是否是可見的。 (參見下面這條)

    · 世界視覺化系統決定照相機在世界中的位置,並根據照相機視野決定世界的哪些區域 / 多邊形是可見的。有許多方法可以完成這個任務, 包括把世界分割成許多區域的暴力方法,每個區域直接為"我能從區域 D 看見區域 AB & C", 到更精緻的 BSP(二叉空間分割)世界。 所有通過這些剔除測試的多邊形被傳遞給多邊形渲染器進行繪製。 

    · 對於每一個被傳遞給渲染器的多邊形, 渲染器依照區域性數學 ( 也就是模型動畫) 和世界數學(相對於照相機的位置?)對多邊形進行變換,並檢查決定多邊形是不是背對相機 (也就是遠離照相機)。背面的多邊形被丟棄。 非背面的多邊形由渲染器根據發現的附近燈光照亮。然後渲染器要看多邊形使用的紋理,並且確定 API/ 圖形卡正在使用那種紋理作為它的渲染基礎。 在這裡,多邊形被送到渲染 API,然後再送給顯示卡。 

  很明顯這有些過分簡單化了,但你大概理解了。 下面的圖表摘自Dave Salvator's 3D 管線一文,可以給你多一些具體細節: 

  3D 管線
  - 高層的概觀
   1. 應用程式/ 場景
  ·場景/ 幾何資料庫遍歷
  ·物件的運動,觀察相機的運動和瞄準
  ·物件模型的動畫運動
  ·3D 世界內容的描述
  ·物件的可見性檢查,包括可能的遮擋剔除
  ·細節層次的選擇 (LOD)

  2. 幾何
  ·變換 (旋轉,平移, 縮放)
  ·從模型空間到世界空間的變換 (Direct3D)
  ·從世界空間到觀察空間變換
  ·觀察投影
  ·細節接受/ 拒絕 剔除
  ·背面剔除 (也可以在後面的螢幕空間中做)
  光照
  ·透視分割 - 變換到裁剪空間
  ·裁剪
  ·變換到螢幕空間

  3. 三角形生成
  ·背面剔除 ( 或者在光照計算之前的觀察空間中完成)
  ·斜率/ 角度計算
  ·掃瞄線變換

  4. 渲染 / 光柵化
  ·著色
  ·紋理
  ·霧
  ·Alpha 透明測試
  ·深度緩衝
  ·抗鋸齒 (可選擇的)
  ·顯示

  通常你會把所有的多邊形放到一些列表內, 然後根據紋理對這個列表排序(這樣你只需要對顯示卡傳送一次紋理, 而不是每個多邊形都傳送一次), 等等。在過去,會把多邊形按照它們到相機的距離進行排序,首先繪製那些距離相機最遠的多邊形, 但現在由於 Z 緩衝的出現,這種方法就不是那麼重要了。 當然那些透明的多邊形要除外,它們要在所有的非半透明多邊形繪製之後才能夠繪製 ,這樣一來,所有在它們後面的多邊形就能正確地在場景中顯現出來。 當然,象那樣,實際上你必須得從後到前地繪製那些多邊形。 但時常在任何給定的 FPS 遊戲場景中, 通常沒有太多透明的多邊形。 它可能看起來像有,但實際上與那些不透明的多邊形相比,其比率是相當低的。 

  一旦應用程式將場景傳遞到 API, API 就能利用硬體加速的變換和光照處理 (T&L), 這在如今的 3D 顯示卡中是很平常的事情。 這裡不討論涉及到的矩陣數學(參見Dave的 3D 管線導論),幾何變換允許 3D 顯示卡按照你的嘗試,根據相機在任何時間的位置和方向,在世界的正確角度和位置繪製多邊形。 

  對於每個點或頂點都有大量的計算, 包括裁剪運算,決定任何給定的多邊形實際上是否可見,在螢幕上完全不可見或部分可見。 光照運算,計算紋理色彩明亮程度,這取決於世界的燈光從什麼角度如何投射到頂點上。 過去,處理器處理這些計算,但現在,當代圖形硬體就能為你做這些事情, 這意謂著你的處理器可以去做其他的事情了。很明顯這是件好事情 (tm) ,由於不能指望市面上所有的 3D 顯示卡板上都有T & L, 所以無論如何你自己將必須寫所有的這些例程 (再一次從遊戲開發者角度來說)。 你將在本文各處的不同段落看到 "好事情 ( tm)" 這個詞彙。 我認為,這些特徵為使遊戲看起來更好作出了非常有用的貢獻。 毫不令人吃驚,你也將會看見它的對立面;你猜到了,那就是“壞事情 (tm)”。 我正在嘗試爭取這些詞彙的版權, 你要使用他們就得支付一筆小小的費用喲。


曲面片(高次表面)
  除了三角形,曲面片的使用現在正變得更普遍。 因為他們能用數學表示式來描述幾何 ( 通常涉及某種曲線的幾何形體) ,而不僅僅只是列出大量的多邊形以及在遊戲世界中的位置, 所以曲面片 ( 高次表面的另一個名稱) 非常好。 這樣,你實際上就能夠動態地根據方程式來建立( 和變形 )多邊形網格, 並決定你實際想要從曲面片上看到的多邊形數量。 因此,舉例來說,你可以描述一個管道, 然後在世界中就可以有這種管道的許多樣例。 在一些房間中, 你已經顯示了 10,000個多邊形,你可以說,"因為我們已經顯示了大量的多邊形,而且任何更多的多邊形將會使幀速率下降, 所以這個管道應該只有 100 個多邊形"。 但在另外一個房間中, 視野中只有 5,000個可見的多邊形,你可以說,"因為我們還沒有達到預算可以顯示的多邊形數量 , 所以,現在這個管道能有 500 個多邊形"。 非常美妙的東西 --但你必須首先知道所有這些,並建立網格,這不是無足輕重的。 通過 AGP 傳送同一個物件的曲面方程確實要比傳送其大量頂點節省成本。 SOF2 就使用了這個方法的一種變體來建立它的地表系統。

  事實上現在的 ATI 顯示卡具有 TruForm, 它能帶一個以三角形為基礎的模型,並將該模型轉換為基於高次表面的模型,使其平滑 — 接著再用十倍三角形數量把模型轉換回基於大量三角形的模型 (被稱為retesselation)。然後模型送往管線做進一步的處理。 實際上 ATI 僅僅在 T & L 引擎之前增加了一個階段來處理這個過程。這裡的缺點是,要控制哪些模型需要被平滑處理而哪些又不需要。你常常想要一些邊緣比較尖銳, 比如鼻子,但它卻被不恰當的平滑過了。 這仍然是一種很好的技術,而且我能預見它在將來會被更多的應用。 

  這就是第一部份 -- 我們將會在第二部分繼續介紹光照和紋理,下面的章節會更加深入。

第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 顯示卡片能執行每畫素運算,這種預設觀察角度的不足就真的不再是有力而快速的法則了。 無論是哪一種方法, 到目前為止,沒有遊戲開發者太多的使用; 更多的遊戲能夠且應該使用凹凸貼圖。


快取記憶體抖動 = 糟糕的事物
  紋理快取記憶體的管理遊戲引擎的速度至關重要。 和任何快取記憶體一樣,快取命中很好,而不命中將很糟糕。如果遇到紋理在圖形顯示卡記憶體被頻繁地換入換出的情況,這就是紋理快取記憶體抖動。發生這種情況時,通常API將會廢棄每個紋理,結果是所有的紋理在下一幀將被重新載入,這非常耗時和浪費。對遊戲玩家來說,當API重新載入紋理快取記憶體時,會導致幀速率遲鈍。

  在紋理快取記憶體管理中,有各種不同的技術將紋理快取記憶體抖動減到最少 – 這是確保任何 3D 遊戲引擎速度的一個決定性因素。 紋理管理是件好事情 – 這意味著只要求顯示卡使用紋理一次,而不是重複使用。這聽起來有點自相矛盾,但效果是它意謂著對顯示卡說,"看, 所有這些多邊形全部使用這一個紋理,我們能夠僅僅載入這個紋理一次而不是許多次嗎?" 這阻止API ( 或圖形驅動軟體) 上傳多次向顯示卡載入紋理。象OpenGL這樣的API實際上通常處理紋理快取記憶體管理,意謂著,根據一些規則,比如紋理存取的頻率,API決定哪些紋理儲存在顯示卡上,哪些紋理儲存在主存。 真正的問題來了:a) 你時常無法知道API正在使用的準確規則。 b)你時常要求在一幀中繪製更多的紋理,以致超出了顯示卡記憶體空間所能容納的紋理。 

  另外一種紋理快取記憶體管理技術是我們早先討論的紋理壓縮。很象聲音波形檔案被壓縮成 MP3 檔案,儘管無法達到那樣的壓縮比率,但紋理可以被壓縮。 從聲音波形檔案到MP3的壓縮可以達到 11:1的壓縮比率,而絕大多數硬體支援的紋理壓縮運演算法則只有 4:1 的壓縮比率,儘管如此,這樣能產生很大的差別。 除此之外,在渲染(繪製)過程中,只有在需要時,硬體才動態地對紋理進行解壓縮。這一點非常棒,我們僅僅擦除即將可能用到的表面。

  如上所述,另外一種技術確保渲染器要求顯示卡對每個紋理只繪製一次。確定你想要渲染(繪製)的使用相同紋理的所有多邊形同時送到顯示卡,而不是一個模型在這裡,另一個模型在那裡,然後又回到最初的紋理論。僅僅繪製一次,你也就通過AGP介面傳送一次。Quake III 在其陰影系統就是這麼做的。處理多邊形時,把它們加入到一個內部的陰影列表,一旦所有的多邊形處理完畢,渲染器遍歷紋理列表,就將紋理及所有使用這些紋理的多邊形同時傳送出去。 

  上述過程在使用顯示卡的硬體 T & L(如果支援的話)時,並不怎麼有效。你面臨的結局是,滿螢幕都是使用相同紋理的大量的多邊形小群組,所有多邊形都使用不同的變換矩陣。這意謂著更多的時間花在建立顯示卡的硬體 T & L 引擎 ,更多的時間被浪費了。 無論如何,因為他們有助於對整個模型使用統一的紋理,所以它對實際螢幕上的模型可以有效地工作。但是因為許多多邊形傾向使用相同的牆壁紋理,所以對於世界場景的渲染,它常常就是地獄。通常它沒有這麼嚴重,因為大體而言,世界的紋理不會有那麼大,這樣一來API的紋理快取系統將會替你處理這些,並把紋理保留在顯示卡以備再次使用。 

  在遊戲機上,通常沒有紋理快取記憶體系統(除非你寫一個)。在 PS2 上面,你最好是遠離"一次紋理" 的方法。在 Xbox 上面, 這是不重要的,因為它本身沒有圖形記憶體(它是 UMA 體系結構),且所有的紋理無論如何始終保留在主存之中。 

  事實上,在今天的現代PC FPS 遊戲中,試圖通過AGP介面傳送大量紋理是第二個最通常的瓶頸。最大的瓶頸是實際幾何處理,它要使東西出現在它應該出現的地方。在如今的3D FPS 遊戲中,最耗費時間的工作,顯然是那些計算模型中每個頂點正確的世界位置的數學運算。如果你不把場景的紋理保持在預算之內,僅居其次的就是通過AGP介面傳送大量的紋理了。然而,你確實有能力影響這些。 通過降低頂層的 MIP 級別(還記得系統在哪裡不斷地為你細分紋理嗎?), 你就能夠把系統正在嘗試送到顯示卡的紋理大小減少一半。你的視覺質量會有所下降-- 尤其是在引人注目的電影片斷中--但是你的幀速率上升了。這種方式對網路遊戲尤其有幫助。實際上,Soldier of Fortune II和Jedi Knight II: Outcast這兩款遊戲在設計時針對的顯示卡還不是市場上的大眾主流顯示卡。為了以最大大小觀看他們的紋理,你的3D 顯示卡至少需要有128MB的記憶體。這兩種產品在思想上都是給未來設計的。 

  上面就是第 2 部份。在下面章節中,我們將介紹許多主題,包括記憶體管理,霧效果,深度測試, 抗鋸齒,頂點著色,API等。

第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,你可以更加貼近顯示卡的特徵,但代價是不能確定將會獲得的準確特徵。

第4部份: 模型與動畫,細節級別


角色建模與動畫
  你的角色模型在螢幕上看起來怎麼樣,怎樣容易建立它們,紋理,以及動畫對於現代遊戲試圖完成的`消除不可信`因素來說至關重要。角色模型系統逐漸變得複雜起來, 包括較高的多邊形數量模型, 和讓模型在螢幕上移動的更好方式。

  如今你需要一個骨骼模型系統,有骨架和網格細節層次,單個頂點骨架的評估,骨架動畫忽略,以及比賽中停留的角度忽略。而這些甚至還沒有開始涉及一些你能做的很好的事情,像動畫混合,骨架反向運動學(IK),和單個骨架限制,以及相片真實感的紋理。這個清單還能夠繼續列下去。但是真的,在用專業行話說了所有這些以後,我們在這裡真正談論的是什麼呢?讓我們看看。 

  讓我們定義一個基於網格的系統和一個骨骼動畫系統作為開始。在基於網格的系統,對於每一個動畫幀,你要定義模型網格的每個點在世界中的位置。舉例來說,你有一個包含200 個多邊形的手的模型,有 300 個頂點(注意,在頂點和多邊形之間通常並不是3個對1個的關係,因為大量多邊形時常共享頂點 – 使用條形和扇形,你能大幅減少頂點數量)。如果動畫有 10 幀,那麼你就需要在記憶體中有300個頂點位置的資料。 總共有300 x 10 = 3000 頂點,每個頂點由x,y,z和顏色/alpha資訊組成。你能看見這個增長起來是多麼的快。Quake I,II和 III 都使用了這種系統,這種系統確實有動態變形網格的能力,比如使裙子擺動,或者讓頭髮飄動。

  相比之下,在骨骼動畫系統,網格是由骨架組成的骨骼( 骨架是你運動的物件)。 網格頂點和骨架本身相關,所以它們在模型中的位置都是相對於骨架,而不是網格代表每個頂點在世界中的位置。因此,如果你移動骨架,組成多邊形的頂點的位置也相應改變。這意謂著你只必須使骨骼運動,典型情況大約有 50 個左右的骨架—很明顯極大地節省了記憶體。


骨骼動畫附加的好處
  骨骼動畫的另一個優點是能夠根據影響頂點的一些骨架來分別“估價” 每個頂點。例如,雙臂的骨架運動,肩,脖子而且甚至軀幹都能在肩中影響網格。當你移動軀幹的時候,網格就活像一個角色一樣移動。總的效果是3D角色能夠實現的動畫更加流暢和可信,且需要更少的記憶體。每個人都贏了。 

  當然這裡的缺點是,如果你想要使有機的東西運動且很好,比如說頭髮,或者披肩,為了讓它看起來自然,你最後不得不在裡面放置數量驚人的骨架,這會擡高一些處理時間。 

  基於骨骼的系統能帶給你的一些其他事情是‘忽略’特定層次骨架的能力 -- 說,"我不關心動畫想要對這塊骨架所做的事情,我想要讓它指向世界中的一個特定點"。這很棒。你能讓模型著眼於世界中的事件,或者使他們的腳在他們站著的地面保持水平。這一切非常微妙,但它可以幫助帶給場景附加的真實感。

  在骨骼系統,你甚至可以指定"我需要把這個特別的動畫用於模型的腿,而一個不同的攜槍或射擊動畫在模型軀幹上播放,且那傢伙(角色)叫喊的不同動畫效果在模型的頭部播放"。非常妙。Ghoul2 ( 在Soldier of Fortune II: Double Helix and Jedi Knight I: Outcast中使用了Raven的動畫系統 ) 擁有所有這些好東西,且特別被設計為允許程式設計師使用所有這些忽略能力。這對動畫的節省像你一樣難以相信。像你一樣的動畫上的這次救援不相信. Raven有一個角色行走的動畫和一個站立開火的動畫,並在它同時行走和開火形下把這兩個動畫合併,而不是需要一個動畫表示角色行走並開火。


More Skeletons in the Closet
  先前描述的效果可以通過具有層次的骨骼系統來完成。這是什麼意思呢?意思是每塊骨架實際上的位置相對於它的父親,而不是每個骨架直接位於空間中的地方。這意謂著如果你移動父親骨架,那麼它所有的子孫骨架也跟著移動,在程式碼上不需要任何額外的努力。這是讓你能夠在任何骨架層次改變動畫,而且通過骨骼其餘部分向下傳遞的東西。 

  建立一個沒有層次的骨骼系統是可能的 -- 但那時你不能忽略一個骨架並且預期它工作。你所看到的只是身體上的一個骨架開始了新動畫,除非你實現了某種‘向下傳遞資訊’的系統,否則在該骨架下面的其它骨架保持原來的動畫。首先由一個層次系統開始,你就自動地獲得這些效果。 

  許多今天的動畫系統中正開始出現一些比較新的特徵,如動畫混合,從一個正在播放的動畫轉變到另外一個動畫需要經過一小段時間,而不是立即從一個動畫突然轉變到另外一個。舉例來說,你有個角色在行走,然後他停了下來。你不是僅僅突然地轉變動畫,讓他的腿和腳停在無效位置,而是一秒鐘混合一半,這樣腳似乎自然地移到了新的動畫。不能夠過高的評價這種效果 -- 混合是一個微妙的事情,但如果正確的運用,它真的有些差別。


反向運動學
  反向運動學 (IK) 是被許多人們丟棄的一個專業術語,對它的真實含義沒有多少概念。IK 是如今遊戲裡面一個相對比較新的系統。使用 IK ,程式設計師能夠移動一隻手,或一條腿, 模型的其餘關節自動重新定位,因此模型被正確定向。而且有模型的關節新位置的其餘者他們自己,因此模型正確的被定向。比如,你將會說,"好,手 , 去拾起桌子上的那個杯子"並指出杯子在世界中的位置。手就會移動到那裡,且它後面的身體會調節其自身以便雙臂移動,身體適當彎曲,等等。

  也有和IK相反的事情,叫做前向運動學,本質上與 IK 工作的次序相反。想像一隻手,手附著在手臂上,手臂附著在身體上。現在想像你重重地擊中了身體。通常手臂像連迦般抽動,且手臂末梢的手隨之振動。 IK 能夠移動身體,並讓其餘的四肢自己以真實的方式移動。基本上它需要動畫師設定每種工作的大量資訊 -- 像關節所能通過的運動範圍,如果一塊骨架前面的骨架移動,那麼這塊骨架將移動多少百分比,等等。

  和它現在一樣,儘管很好,它是一個很大的處理問題,不用它你可以有不同的動畫組合而脫身。值得注意的是,真正的 IK 解決辦法需要一個層次骨骼系統而不是一個模型空間系統 -- 否則它們都耗時太多以致無法恰當地計算每個骨架。


LOD幾何系統
  最後,我們應當快速討論一下與縮放模型幾何複雜度相關的細節級別(LOD)系統(與討論MIP對映時使用的LOD相對照)。假定如今絕大多數PC遊戲支援的處理器速度的巨大範圍,以及你可能渲染的任何給定可視場景的動態性質(在螢幕上有一個角色還是12個?), 你通常需要一些系統來處理這樣的情況,比如,當系統接近極限試圖同時在螢幕上繪製出12個角色,每個角色有3,000個多邊形,並維持現實的幀速率。 LOD 被設計來協助這樣的情景中。最基本的情況,它是在任何給定時間動態地改變你在螢幕上繪製的角色的多邊形數量的能力。面對現實吧,當一個角色走遠,也許只有十個螢幕畫素高度,你真的不需要3000個多邊形來渲染這個角色 -- 或許300個就夠了,而且你很難分辨出差別。 

  一些 LOD 系統將會需要你建立模型的多個版本,而且他們將會依靠模型離觀察者的接近程度來改變螢幕上的LOD級別, 以及多少個多邊形正被同時顯示。更加複雜的系統實際上將會動態地減少螢幕上的多邊形數量,在任何給定時間,任何給定的角色,動態地 -- Messiah和Sacrifice包括了這種風格的技術,儘管在CPU方面並不便宜。你必須確信,與首先簡單地渲染整個事物相比,你的 LOD 系統沒有花較多的時間計算出要渲染那些多邊形(或不渲染)。 任一方式都將會工作,由於如今我們試圖要在螢幕上繪製的多邊形數量,這是件非常必要的事情。注意, DX9 將會支援硬體執行的自適應幾何縮放(tessellation)。

  歸結起來是,得到一個運動流暢,其表現和移動在視覺上可信,螢幕上看起來逼真的模型。流暢的動畫時常是通過手工建造動畫和運動捕捉動畫的組合得到。有時你僅僅手工建立了一個給定的動畫 -- 當你在為一個模型做一些你在現實生活中不能做到的事情的動畫時, 你傾向於這樣做 -- 舉例來說,你確實不能向後彎腰,或像Mortal Kombat 4中的Lui Kang那樣在行進的腳踏車上踢腿,通常運動捕捉這時候就出局了! 通常運動捕捉動畫 -- 實際上視訊捕捉活生生的演員貫穿於你想在螢幕上所看到的動畫 -- 是得到逼真的東西的方式。真實感的東西能使一款普通遊戲看起來很棒,而且能掩飾許多事情。比如 NFL Blitz,螢幕上的模型大約有 200 個多邊形。它們在靜止站立時看起來可怕的斑駁,一旦這些模型跑動起來它們就有快速流暢的動畫,模型自身的許多醜陋消失了。眼睛容易看見的是 '逼真的' 動畫而不是模型自身的結構。 一個不錯的模型設計師能夠掩飾大多數模型缺陷。

  我希望這些帶給你對模型和動畫問題的洞察力。在第五部份中,我們將會更加深入3D世界的建造,討論一些物理,運動和效果系統的東西。

第5部分: 物理,運動,效果


世界建造
  常常在建立一個含有任何3D成分的遊戲時,你最終要試圖建立一個將會在裡面產生遊戲動作的3D環境。 不知怎麼的遊戲開發者提供了一個建立這種環境的方,它容易修改,有效率,有較低的多邊形數量,對於遊戲既容易渲染又容易運用物理學。很簡單,對嗎?當做這個的時候我用左手在做什麼?當做這的時候 , 我對我的左手做什麼? 是的。不錯。 

  雖然那裡有許多3D結構程式,從CAD/CAM程式到3D Studio Max,建造遊戲世界是不同於建造內部或外部世界的模型的尷尬。你有三角形數量問題 -- 任何給定的渲染器一次只能渲染這麼多的多邊形,這對於天才的關卡設計師來說永遠都不夠。不知這些,你也只能每個關卡儲存預定數量的多邊形,所以即使你的渲染器能夠在視野中處理250,000個多邊形,即使你只能在合理數量的空間中儲存500,000個多邊形,那麼取決於你怎