Microsoft發(fā)布的DirectX 10代表了自從可編程Shader出現(xiàn)以來在3D API方面的最巨大的進(jìn)步。通過一番脫胎換骨般的重建,DirectX 10展現(xiàn)出一系列非常醒目的新特性,包括高度優(yōu)化的運(yùn)行時(shí),強(qiáng)大的Geometry Shader,紋理數(shù)組等等,這些特性將引領(lǐng)PC實(shí)時(shí)三維圖形進(jìn)入一個(gè)全新的世界。
DirectX 發(fā)展簡(jiǎn)史
在過去的十年中,DirectX已經(jīng)穩(wěn)步成為了Microsoft Windows平臺(tái)上進(jìn)行游戲開發(fā)的首選API。每一代的DirectX都帶來對(duì)新的圖形硬件特性的支持,因此每次都能幫助游戲開發(fā)者們邁出驚人的一步。
微軟DirectX API(Application Programming interface :應(yīng)用程序界面) 最早發(fā)布于1995年,其設(shè)計(jì)目標(biāo)是為Windows平臺(tái)軟件開發(fā)人員提供一個(gè)更簡(jiǎn)便的針對(duì)多媒體和游戲應(yīng)用編程的標(biāo)準(zhǔn)接口。
在DirectX出臺(tái),開發(fā)者針對(duì)音頻、視頻等的操作必須基于硬件進(jìn)行,——當(dāng)然,基于OpenGL能夠在很大程序上減輕工作量,但OpenGL獲得的支持顯然遠(yuǎn)遠(yuǎn)不夠。——而顯卡、聲卡等的產(chǎn)品種類眾多,要編寫一款能運(yùn)行在所有平臺(tái)上的游戲簡(jiǎn)直是一件噩夢(mèng)般的工作。
通過提供一系列的針對(duì)多媒體應(yīng)用的API,如圖形(包括2D與3D應(yīng)用)、音頻或輸入設(shè)備等,DirectX提供了一整套的多媒體接口方案,這可以讓開發(fā)者根據(jù)API編寫相應(yīng)的軟件程序,而不必考慮具體的硬件,硬件的差別性顯得無足輕重,編程人員得以更有效率的開發(fā)各種多媒體、游戲軟件。
當(dāng)然,DirectX的發(fā)展并不是一帆風(fēng)順的,最初的版本遠(yuǎn)談不上穩(wěn)定。
版本 |
操作系統(tǒng) |
發(fā)布日期 |
DirectX 1.0 |
Windows 95a |
9/30/95 |
DirectX 2.0/2.0a |
Windows 95OSR2/NT4.0 |
6/5/96 |
DirectX 3.0/3.0a |
Windows NT 4.0 SP3 |
9/15/96 |
DirectX 4.0 |
|
未發(fā)布 |
DirectX 5.0 |
Windows NT 4.0/Beta for NT 5.0 |
7/16/97 |
DirectX 5.1 |
Windows 95/98/NT4.0 |
12/1/97 |
DirectX 5.2 |
Windows 95 |
5/5/98 |
DirectX 6.0 |
Windows 98/NT4.0 |
8/7/98 |
DirectX 6.1 |
Windows 95/98/98SE |
2/3/99 |
DirectX 7.0 |
Windows 95/98/98SE/2000 |
9/22/99 |
DirectX 7.0a |
Windows 95/98/98SE/2000 |
9/99 |
DirectX 7.1 |
Windows 95/98/98SE/ME/2000 |
9/16/99 |
DirectX 8.0/8.0a |
Windows 95/98/98SE/ME/2000 |
9/30/2000 |
DirectX 8.1 |
Windows 95/98/98SE/ME/2000/XP |
11/12/01 |
DirectX 9 Shader Model 2.0 |
Windows 95/98/98SE/ME/2000/XP |
12/19/2002 |
DirectX 9 Shader Model 2.0b |
Windows 98/98SE/ME/2000/XP |
8/13/2003 |
DirectX 9 Shader Model 3.0 |
Windows 98/98SE/ME/2000/XP |
8/9/2004 |
DirectX 3D的發(fā)展
DirectX中應(yīng)用在3D圖形方面的特定DirectX API即Direct3D,這也是DirectX中最重要的部分。不過,DirectX 3D得到廣泛應(yīng)用是在DirectX 6.0之后:
DirectX 6.0:加入了雙線性過濾、三線性過濾等優(yōu)化3D圖像質(zhì)量的技術(shù),加入環(huán)境影射凹凸貼圖,使3D游戲的畫面更具有真實(shí)感。
DirectX 7.0:最大的特色就是支持了T&L,中文名稱是“坐標(biāo)轉(zhuǎn)換和光源”,3D游戲中坐標(biāo)和燈光的轉(zhuǎn)換工作從此由CPU轉(zhuǎn)交給了GPU,比DX6.1性能提升20%。這也成就了nVIDIA GeForce 256與ATi Radeon 256的輝煌,令3DFX徹底退出市場(chǎng)競(jìng)爭(zhēng)。
DirectX 7.0a:增強(qiáng)了力反饋游戲控制設(shè)備的性能和兼容性。
DirectX 7.1:與Windows Millennium一同發(fā)布。
DirectX 8.0/8.0a:支持Shader Model 1.0和1.1,從此在顯卡中引入可編程像素著色器(Pixel Shaders)和頂點(diǎn)著色器(Vertex Shaders)的概念,同時(shí)應(yīng)用在Xbox游戲機(jī)中。同硬件T&L僅僅實(shí)現(xiàn)的固定光影轉(zhuǎn)換相比,VS和PS單元的靈活性更大,它使GPU真正成為了可編程的處理器。
DirectX 8.1: Pixel Shader升級(jí)到1.2、1.3、1.4版,可以支持最高每時(shí)鐘28指令執(zhí)行,其中1.4版當(dāng)時(shí)僅ATi Radeon 8500顯卡支持。
DirectX 9.0 Shader Model 2.0: SM2.0的shader性能更強(qiáng),支持最高96指令的pixel shader長(zhǎng)度,同時(shí)DirectPlay和一些音頻方面也有大幅提升。
DirectX 9.0 Pixel Shader 2.0b: ATI Radeon X600/700/800系列顯卡首先采納,開始支持更多指令(最高1536)和更多臨時(shí)寄存器(32相比之前為12),同時(shí)還加入新的貼面寄存器(facing register)和幾何實(shí)例(geometry instancing)的支持。
DirectX 9.0 Shader Model 3.0:支持更多指令,支持指令的流量控制和動(dòng)態(tài)分支,從而使得編程人員可以在shaders中加入循環(huán)操作,使得編程更加容易,首次被Geforce 6800顯卡采用。
從DirectX的發(fā)展史中我們可以看到,微軟的3D API和硬件一同發(fā)展,新硬件帶來新的DX特性,新的DX特性加速硬件的發(fā)展,在DirectX10上面,又是一個(gè)3D圖形發(fā)展的新境界。
DirectX 10的架構(gòu)優(yōu)勢(shì)
DirectX之所以在廣大的開發(fā)者中流行,是得益于它的簡(jiǎn)單易用和豐富的功能特性。然而,DirectX一直被一個(gè)主要的問題所困擾,那就是高CPU負(fù)載。
在圖形編程API出現(xiàn)之前,3D應(yīng)用程序直接向圖形硬件發(fā)送命令來完成圖形的繪制工作。雖然這樣開發(fā)工作比較繁重,但硬件效率則能在很大程度上得到保證。
而如DirectX和OpenGL這樣的圖形API則是通過在圖形硬件和應(yīng)用程序之間架起了一個(gè)中間層,這樣,應(yīng)用程序可以使用統(tǒng)一的圖形編程代碼來完成對(duì)底層硬件的操作,將程序員們從與大量的圖形硬件交互的惡夢(mèng)中解救出來。但是,這也造成了每次DirectX從應(yīng)用程序那里接收到一條命令時(shí),就必須先對(duì)這條命令進(jìn)行分析和處理,再向圖形硬件發(fā)送相對(duì)應(yīng)的硬件命令。由于這個(gè)分析和處理的過程由CPU完成,造成了每一條3D繪圖命令都會(huì)帶來CPU的負(fù)載。
從技術(shù)角度,這種CPU負(fù)載給3D圖象帶來兩個(gè)負(fù)面影響:首先,限制了畫面中可以同時(shí)繪制的物體數(shù)量;其次,限制了可以在一個(gè)場(chǎng)景中使用的獨(dú)立的特效的數(shù)量。這就使得游戲畫面中的細(xì)節(jié)數(shù)量受到了很大的限制,而圖像具有真實(shí)感的主要要求便是豐富的細(xì)節(jié)。
DirectX 10的主要優(yōu)勢(shì)便是最大程度地降低了CPU負(fù)載,主要通過三個(gè)途徑來達(dá)到這個(gè)目的:第一,修改API核心,使得繪制物體和切換材質(zhì)特效時(shí)的消耗降低,提高繪圖效率;第二,引入新的機(jī)制,降低圖形運(yùn)算操作對(duì)CPU的依賴性,使更多的運(yùn)算在GPU中完成;第三,使大量的物體可以通過調(diào)用單條DirectX繪制命令進(jìn)行批量繪制。
下面我們就來仔細(xì)的看一下這三種方式:
提高繪圖效率
在DirectX 10中,對(duì)上代DirectX版本中三維數(shù)據(jù)和繪制命令的驗(yàn)證過程進(jìn)行了很大程度的修改。所謂三維數(shù)據(jù)和命令的驗(yàn)證,是指在DirectX繪制圖形之前,對(duì)傳給它的圖形數(shù)據(jù)和繪制命令進(jìn)行格式和數(shù)據(jù)完整性的檢查,以保證它們被送到圖形硬件時(shí)不會(huì)導(dǎo)致硬件出問題;這是很必要的一步操作,但是不幸的是這會(huì)帶來很大的性能開銷。

從上表我們可以很容易的看出,在DirectX 9中,每次繪制一幀畫面之前,都會(huì)對(duì)即將使用的相關(guān)數(shù)據(jù)進(jìn)行一次驗(yàn)證。而DirectX 10中,僅當(dāng)這些數(shù)據(jù)被創(chuàng)建后驗(yàn)證一次。這很明顯是可以大大提高游戲進(jìn)行中的效率的。
降低圖形運(yùn)算對(duì)CPU的依賴
在降低圖形運(yùn)算對(duì)CPU的依賴方面,DirectX 10 引入的三個(gè)重要機(jī)制就是:紋理陣列(texture arrays)、繪制預(yù)測(cè) (predicated draw)和流式輸出(stream out)。不要被這三個(gè)晦澀的名詞嚇倒,實(shí)際上它們是三個(gè)不難理解的機(jī)制。
紋理陣列
傳統(tǒng)的DirectX在多張紋理中進(jìn)行切換的操作是種很給CPU帶來很大壓力的操作,因?yàn)槊壳袚Q一次,都要調(diào)用一次DirectX的API函數(shù)。而每繪制一個(gè)使用新紋理的物體,就要進(jìn)行一次這樣的切換操作;有時(shí)為了實(shí)現(xiàn)特殊的材質(zhì)特效,繪制一個(gè)物體時(shí)可能就要切換好幾次紋理,開銷很大。
所以,之前游戲中經(jīng)常會(huì)出現(xiàn)將大量的小紋理拼合到一張大的紋理中,通過給不同的三維物體分配這張大紋理的不同局部的方式,以期減少紋理切換,提高游戲運(yùn)行效率。這種方式實(shí)現(xiàn)起來相當(dāng)復(fù)雜,而且DirectX 9中對(duì)紋理的尺寸的限制是4048×4048像素,也就是說,如果要容下更多的小紋理塊,可能就得加載很多張這樣的大紋理。
DirectX 10引入的新的紋理陣列機(jī)構(gòu),將允許在一個(gè)由顯卡維護(hù)的陣列中容納512張單獨(dú)的紋理,而且,在shader程序中可以使用一條新的指令來獲取這個(gè)陣列中的任意一張紋理。而這種shader指令是運(yùn)行在GPU中的;這樣,就把原來要消耗很多CPU時(shí)間的紋理切換工作輕松地轉(zhuǎn)給了GPU。由于紋理一般是直接放在顯存中的,因此以這樣的方式,將工作交與和顯存一同位于顯卡上的GPU來完成更有效率。如今,在DirectX 10中,只要一開始設(shè)置好紋理陣列中的紋理,然后每次繪制一個(gè)物體時(shí)為它指定一個(gè)紋理的索引號(hào),并同物體三維數(shù)據(jù)一起傳遞到shader中,就可以放心的讓GPU來給物體選紋理了。
繪制預(yù)測(cè)
在一般的三維場(chǎng)景里,很多物體都是完全被別的物體擋在后面的。這時(shí)候如果要顯卡繪制這些物體就是白費(fèi)力氣。盡管高級(jí)的GPU可以通過硬件算法將場(chǎng)景畫面中被擋住的像素(注意是像素)預(yù)先剔除,但是仍然會(huì)有很多不應(yīng)進(jìn)行的多余運(yùn)算。例如,一個(gè)完全被擋住的復(fù)雜的角色模型,它的身上可能有幾千個(gè)頂點(diǎn),需要做復(fù)雜的骨骼皮膚動(dòng)畫處理、頂點(diǎn)光照運(yùn)算等等,然而,GPU是在處理完這些頂點(diǎn)之后,并要把這個(gè)角色模型一個(gè)像素一個(gè)像素地畫到畫面中時(shí),才開始判斷每個(gè)像素是否需要畫,而當(dāng)所有的像素都被剔除了時(shí),之前做的頂點(diǎn)處理也就全白費(fèi)了。在DirectX 10中的繪制預(yù)測(cè)便正是針對(duì)這種情況的解決,簡(jiǎn)言之,繪制預(yù)測(cè)通過用一個(gè)可以代表某個(gè)復(fù)雜物體的簡(jiǎn)單物體來判斷這個(gè)物體是否被全部擋住了,例如用一個(gè)可以罩住剛才那個(gè)角色的大盒子,當(dāng)繪制這個(gè)盒子時(shí),如果發(fā)現(xiàn)所有的像素都被屏蔽掉了,也即是說這個(gè)盒子肯定完全看不見,那么,里面的角色繪制包括骨骼皮膚運(yùn)算等之類的操作便完成不必進(jìn)行。而一個(gè)盒子頂多有八個(gè)頂點(diǎn),相比處理幾千個(gè)頂點(diǎn),開銷小得多。
另外,以前這個(gè)步驟中有些真運(yùn)算也需CPU完成的,在DirectX 10中,已經(jīng)完全交由GPU來做,這也可以在一定程度上減輕CPU的壓力。
數(shù)據(jù)流式輸出
數(shù)據(jù)流式輸出也是DirectX 10的重要特性,它允許GPU上的Vertex shader或Geometry shader向顯存中添加數(shù)據(jù),而這在以往的vertex shader中是不可能的。
在之前的DirectX版本中,vertex shader只能讀取顯存中已有的頂點(diǎn)數(shù)據(jù);而DirectX 10中引入的新的Geometry shader,不但能讀取顯存中的頂點(diǎn)數(shù)據(jù)、幾何(點(diǎn)、線段、三角形)數(shù)據(jù),還可以生成新的幾何數(shù)據(jù)放回顯存。
批量繪制
在DirectX 9中,對(duì)渲染狀態(tài)的管理一直是個(gè)十分信賴于CPU運(yùn)算能力的操作。所謂渲染狀態(tài),是指顯卡進(jìn)行一次繪制操作時(shí)所需要設(shè)置的各種數(shù)據(jù)和參數(shù)。例如,要繪制一個(gè)人物角色,就需要先設(shè)置他的幾何模型數(shù)據(jù)的數(shù)據(jù)格式、紋理過濾模式、半透明混合模式等等,每設(shè)置一項(xiàng),都要調(diào)用一次DirectX API,占用大量CPU時(shí)間,極大的約束了渲染的性能。
為了使這些操作能夠批量的進(jìn)行,DirectX 10中引入了兩個(gè)新的結(jié)構(gòu)——狀態(tài)對(duì)象(state object)和常量緩沖(constant buffers)。
狀態(tài)對(duì)象就是將以前的零散狀態(tài)按照功能歸結(jié)為幾個(gè)整體,這樣,當(dāng)要設(shè)置一系列相關(guān)狀態(tài)時(shí),無需為每一個(gè)狀態(tài)來調(diào)用一次DirectX API,只需要調(diào)用一次將這些狀態(tài)統(tǒng)統(tǒng)設(shè)置到顯卡中去。
而常量緩沖是另一個(gè)十分有意義的機(jī)制。在繪制模型前的準(zhǔn)備工作中,渲染狀態(tài)的設(shè)置只是一小部分。還是拿繪制人物角色來說,能照亮這個(gè)人的光源的顏色、位置、類型、范圍等等,都要提前設(shè)給顯卡;為了通過骨骼來帶動(dòng)他的皮膚做出姿勢(shì),還要設(shè)置骨骼的位置信息等等,而這些東西主要都是通過GPU中的常量寄存器(constant registers)來傳遞給它的。每個(gè)常量寄存器可以存儲(chǔ)一個(gè)4維的浮點(diǎn)型向量(即四個(gè)浮點(diǎn)數(shù))。常量寄存器是游戲程序向GPU輸入游戲場(chǎng)景中數(shù)據(jù)的重要途徑。
在DirectX 9中,這種常量寄存器的數(shù)量是十分有限的,而且每次更新一個(gè)寄存器,都需要調(diào)用一次DirectX API函數(shù)。DirectX 10通過使用常量緩沖(constant buffer)這種結(jié)構(gòu),在每個(gè)constant buffer中都可以容納4096個(gè)常量,而且只需調(diào)用一次API就可以更新一大批常量。
比如說,在以前的DirectX版本中,如果程序想在場(chǎng)景里畫很多的樹木和雜草,可以采用一個(gè)類似于“克隆”的方法:先做好一棵或幾棵樹、草的三維模型,然后在畫一幀畫面時(shí),不停的在不同的位置、方向,用不同的大小為參數(shù),調(diào)用DirectX API的繪制函數(shù)來畫這些模型,就可以畫出很多草木來。但是每畫一棵,都要設(shè)置一大堆參數(shù)后調(diào)用一次API,這是很耗CPU時(shí)間的,所以在以前的游戲中鮮有大規(guī)模且細(xì)節(jié)豐富的森林場(chǎng)景。
而在DirectX 10中,我們可以先把樹、草的幾個(gè)模型設(shè)給顯卡,然后將所有要畫的樹木的位置、方向和大小一次性的寫入到constant buffer中,這樣,顯卡便一下把所有的樹木和草都一起繪制出來了。
總之,DirectX 10通過提前數(shù)據(jù)驗(yàn)證、紋理陣列、繪制預(yù)測(cè)、流式輸出、狀態(tài)對(duì)象、常量緩沖等機(jī)制,幫助游戲的效果和效率上升到一個(gè)新的高度。這樣,也避免了之前DirectX版本因CPU負(fù)載過大而無法對(duì)圖形實(shí)施更多細(xì)節(jié)優(yōu)化的問題。
Shader Model 4.0
DirectX 10另一個(gè)引人矚目的特性便是引入了Shader Model 4.0,那么,Shader Model 4.0能夠帶來怎樣的新特性,特別是將它與DirectX 9.0c中Shader Model 3.0相比時(shí)?
引入新Shader : Geometry shader
DirectX 10新引入的Geometry Shader,可以簡(jiǎn)單地編程操縱幾何圖元,同時(shí), vertex、geometry、pixel shader采用了統(tǒng)一的Sahder架構(gòu)。
Geometry shaders是可編程圖形流水線的一大進(jìn)步。它第一次允許由GPU來動(dòng)態(tài)的生成和銷毀幾何圖元數(shù)據(jù)。通過和新的數(shù)據(jù)流輸出功能配合使用,許多以前無法實(shí)施的算法現(xiàn)在都可以在GPU中使用了。
統(tǒng)一的Shader架構(gòu)
在DirectX 9中,Pixel shader總是在各個(gè)方面落后于vertex shaders,包括常量寄存器個(gè)數(shù)、可用的指令個(gè)數(shù)、shader長(zhǎng)度等。程序員需要區(qū)分對(duì)待這兩種shader。
而在shader model 4中,無論 vertex、geometry和pixel shader,均有統(tǒng)一的指令集、同樣的臨時(shí)/常量寄存器個(gè)數(shù),它們將平等的共享GPU中的所有可用資源。這樣,在編程時(shí)便不必再考慮每種shader自身的限制了。
百倍于DirectX 9的可用資源
對(duì)于shader中可用的資源,在Shader model 4.0中比原來有了驚人的擴(kuò)充。就像早期的程序員們絞盡腦汁的省著用可憐的640k內(nèi)存一樣,在使用以前的DirectX開發(fā)游戲的過程中,程序員需要小心翼翼的分配珍貴的shader寄存器資源。寄存器的數(shù)量,直接影響著shader程序的復(fù)雜度。這和在640k內(nèi)存的 機(jī)器上,怎么也不可能寫出Microsoft Office這樣的大規(guī)模軟件是同一個(gè)道理。
而在DirectX 10中,將臨時(shí)寄存器由原來的32個(gè)擴(kuò)充到了4096個(gè),將常量寄存器由原來的256個(gè)擴(kuò)充到了65536個(gè)。
更多的渲染目標(biāo)(Render Target)
所謂渲染目標(biāo),就是指GPU可以把畫面繪制到的目標(biāo),我們可以把它理解為GPU的畫布。一般來說,渲染目標(biāo)被輸出到屏幕上,這樣我們就能看到畫好的畫面了。但是有時(shí)為了實(shí)現(xiàn)一些特效,某些渲染結(jié)果并不直接畫到屏幕上,而是再返給GPU做進(jìn)一步的特效處理,而且渲染目標(biāo)中也不一定是畫好的畫面的顏色信息。
根據(jù)圖形特效的需要,渲染目標(biāo)可能是每個(gè)物體距離屏幕的遠(yuǎn)近,或者物體表面上每個(gè)像素的方向,或者每個(gè)物體表面的溫度等等,之為了實(shí)現(xiàn)特效,可以按需要在其中繪制任何信息。為了提高這種情況下的效率,很多新的顯卡都支持在同一遍Shader執(zhí)行結(jié)束后,同時(shí)把不同的信息繪制到不同的渲染目標(biāo)中。在DirectX 9中就已經(jīng)支持這種機(jī)制了,但是它約束最多同時(shí)向四個(gè)渲染目標(biāo)繪制。而DirectX 10將這個(gè)數(shù)量提升了一倍。
更多的紋理
在Shader Model 4.0中提供了對(duì)紋理陣列(Texture arrays)的支持。在前文中已經(jīng)對(duì)紋理陣列有了比較詳細(xì)的介紹,在這里只著重介紹一下與shader相關(guān)的部分。
在每個(gè)紋理陣列中,最多可以保存 512張同樣大小的紋理。而且每張貼圖的分辨率被擴(kuò)展到了8192×8192。更大的分辨率意味著紋理中更豐富的細(xì)節(jié)。在一個(gè)shader中能夠同時(shí)訪問的紋理個(gè)數(shù)被增加到了128個(gè),也就是說在每次執(zhí)行同一個(gè)shader時(shí),可以使用一個(gè)紋理陣列的512個(gè)紋理中的128個(gè)。所以說,在DirectX 10中,紋理的多樣性和細(xì)節(jié)程度將會(huì)有大幅的提升。
新的HDR顏色格式
要說這些年來在實(shí)時(shí)圖形界炒得最熱的概念,應(yīng)該是HDR了。它通過采用浮點(diǎn)格式的顏色格式來為紋理、光照等計(jì)算提供極大的精度和顏色范圍(以前的紋理一般 都是采用整數(shù)型的顏色格式)。盡管最后顯示到屏幕上還是每個(gè)顏色通道8位的整數(shù)格式,但是以前由于在材質(zhì)、光照計(jì)算中紋理也是用每通道8位的格式來參與計(jì)算,所以在顯示到畫面之前,很多細(xì)節(jié)就在低精度的運(yùn)算中丟失了。
而采用每顏色通道16位浮點(diǎn)數(shù)的紋理,能夠保證在運(yùn)算過程中幾乎沒有顏色細(xì)節(jié)信息的丟失。另外,采用16位浮點(diǎn)格式的顏色通道,可以表現(xiàn)更大的顏色范圍。這些就是HDR的優(yōu)越性。
對(duì)用戶而言,當(dāng)游戲中的畫面罩上一層HDR效果后,立刻顯得和真正的照片一樣,有朦朧的光暈、細(xì)致的高光和十分自然的色調(diào)。
然而,采用每個(gè)顏色通道16位浮點(diǎn)數(shù)的格式,比采用每通道8位的整數(shù)格式的紋理要多占據(jù)一倍的顯存;這給繪制的效率帶來了負(fù)面的影響。所以在 DirectX 10中引入了兩個(gè)新的HDR格式。第一種是R11G11B10,表示紅色和綠色通道用11位浮點(diǎn)數(shù),而藍(lán)色通道采用10位浮點(diǎn)數(shù)表示。那么,為什么不都用 11位呢?這是為了湊32這個(gè)整數(shù)。學(xué)過計(jì)算機(jī)的人都知道,當(dāng)內(nèi)存中一個(gè)數(shù)據(jù)單元的寬度是32位時(shí),對(duì)它的操作效率最高;而且在紋理數(shù)據(jù)中一般要求每個(gè)像素的數(shù)據(jù)寬度是2的倍數(shù),如2,8,16,32,64等等。又因?yàn)槿搜蹖?duì)藍(lán)色的敏感度不如對(duì)紅色和綠色,所以它比其他兩個(gè)通道少用了一位。
另外一種格式是采用每通道9位尾數(shù)、所有通道共享5位指數(shù)的形式(眾所周知,在計(jì)算機(jī)中,浮點(diǎn)數(shù)是采用尾數(shù)附加指數(shù)的形式來表示的),加起來還是32位。 這些新的格式使得紋理能夠與原來占用同樣多的顯存空間,避免了大的空間和帶寬消耗。同時(shí),為了適合需要精確的科學(xué)計(jì)算的場(chǎng)合,DirectX 10能夠支持每通道32位(4個(gè)通道加起來128位)精度的浮點(diǎn)數(shù)紋理。
DirectX 10中帶來的這些擴(kuò)充和提高,使得創(chuàng)建前所未有的細(xì)節(jié)的實(shí)時(shí)游戲場(chǎng)景真正成為可能。
幾何著色器與流式輸出
在DirectX 10發(fā)布之前,圖形硬件只有在GPU上操作已有數(shù)據(jù)的能力。頂點(diǎn)著色器(Vertex Shader)和像素著色器(Pixel Shader)都允許程序操作內(nèi)存中已有的數(shù)據(jù)。這種開發(fā)模型非常成功,因?yàn)樗趶?fù)雜網(wǎng)格蒙皮和對(duì)已有像素進(jìn)行精確計(jì)算方面都表現(xiàn)的很出色。但是,這種開發(fā)模型不允許在圖像處理器上生成新數(shù)據(jù)。當(dāng)一些物體在游戲中被動(dòng)態(tài)的創(chuàng)建時(shí)(比如新型武器的外形),就需要調(diào)用CPU。可惜現(xiàn)在大多數(shù)游戲已經(jīng)很給CPU帶來了很大的壓力,游戲進(jìn)行時(shí)動(dòng)態(tài)創(chuàng)建龐大數(shù)量新數(shù)據(jù)的機(jī)會(huì)就變得微乎其微了。
Shader Model 4.0中引入的幾何著色器(Geometry Shader),第一次允許程序在圖像處理器中創(chuàng)建新數(shù)據(jù)。這一革命性的事件使得GPU在系統(tǒng)中的角色由只可處理已有數(shù)據(jù)的處理器變成了可以以極快速度既可處理又可生成數(shù)據(jù)的處理器。在以前圖形系統(tǒng)上無法實(shí)現(xiàn)的復(fù)雜算法現(xiàn)如今變成了現(xiàn)實(shí)。
幾何著色器被放在頂點(diǎn)著色器和光柵化階段(Rasterizer)中間。所謂光柵化,就是一行一行的掃描每個(gè)三角形,把它們一個(gè)像素一個(gè)像素的繪制到畫面 上。幾何著色器把經(jīng)過頂點(diǎn)著色器處理過的頂點(diǎn)當(dāng)作輸入,對(duì)于每個(gè)頂點(diǎn),幾何著色器可以生成1024個(gè)頂點(diǎn)作為輸出。這種生成大量數(shù)據(jù)的能力叫做數(shù)據(jù)擴(kuò)大 (Data Amplification)。同樣的,幾何著色器也可以通過輸出更少的頂點(diǎn)來刪除頂點(diǎn),因此,就叫做數(shù)據(jù)縮小(Data Minimization)。這兩個(gè)新特性使GPU在改變數(shù)據(jù)流方面變得異常強(qiáng)大。
細(xì)分的虛擬位移貼圖(Displacement Mapping with Tessellation)
幾何著色器讓虛擬位移貼圖可以在GPU上生成。虛擬位移貼圖是在離線渲染系統(tǒng)中非常流行的一項(xiàng)技術(shù),它可以用一個(gè)簡(jiǎn)單的模型和高度圖(Height Map)渲染出非常復(fù)雜的模型。高度圖是一張用來表示模型上各點(diǎn)高度的灰度圖。渲染時(shí),低多邊形的模型會(huì)被細(xì)分成多邊形更多的模型,再根據(jù)高度圖上的信息,把多邊形擠出,來表現(xiàn)細(xì)節(jié)更豐富的模型。
而在DirectX 9中,GPU無法生成新的數(shù)據(jù),低多邊形的模型無法被細(xì)分,所以只有小部分功能的虛擬位移貼圖可以實(shí)現(xiàn)出來。現(xiàn)在,使用DirectX 10的強(qiáng)大力量,數(shù)以千計(jì)的頂點(diǎn)可以憑空創(chuàng)造出來,也就實(shí)現(xiàn)了實(shí)時(shí)渲染中真正的細(xì)分的虛擬位移貼圖。
基于邊緣(Adjacency)的新算法
幾何著色器可以處理三種圖元:頂點(diǎn)、線和三角形。同樣的,它也可以輸出這三種圖元中的任何一種,雖然每個(gè)著色器只能輸出一種。在處理線和三角形時(shí),幾何著 色器有取得邊緣信息的能力。使用線和三角形邊緣上的頂點(diǎn),可以實(shí)現(xiàn)很多強(qiáng)大的算法。比如,邊緣信息可以用來計(jì)算卡通渲染和真實(shí)毛發(fā)渲染的模型輪廓。
流式輸出(Stream Output)
在DirectX 10之前,幾何體必須在寫入內(nèi)存之前被光柵化并送入像素著色器(pixel shader)。DirectX 10引入了一個(gè)叫做數(shù)據(jù)流式輸出(Stream Output)的新特性,它允許數(shù)據(jù)從頂點(diǎn)著色器或幾何著色器中直接被傳入幀緩沖內(nèi)存(Frame Buffer Memory)。這種輸出可以被傳回渲染流水線重新處理。當(dāng)幾何著色器與數(shù)據(jù)流輸出結(jié)合使用時(shí),GPU不僅可以處理新的圖形算法,還可以提高一般運(yùn)算和物理運(yùn)算的效率。
在生成、刪除數(shù)據(jù)和數(shù)據(jù)流輸出這些技術(shù)的支持下,一個(gè)完整的粒子系統(tǒng)就可以獨(dú)立地在GPU上運(yùn)行了。粒子在幾何著色器中生成,在數(shù)據(jù)擴(kuò)大的過程中被擴(kuò)大與派生。新的粒子被數(shù)據(jù)流輸出到內(nèi)存,再被傳回到頂點(diǎn)著色器制作動(dòng)畫。過了一段時(shí)間,它們開始逐漸消失,最后在幾何著色器中被銷毀。
高級(jí)渲染語言(HLSL 10)
DirectX 10 為以前的DirectX 9中的“高級(jí)著色語言”(High Level Shading Language )帶來了諸多功能強(qiáng)大的新元素。其中包括可以提升常量更新速度的“常量緩沖器”(Constant Buffers),提升渲染流程中操作數(shù)據(jù)的靈活性的“視圖”(view),為更廣泛的算法所準(zhǔn)備的“整數(shù)與位指令”(Integer and Bitwise Instructions),添加了switch語句。
常量寄存器(Constant Buffers)
著色程序同普通的程序一樣需要使用常量來定義各種參數(shù),例如光源的位置和顏色,攝像機(jī)的位置和投影矩陣以及一些材質(zhì)的參數(shù)(例如反光度)。在整個(gè)渲染的過程中,這些常量往往需要頻繁的更新,而數(shù)以百計(jì)的常量的使用以及更新無疑會(huì)給CPU帶來極大的負(fù)載。DirectX 10中新加入的常量緩沖器可以根據(jù)他們的使用頻率將這些常量分配到指定的緩沖器中并協(xié)調(diào)的對(duì)其進(jìn)行更新。
在一個(gè)著色程序中DirectX 10支持最多16個(gè)常量緩沖器,每一個(gè)緩沖器可以存放4096個(gè)常量。與其相比DirectX 9實(shí)在是少得可憐,因?yàn)樗诿總€(gè)著色程序中同時(shí)最多只能支持256個(gè)常量。

相比DirectX 9,DirectX 10不僅提供了更多的常量,最主要的是它大幅的提升了常量更新的速度。對(duì)那些被分配到同一個(gè)緩沖器中的常量,我們只需進(jìn)行一次操作就可以將它們?nèi)扛峦戤叄菃蝹€(gè)單個(gè)的去更新。
由于不同的常量更新的時(shí)間間隔各異,所以跟據(jù)使用的頻率來對(duì)他們進(jìn)行組織就可以獲得更高的效率。舉例來說:攝像機(jī)的視矩陣只在每一幀之間發(fā)生改變,而類似貼圖信息這樣的材質(zhì)參數(shù)卻會(huì)在圖元切換時(shí)發(fā)生改變。于是這些常量緩沖器被分成了兩個(gè)部分:那些每幀更新的常量緩沖器專門存放那些需要在兩幀間更新的常數(shù)并在兩幀間一次把他們?nèi)扛拢硗獾膱D元切換更新的常量緩沖器也同理。這樣就會(huì)將更新常量過程中的一些不必要的工作消除,以便讓整個(gè)著色器腳本比在 DirectX 9中運(yùn)行的更加順暢。
視圖(Views)
在DirectX 9中,著色器(shader)中的數(shù)據(jù)的類型是被嚴(yán)格劃分開的。例如,頂點(diǎn)著色器用到的頂點(diǎn)緩沖器中的數(shù)據(jù)不能當(dāng)作貼圖的數(shù)據(jù)來讓像素著色器使用。這樣就將特定的資源類型同其相對(duì)應(yīng)的渲染流程中的特定步驟緊密地結(jié)合了起來,同時(shí)限制了資源資源在整個(gè)渲染流程中可以使用的范圍。
DirectX 10舍棄了“嚴(yán)格區(qū)分的數(shù)據(jù)類型”這一概念。當(dāng)一段數(shù)據(jù)被創(chuàng)建,那么DirectX 10所做的僅僅是將其簡(jiǎn)單的當(dāng)作內(nèi)存中的一段區(qū)域(bit field)來對(duì)待。如果要想使用這一段沒有定義類型的數(shù)據(jù)就必須通過使用一個(gè)“view”。 使用“view”,相同的一段數(shù)據(jù)就可以有各種各樣的方法來讀取。DirectX 10支持對(duì)同一段資源在同時(shí)使用兩個(gè)“view”。
通過這種多重“view”的手段,就可以在整個(gè)渲染流程的不同部分以不同目的使用同一段數(shù)據(jù)。例如:我們可以通過像素著色器將一段幾何數(shù)據(jù)渲染到一張紋理 上,之后頂點(diǎn)著色器通過一個(gè)“view”將這張紋理視為一個(gè)頂點(diǎn)緩沖器并將其中的數(shù)據(jù)作為幾何數(shù)據(jù)渲染。“view”通過在整個(gè)渲染流程中的不同步驟重復(fù) 使用同一段數(shù)據(jù)為“數(shù)據(jù)處理”帶來了更大的靈活性,幫助開發(fā)者實(shí)現(xiàn)更多更有創(chuàng)意更精彩的特效。
整數(shù)與位運(yùn)算指令(Integer and Bitwise Instructions)
在新的高級(jí)著色器語言中添加了“整數(shù)與位指令”,這樣把“整數(shù)與位運(yùn)算指令”的操作加入其基礎(chǔ)運(yùn)算函數(shù)的好處在于幫助一些算法在GPU上的實(shí)現(xiàn)。開發(fā)者終于可以直接使用整數(shù)而非從浮點(diǎn)中強(qiáng)轉(zhuǎn)來計(jì)算出準(zhǔn)確的答案。數(shù)組的索引號(hào)現(xiàn)在可以輕松的計(jì)算出來。GPU無整數(shù)運(yùn)算的時(shí)代終于被終結(jié)了。這將為shader 程序的開發(fā)帶來很大的便利。
Switch 語句(Switch Statement)
在DirectX 10中, HLSL可以支持switch語句,這將大幅簡(jiǎn)化那些有著大量判斷(分支)的著色器腳本的編碼。一種用法就是建立一個(gè)“航母級(jí)的著色器(shader) 程序”——包含了大量的小型著色器程序并且自身體形巨大的著色器程序。在這個(gè)“航母級(jí)的著色器程序”,我們可以通過設(shè)定一個(gè)材質(zhì)ID在switch語句中 判斷來輕松的在渲染同一個(gè)圖元時(shí)切換不同的特效。也就是說,現(xiàn)在一個(gè)軍隊(duì)中的每個(gè)士兵身上都可以擁有各自不同的特效了。
DirectX 10的其他改進(jìn)
alpha to coverage
在游戲中,經(jīng)常使用帶有半透明信息紋理的多邊形模型來模擬復(fù)雜的物體,例如,草、樹葉、鐵絲網(wǎng)等。如果使用真正的模型,一顆邊緣參差不齊的小草可能就要消耗掉幾百個(gè)多邊形;然而采用透明紋理,可以只用2~3個(gè)多邊形就解決了。

透明紋理示意
然而,當(dāng)使用這種有半透明信息的紋理時(shí)候,它的不透明和透明部分的邊界線上,常常會(huì)出現(xiàn)難看的鋸齒。采用半透明混合技術(shù)可以解決這個(gè)問題,但是它需要把場(chǎng)景中所有這類物體按照由遠(yuǎn)到近的順序來繪制,才能保證它們的遮擋關(guān)系是正確的,這會(huì)給CPU帶來很大的壓力,并不可取。在以前版本的DirectX中,alpha測(cè)試和混合簡(jiǎn)直就是圖形程序員的噩夢(mèng)。
在DirectX 10中,使用了一種新的技術(shù)叫做Alpha to coverage。使用這種技術(shù),在透明和不透明交界處的紋理像素會(huì)被進(jìn)行多極取樣(Multi-sample),達(dá)到抗鋸齒的效果。這就在不引入大的性能開銷的情況下簡(jiǎn)單并有效地解決了這個(gè)問題。室外場(chǎng)景的游戲?qū)⒋蟠笫芤嬗谶@種技術(shù),樹葉、鐵絲網(wǎng)、草的邊緣將會(huì)更加柔和、圓滑。

Alpha to coverage效果
shadow map filtering
陰影圖(Shadow map)技術(shù)已經(jīng)逐漸成為了渲染真實(shí)感陰影的流行技術(shù)。在包括《戰(zhàn)爭(zhēng)機(jī)器》、《分裂細(xì)胞:雙重特工》、《Ghost Recon》、《刺客信條》等的各大次世代游戲中都能看到它的身影。然而,由于shadow map的尺寸限制,用它實(shí)現(xiàn)的陰影邊緣往往有明顯的鋸齒。在DirectX 10中,提供了對(duì)shadow map進(jìn)行過濾的功能的正式支持。經(jīng)過過濾后,陰影的邊緣將會(huì)變得更加柔和。
posted on 2007-05-31 15:11
清源游民 閱讀(1112)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
C++