• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            D3d9的一些更新 (轉(zhuǎn))

            由于Aug 8造成的D3D9恐懼癥已經(jīng)完全消除了,這一章將會(huì)給大家介紹將3D引擎轉(zhuǎn)向D3D9的各個(gè)方面,包括終于出現(xiàn)的全屏幕模式。從這章以后,我將使用D3D9作為講解的語(yǔ)言繼續(xù)D2D教程。

            【OP結(jié)束,開(kāi)始正片】

            『Why?』

              估計(jì)大家首先要問(wèn)的就是“Why?”為什么要前進(jìn)到D3D9?理由如下:
            1、D3D9修復(fù)了D3D8已知的所有Bug,因此運(yùn)行起來(lái)更穩(wěn)定,速度也要快。
            2、D3D9提供了許多便利的新功能,雖然絕大多數(shù)是面向3D的,但是也有不少2D適用的,比如IDirect3DDevice9::StretchRect,以及對(duì)IDirect3DSurface9的改進(jìn)等等。D3DX庫(kù)就更多了,比如D3DXSaveSurfaceToFileInMemory,一開(kāi)始沒(méi)發(fā)現(xiàn)這個(gè)函數(shù)有啥用處,現(xiàn)在基本離不開(kāi)了。
            3、HLSL。就像上一話我說(shuō)的那樣,D2D教程以后會(huì)有PixelShader的內(nèi)容。我可不想拿匯編來(lái)寫(xiě)Shader,會(huì)死人的(祝賀我吧,終于拋棄匯編Shader了……)。雖然說(shuō)這不是決定性的理由,因?yàn)檫€有Cg什么的,不過(guò)我想編寫(xiě)顯卡無(wú)關(guān)的代碼,因此我不去研究Cg(反正和HLSL差不多)以及R2VB之類(lèi)。
            4、ID3DXFont,往下看你就知道了。

            《D3D的變化》

            『界面名稱(chēng)變化』

              一句話:8改成9就行。

            『“創(chuàng)建”型方法的一個(gè)統(tǒng)一變化』

              許多Create*()方法,比如創(chuàng)建設(shè)備、創(chuàng)建紋理、創(chuàng)建頂點(diǎn)緩沖等等,多了一個(gè)HANDLE* pSharedHandle參數(shù),無(wú)用,NULL之(看來(lái)微軟原打算弄個(gè)共享句柄之類(lèi),不過(guò)被D3D10巨大的變化浮云了)

            『創(chuàng)建D3D設(shè)備的變化』

              D3DPRESENT_PARAMS的FullScreen_PresentationInterval變成了PresentationInterval,也就是說(shuō)即使在窗口模式下也可以做到垂直同步來(lái)防止撕裂現(xiàn)象(2D的福音啊)。相應(yīng)的,D3DSWAPEFFECT_COPY_VSYNC消失了,反正這個(gè)效果也不咋的,消失了也好。
              要做到垂直同步需要給PresentationInterval賦值D3DPRESENT_INTERVAL_DEFAULT或D3DPRESENT_INTERVAL_ONE。其中D3DPRESENT_INTERVAL_ONE的效果比D3DPRESENT_INTERVAL_DEFAULT好一點(diǎn),不過(guò)相應(yīng)的也會(huì)占用多一點(diǎn)點(diǎn)系統(tǒng)資源……真的只有一點(diǎn)點(diǎn)而已,實(shí)在是無(wú)所謂的……
              如果不要垂直同步,想要看看實(shí)際禎速的話,D3DPRESENT_INTERVAL_IMMEDIATE。
              注意在窗口模式下,你只能使用這三種Present模式,全屏幕模式下就可以使用別的(但是要首先檢測(cè)D3DCAPS9以查看顯卡是否支持)。不過(guò)我感覺(jué)對(duì)99%的游戲來(lái)說(shuō),有這三個(gè)就足夠了。
              另外在窗口模式下,BackBufferFormat也可以設(shè)置成D3DFMT_UNKNOWN,D3D會(huì)自動(dòng)獲取當(dāng)前桌面的格式設(shè)定成后備緩沖的格式,省去GetDisplayMode。實(shí)際上,窗口模式下的后備緩沖已經(jīng)不需要和桌面格式相同,你可以通過(guò)IDirect3D9::CheckDeviceFormatConversion來(lái)檢查,如果這個(gè)設(shè)備支持這兩種顏色格式之間的轉(zhuǎn)換,就可以給程序的后備緩沖設(shè)定上不同的格式。我試過(guò)在桌面格式為32Bit(D3DFMT_X8R8G8B8)時(shí)將程序的后備緩沖格式設(shè)置為D3DFMT_R5G6B5(16Bit),發(fā)現(xiàn)了速度提升,也就是說(shuō)這個(gè)設(shè)定是有意義的。
              可創(chuàng)建的設(shè)備類(lèi)型多了一種D3DDEVTYPE_NULLREF,在安裝了D3D SDK的機(jī)子上等同于D3DDEYTYPE_REF,在其他的機(jī)子上,這種設(shè)備實(shí)際上沒(méi)有創(chuàng)建真正意義的D3D設(shè)備,只是允許你創(chuàng)建的紋理、表面等資源,但是Render、Present等操作都會(huì)無(wú)效(實(shí)際上這些資源都創(chuàng)建在了D3DPOOL_SCRATCH池里,不管你設(shè)定使用的是什么POOL)。也就是說(shuō),僅僅在模擬基本的運(yùn)行而已。你可以用這個(gè)設(shè)備來(lái)編寫(xiě)一個(gè)利用D3DX函數(shù)庫(kù)進(jìn)行圖像格式轉(zhuǎn)換的程序,比如把一大堆不同的格式轉(zhuǎn)換成易于D3D9使用的DDS格式。因?yàn)閷?shí)際上沒(méi)有創(chuàng)建設(shè)備,你甚至可以編寫(xiě)成控制臺(tái)的,通過(guò)GetConsoleWindow的方法獲得HWND。Mercury 3用的MIF格式的轉(zhuǎn)換器就是這么做出來(lái)的。注意D3DDEVTYPE_NULLREF只能用在IDirect3D::CreateDevice時(shí),其他的方法都不行。

            『創(chuàng)建表面的變化』

              創(chuàng)建表面(Surface)的方法變成了IDirect3DDevice9::CreateOffscreenPlainSurface,參數(shù)很簡(jiǎn)單不用多說(shuō),需要注意的是可以選擇POOL了。

            『設(shè)定FVF的變化』

              設(shè)定FVF時(shí),原來(lái)通過(guò)IDirect3DDevice8::SetVertexShader,現(xiàn)在有了一個(gè)專(zhuān)門(mén)用來(lái)設(shè)定FVF的方法:IDirect3DDevice9::SetFVF。這是個(gè)很好的變化,省得把FVF和Shader弄混(題外話:也就是因?yàn)檫@個(gè)變化,讓Shader在設(shè)備Reset后得以保存,不錯(cuò)不錯(cuò))

            『獲取后備緩沖』

              D3D9現(xiàn)在允許有多個(gè)后備緩沖交換鏈,不過(guò)對(duì)于2D來(lái)說(shuō),基本不需要這種東西,IDirect3DDevice9::GetBackBuffer多出來(lái)的第一個(gè)參數(shù)賦值0即可。如果你有興趣,可以去研究一下這個(gè)玩意,有時(shí)候可以用來(lái)做分場(chǎng)。

            SetStreamSource』

              這個(gè)方法的功能被擴(kuò)展了,對(duì)比參數(shù)就可以知道,多出來(lái)的OffsetInBytes允許你選擇一個(gè)頂點(diǎn)緩沖的Offset,D3D9將從這個(gè)Offset之后開(kāi)始讀取數(shù)據(jù)。因此你可以把幾組用來(lái)渲染紋理的正方形頂點(diǎn)存儲(chǔ)到一個(gè)頂點(diǎn)緩沖里面。

            SetSamplerState』

              這個(gè)是D3D9的新方法,把原先SetTextureStageState的一些功能獨(dú)立了出來(lái),和2D關(guān)系最密切的就是紋理過(guò)濾了。原先的D3DTSS_MINFILTER變成了D3DSAMP_MINFILTER,相應(yīng)的D3DTSS_MAGFILTER也變成D3DSAMP_MAGFILTER,D3DTSS_MAXANISOTROPY變成D3DSAMP_MAXANISOTROPY。另外還有更多的,比如紋理尋址等。你去看一下D3DSAMPLERSTATETYPE枚舉類(lèi)型的內(nèi)容就知道它“遷移”了些什么。
              這個(gè)變化對(duì)于Shader來(lái)說(shuō)很方便。改成Sampler的東西在PixelShader過(guò)程也會(huì)有效,而沒(méi)有更改的東西在PixelShader就不會(huì)有效了。D3D8時(shí)候把這些全都放在了一起,容易造成混亂。

            SetRenderTarget』

              D3D9現(xiàn)在允許多重RenderTarget存在,不過(guò)我們基本上只用一個(gè),RenderTargetIndex設(shè)為0,第二個(gè)參數(shù)仍然是需要設(shè)定的表面。與D3D8相同的是,在設(shè)定之前仍然需要先通過(guò)GetSurfaceLevel獲得表面才行。

            『頂點(diǎn)緩沖的鎖定』

              注意IDirect3DVertexBuffer9::Lock的第三個(gè)參數(shù),從原來(lái)的BYTE**變成了void**。也就是這樣了……

            『其他的一些變化』

            1、CopyRects變成了UpdateSurface。和UpdateTexture一樣,只能從D3DPOOL_SYSTEMMEM拷貝到D3DPOOL_DEFAULT
            2、增加了一個(gè)比較有用的IDirect3DDevice9::ColorFill方法,作用是向D3DPOOL_DEFAULT的某個(gè)區(qū)域填充顏色,和Clear的功能類(lèi)似,但是在使用目的上要比Clear明確的多,并且由于不牽扯深度緩沖之類(lèi),速度要快一些。
            3、增加了一個(gè)IDirect3DDevice9::StretchRect方法,通過(guò)這個(gè)方法就可以在D3DPOOL_DEFAULT的表面或紋理之間進(jìn)行帶過(guò)濾器的縮放操作,免去利用Render的過(guò)程,非常有用。不過(guò)這個(gè)方法由于使用了硬件處理,限制較多,請(qǐng)大家仔細(xì)看SDK文檔的Remarks部分。

            《D3DX的變化》

              D3DX的變化實(shí)際上相當(dāng)?shù)亩啵缥乙婚_(kāi)始所說(shuō),基本都是面向3D的。需要我們注意的有以下幾種:
            1、D3DX***FromFile之類(lèi)的函數(shù)支持的圖像格式增加了,不過(guò)所增加的都是很少見(jiàn)的格式。平時(shí)基本上還是用BMP、TGA和PNG就足夠。
            2、增加了D3DXSave***ToFileInMemory,將會(huì)把文件寫(xiě)入內(nèi)存。這個(gè)函數(shù)的作用似乎不是很容易想到,但是如果你要寫(xiě)一個(gè)集成了轉(zhuǎn)換、打包功能的工具,這個(gè)就很有用了,省去了通過(guò)臨時(shí)文件操作造成的各種問(wèn)題。另外如果你熟悉某種圖形文件的格式的話,還可以通過(guò)直接訪問(wèn)這個(gè)文件獲得RAW信息。注意,這類(lèi)函數(shù)寫(xiě)入的是一個(gè)ID3DXBuffer,這個(gè)東西很簡(jiǎn)單,只有兩個(gè)特定的方法,一看便懂,不再多言。
            3、增加了一個(gè)ID3DXLine,可以方便你在2D上畫(huà)線,創(chuàng)建ID3DXLine的方法是D3DXCreateLine。這個(gè)東西也不復(fù)雜,使用方法有點(diǎn)像ID3DXSprite,稍微研究一下就能弄懂,注意每次Draw的是D3DPT_LINESTRIP。用它比直接用頂點(diǎn)緩沖的好處是可以方便的打開(kāi)反鋸齒,效果嘛……基本滿(mǎn)意。
            4、增加了一個(gè)ID3DXRenderToSurface,“理論上來(lái)說(shuō)”方便了利用RenderTarget的過(guò)程……不過(guò)我感覺(jué)反而弄得復(fù)雜了。創(chuàng)建的方法是D3DXCreateRenderToSurface,有心情的朋友自己研究看看吧,我就不講了。

              ID3DXSprite和ID3DXFont在Summer 2004的DX9 SDK(也就是第一版DX9.0c)開(kāi)始發(fā)生了很大變化,下面詳述:

            『ID3DXSprite』

              你會(huì)發(fā)現(xiàn)ID3DXSprite::DrawTransform不見(jiàn)了,取而代之的是其功能被整合到ID3DXSprite::SetTransform里面,也就是說(shuō)為了縮放和旋轉(zhuǎn),我們不得不和矩陣打交道了。其實(shí)也不會(huì)太復(fù)雜,因?yàn)槲覀冎皇亲鲆恍┚仃囘\(yùn)算,學(xué)過(guò)線性代數(shù)的朋友肯定會(huì)很熟悉,就算你不怎么熟悉線性代數(shù),也沒(méi)關(guān)系,D3DX函數(shù)庫(kù)提供了現(xiàn)成的矩陣運(yùn)算函數(shù),你只要用就行了。

            D3DXMatrixScaling
            D3DXMatrixRotationZ
            D3DXMatrixTranslation

              按照順序調(diào)用這三個(gè)函數(shù)……或許學(xué)過(guò)3D的馬上就想到這點(diǎn)了,的確是沒(méi)錯(cuò)啦。注意順序哦:Scaling -> Rotation -> Translation,簡(jiǎn)稱(chēng)SRT(看過(guò)全金屬狂潮嗎?看過(guò)的話這個(gè)單詞很好記吧^_^),弄錯(cuò)了可是得不到正確結(jié)果的。
              你是不是想到把同一個(gè)D3DXMATRIX當(dāng)作參數(shù)使用三次?錯(cuò)啦!你要用矩陣乘法。創(chuàng)建三個(gè)D3DXMATRIX,比如mat1、mat2、mat3,分別用這三個(gè)函數(shù)將其創(chuàng)建為縮放矩陣、旋轉(zhuǎn)矩陣和平移矩陣,然后在ID3DXSprite::SetTransform時(shí),這樣寫(xiě):

            SetTransform(mat1 * mat2 * mat3);

              有夠麻煩的是不?ID3DXSprite方便了做3D的,可害苦了做2D的,所以我已經(jīng)不直接用這個(gè)了(什么叫不直接用?往下看)。

            『ID3DXFont』

              大家來(lái)歡呼吧!Summer 2004改進(jìn)的ID3DXFont徹底槍斃掉了上一話那個(gè)字體引擎……
              這東西的改進(jìn),怎么說(shuō)呢,應(yīng)該說(shuō)是改頭換面吧,速度、效果都和以前不是一個(gè)數(shù)量級(jí)。可憐的PixelFont,才存在了一話就要被拋棄了。
              ID3DXFont多出來(lái)的幾個(gè)方法,Preload*()這類(lèi)的,就是把一些常用的字的字模提前讀取到內(nèi)存里面加快速度,同時(shí)還可以使用ID3DXSprite渲染,進(jìn)一步加快速度。雖然內(nèi)部仍然有GDI的部分,不過(guò)很明顯工作方式發(fā)生了極大的變化。根據(jù)我的估計(jì),這次的ID3DXFont很聰明的利用GDI獲得文字的輪廓,然后通過(guò)紋理來(lái)渲染。這樣的速度就快得多了,而且文字質(zhì)量也得到了很好的控制,基本和直接用GDI的質(zhì)量相同了。
              由于PreloadCharacters()和PreloadGlyphs()不是那么好理解,一般用PreloadText()就行。建議將所有ASCII字符、標(biāo)點(diǎn)符號(hào)和部分漢字預(yù)讀進(jìn)去。這個(gè)預(yù)讀過(guò)程略微有點(diǎn)慢,而且根據(jù)預(yù)讀的文字?jǐn)?shù)量和你創(chuàng)建文字的字號(hào),占用的內(nèi)存也不同。這里給大家一堆文字,你Copy過(guò)去就行:

            引用

            const char strPreloadText[] = " 1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM~!@#$%^&*()-=[]\\;',./_+{}|:\"<>? 、。·ˉˇ¨〃—~‖…‘’“”〔〕〈〉《》「」『』〖〗【】!"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}我人有的和主產(chǎn)不為這工要在第一上是中國(guó)經(jīng)已發(fā)了民同";

              注意第一個(gè)字符是空格哦!把空格預(yù)讀進(jìn)去可是很重要的^_^
              看上去并不多,因?yàn)橐紤]到內(nèi)存占用及速度,我只預(yù)讀了一些符號(hào)和五筆的一鍵字。這些字符在24號(hào)字時(shí)候已經(jīng)占用了快1MB了,比起PixelFont字庫(kù)占用的要大得多。天知道ID3DXFont到底預(yù)讀了些什么……
              PreloadText()的第二個(gè)參數(shù)不要用strlen,sizeof(strPreloadText)即可。
              然后就是利用ID3DXSprite來(lái)渲染。注意ID3DXFont::DrawText的第一個(gè)參數(shù)就是LPD3DXSPRITE,因此如果要利用ID3DXSprite,要將ID3DXFont::DrawText放到ID3DXSprite::Begin和ID3DXSprite::End之間。這就是我剛才說(shuō)的不直接用ID3DXSprite的意思,ID3DXFont會(huì)完成ID3DXSprite的全部調(diào)用,你不用擔(dān)心。
              另外你應(yīng)該注意到ID3DXSprite::Begin增加了參數(shù),實(shí)際上DX文檔里面沒(méi)說(shuō),但是示例里面有,如果想讓ID3DXSprite發(fā)揮作用并且最大幅度的提升效率,參數(shù)上設(shè)定D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE即可。意思很明白:打開(kāi)Alpha過(guò)濾和紋理篩選。這里DX文檔上有個(gè)錯(cuò)誤一直沒(méi)改:文檔里給出的是D3DXSprite__SORT_TEXTURE,但是你可以試試,絕對(duì)報(bào)錯(cuò)。
              剩下的就沒(méi)啥了,ID3DXFont的使用方法上一話已經(jīng)講過(guò)。要注意的是D3DXCreateFont和D3DXCreateFontIndirect都發(fā)生了變化。D3DXCreateFont已經(jīng)不再牽扯GDI了,D3DXCreateFontIndirect所使用的結(jié)構(gòu)也變成了D3DXFONT_DESC,相對(duì)于LOGFONT結(jié)構(gòu),除去了一些用不著的參數(shù),增加了一個(gè)MipLevels,就是MipMap等級(jí)啦,不用多說(shuō),2D下只用1。其他的上一話都有。實(shí)際上由于D3DXCreateFont已經(jīng)不再關(guān)聯(lián)GDI,D3DXCreateFontIndirect的存在僅僅是由于歷史原因(為了兼容像我這種人的使用習(xí)慣),大家還是用D3DXCreateFont吧,省事。
              截圖就不貼了,沒(méi)啥意義。你可能覺(jué)得直接向后備緩沖上DrawText還不夠好看,那么就先畫(huà)到一張紋理上,然后將紋理錯(cuò)位渲染到后備緩沖并且打開(kāi)線型過(guò)濾,就可以達(dá)到和PixelFont相同的效果了。
              速度嘛……我畫(huà)了整整一屏幕字,在不緩沖文字的情況下(這個(gè)“緩沖文字”和ID3DXFont的文字緩沖可不是一回事啊!看過(guò)上一話的都應(yīng)該知道我這里指的是什么),速度仍然在120FPS以上。或許你會(huì)覺(jué)得速度還是有點(diǎn)慢,但是,如果用D3D8的ID3DXFont畫(huà)上這么一屏幕,基本就只剩20FPS了。
              使用ID3DXFont替換掉PixelFont的優(yōu)勢(shì)就是可以方便的自定義字體字號(hào)了,并且也不再受GB2312字庫(kù)的限制。所以大家都換了吧……都換了吧……把PixelFont忘了吧……

            『穩(wěn)定的DX9 SDK版本』

              我現(xiàn)在用的是April 2006,而且應(yīng)該會(huì)用很長(zhǎng)時(shí)間。August 2006我是肯定不會(huì)去用啦!即使我不再恐懼D3D9,也會(huì)對(duì)這個(gè)SDK避讓三分的。其實(shí)對(duì)于2D,我感覺(jué)用到April 2006就足夠了,之后的DX9 SDK主要在D3DX的3D函數(shù)庫(kù)部分進(jìn)行更改……其實(shí)也是秋后的螞蚱蹦達(dá)不了幾天,D3D10馬上就要出來(lái)了。要說(shuō)D3D10啊……你還是看我另外一篇日志好了,總之打死我都不拿它做2D。

              實(shí)際上僅僅是2D的話,從D3D8轉(zhuǎn)向D3D9并沒(méi)有多少變化,主要是穩(wěn)定嘛!只要你不調(diào)用一些D3D9專(zhuān)用的功能,即使拿D3D9來(lái)做2D,在絕大多數(shù)顯卡上還是能夠運(yùn)行的。嗯……GF2等級(jí)以上吧,GF2之前的,也太老了,無(wú)視好了。

            《再上點(diǎn)菜好了:全屏幕模式》

              其實(shí)并不是多么復(fù)雜的問(wèn)題,讓我拖了這么久……不拖了,這里就教給大家如何做全屏幕模式以及如何處理設(shè)備丟失的問(wèn)題。

            『創(chuàng)建全屏幕模式』

              D3DPRESENT_PARAMS里面,Windowed設(shè)定為false,并且一定要設(shè)定BackBufferWidth和BackBufferHeight,完畢。
              哈哈,就這么簡(jiǎn)單,或許早就有人嘗試過(guò)了,但是你試試按下Alt+Tab,再切換回去,保證你什么都看不到。
              之前曾經(jīng)說(shuō)過(guò),DX8之前的版本,在全屏幕下工作比在窗口下容易,到DX8之后就則完全顛倒過(guò)來(lái)。因?yàn)樵诖翱谀J较虏挥脫?dān)心設(shè)備丟失(除非你更改桌面分辨率),全屏幕模式下就會(huì)有這個(gè)問(wèn)題了。下面詳述:

            『設(shè)備、資源丟失』

              設(shè)備丟失會(huì)發(fā)生在全屏幕模式下切換回桌面時(shí)(不論是通過(guò)Alt+Tab還是QQ上有人給你發(fā)了張圖片-_-bbb),而且如果在調(diào)用IDirect3DDevice9::Reset(從現(xiàn)在開(kāi)始就是D3D9了啊!忘記D3D8吧……)的時(shí)候發(fā)生錯(cuò)誤,設(shè)備也會(huì)丟失。
              設(shè)備丟失會(huì)造成資源丟失:所有創(chuàng)建在D3DPOOL_DEFAULT池的資源都會(huì)丟失,需要重新創(chuàng)建,其內(nèi)容當(dāng)然也會(huì)消失,需要重寫(xiě)。
              然而創(chuàng)建在D3DPOOL_SYSTEMMEM和D3DPOOL_SCRATCH池的資源不會(huì)受到影響。創(chuàng)建在D3DPOOL_MANAGED池的資源也不會(huì)丟失,而且在設(shè)備重新可用的時(shí)候,D3DPOOL_MANAGED池的資源也可以立即投入使用,內(nèi)容也不會(huì)改變。看這個(gè)池名字:托管池就能知道,D3D幫你處理了所有問(wèn)題。
              因此避免設(shè)備丟失后資源丟失的簡(jiǎn)易方法就是將所有資源創(chuàng)建在D3DPOOL_MANAGED池內(nèi)。不過(guò)這并不是個(gè)好方法,這意味著不能用渲染對(duì)象——記得嗎?RenderTarget只能創(chuàng)建在D3DPOOL_DEFAULT。實(shí)際上最好的方法是跟蹤所有D3DPOOL_DEFAULT資源,比如利用std::list,將所有D3DPOOL_DEFAULT資源勾住,在設(shè)備發(fā)生丟失的時(shí)候釋放掉資源,設(shè)備可以繼續(xù)使用的時(shí)候重新創(chuàng)建資源,記得把數(shù)據(jù)寫(xiě)回去。對(duì)于其他的池就不用這么折騰了。

            『當(dāng)設(shè)備丟失之后』

              不論通過(guò)任何方式發(fā)生了設(shè)備丟失,所有的操作幾乎都會(huì)失效,只有Release()可以用——其實(shí)D3D會(huì)保證有部分操作可以成功,但是也僅僅是“可以”成功而不是“一定”成功,所以你還不如認(rèn)定丟失的時(shí)候全都會(huì)失敗比較好——以及IDirect3DDevice9::TestCooperativeLevel。因此在設(shè)備丟失之后,你應(yīng)該停止整個(gè)游戲循環(huán),而通過(guò)反復(fù)調(diào)用IDirect3DDevice9::TestCooperativeLevel判斷設(shè)備是否可用。

            『IDirect3DDevice9::TestCooperativeLevel』

              這個(gè)方法檢測(cè)當(dāng)前的設(shè)備狀態(tài)。返回值有四種:D3D_OK一切正常,D3DERR_DEVICELOST設(shè)備丟失,D3DERR_DEVICENOTRESET設(shè)備可以Reset。另外還有D3D9新增的D3DERR_DRIVERINTERNALERROR,遇到這個(gè)你就完蛋了,基本不可能恢復(fù)了,終止程序吧。
              按照順序來(lái)講,如果游戲在正常運(yùn)行,D3D_OK會(huì)返回;如果發(fā)生了設(shè)備丟失并且在這個(gè)時(shí)候不能恢復(fù),比如全屏幕模式的時(shí)候用戶(hù)切換到了Windows桌面,就會(huì)返回D3DERR_DEVICELOST;如果用戶(hù)又切換回了游戲,設(shè)備可以恢復(fù)了(還沒(méi)恢復(fù)呢!只是“可以”恢復(fù)而已),就會(huì)返回D3DERR_DEVICENOTRESET
              另外,IDirect3DDevice9::Present也會(huì)返回類(lèi)似的值,不過(guò)你最好別指望這個(gè),老老實(shí)實(shí)的用TestCooperativeLevel。因?yàn)镻resent在設(shè)備可以恢復(fù)的時(shí)候還是返回D3DERR_DEVICELOST(外一句:D3D10的時(shí)候TestCooperativeLevel就會(huì)完全整合到Present里面了,可喜可賀可喜可賀)

            『處理設(shè)備丟失』

              看下面的偽代碼:

            switch (IDirect3DDevice9::TestCooperativeLevel()){
              case D3D_OK:
                GameLoop();
                break;
              case D3DERR_DEVICELOST:
                break;
              case D3DERR_DEVICENOTRESET
                OnLostDevice();
                IDirect3DDevice9::Reset();
                OnResetDevice();
                break;
              default:
                QuitGame();
                break;
            }

              GameLoop()就是你的游戲運(yùn)行的過(guò)程了。把這個(gè)switch寫(xiě)在我們游戲框架的GameMain()部分,具體的位置可以看任何一話附帶的源代碼。
              好像我一直沒(méi)有講IDirect3DDevice9::Reset的參數(shù)啊?因?yàn)橹挥幸粋€(gè)參數(shù),就是指向D3DPRESENT_PARAMS的指針。把你第一次創(chuàng)建設(shè)備時(shí)使用的D3DPRESENT_PARAMS結(jié)構(gòu)保存起來(lái),供Reset來(lái)用。
              OnLostDevice()就是Release掉所有D3DPOOL_DEFAULT的資源,OnResetDevice()就是Create*()恢復(fù)啦!你可能注意到ID3DXFont、ID3DXSprite等等都有同名的方法,就是在這個(gè)時(shí)候調(diào)用的。如果你沒(méi)有這么做,也就是說(shuō)還保留著任何D3DPOOL_DEFAULT的資源的話,IDirect3DDevice9::Reset就一定會(huì)失敗。
              另外在OnResetDevice里面你還要重新進(jìn)行SetRenderState、SetSamplerState等等,Reset之后這些東西也丟失了。實(shí)際上Reset和重新創(chuàng)建一次設(shè)備類(lèi)似,所不同的是重新創(chuàng)建設(shè)備的話你需要連D3DPOOL_MANAGED的資源也Release掉。這個(gè)話題就不討論了。
              從代碼可以看出來(lái),D3DERR_DEVICELOST時(shí)程序什么都沒(méi)做,只是在傻等。我認(rèn)為這是一個(gè)好習(xí)慣,因?yàn)閷?shí)在不能保證在D3DERR_DEVICELOST時(shí)除了Release還能干什么,與其這樣還不如等設(shè)備能用了再說(shuō)。

              實(shí)在懶得管資源的話,全部D3DPOOL_MANAGED好了。至于渲染對(duì)象?自己想辦法。

            『人工制造“設(shè)備丟失”』

              “干嘛還要制造設(shè)備丟失啊?”如果更改游戲分辨率、色深、切換全屏幕及窗口狀態(tài),進(jìn)行這樣的操作也要通過(guò)Reset,同樣的,Reset之前也要釋放掉所有D3DPOOL_DEFAULT資源(其實(shí)嚴(yán)格來(lái)說(shuō),還有更多的資源也要釋放,不過(guò)在2D下基本不會(huì)創(chuàng)建這類(lèi)資源,你就不用管了)并且調(diào)用ID3DXSprite::OnLostDevice之類(lèi)的方法。這就是人工制造“設(shè)備丟失”了。實(shí)際上在這個(gè)過(guò)程設(shè)備并沒(méi)有真正的丟失,只是會(huì)有一段時(shí)間處于不可用的狀態(tài),此時(shí)Reset尚未返回,整個(gè)D3D設(shè)備就好像死了一樣。舉個(gè)例子,你切換桌面分辨率,會(huì)有那么一段時(shí)間顯示器上什么都不顯示,然后很快就正常了。和這個(gè)現(xiàn)象是同一個(gè)原因。Reset成功后記得恢復(fù)資源。
              你可能注意到這里的Reset和上面的Reset不是一回事。的確是這樣,這里是為了重設(shè)狀態(tài)而不是恢復(fù)設(shè)備。因此更改分辨率、色深的Reset需要寫(xiě)到switch外面,也就是別和它攪和的意思-_-bb。而且你只需要OnLostDevice -> Reset -> OnResetDevice。記住:正確的調(diào)用Reset不會(huì)造成設(shè)備丟失,這個(gè)概念別弄混了。

            『切換全屏幕模式時(shí)的注意事項(xiàng)』

              注意WindowStyle的變化。切換成全屏幕模式后,只能使用WS_POPUP,不然顯示會(huì)變得怪怪的,你可以通過(guò)SetWindowLongPtr函數(shù)更改窗口外觀,第二個(gè)參數(shù)指定GWL_STYLE即可。別忘了WS_VISIBLE啊!不然你什么都看不見(jiàn)。

            『更詳細(xì)的文檔』

              我這里只是簡(jiǎn)單討論了造成設(shè)備丟失的原因及處理方法,更詳細(xì)的內(nèi)容你可以參考DX SDK文檔的Lost Device文章,人家是權(quán)威的。

            【以上,正片結(jié)束,后面是ED】

              我們前進(jìn)到了D3D9,趕上了時(shí)代。
              我們創(chuàng)建了全屏幕游戲,趕上了時(shí)代。
              我卻變得一腦子漿糊,被觀眾拋棄了。
              哈哈,開(kāi)玩笑啦,不過(guò)這一話很亂倒是真的,因?yàn)椴徽撌歉碌紻3D9還是設(shè)備丟失,牽扯的東西都太散太雜,結(jié)果弄得這一話也是一盤(pán)散沙(居然又沒(méi)有附帶代碼)。唉,大家就忍了吧,忍不了的話就來(lái)PIA我吧。

              關(guān)于更新至D3D9更多的內(nèi)容,你可以參考SDK文檔的《Converting to Direct3D 9》。

            【以上,ED結(jié)束,后面是……】

              第一季完結(jié)了……
              回過(guò)頭來(lái)看看,從第一話創(chuàng)建一個(gè)Windows窗口,到這一話的設(shè)備丟失,話題的層次一直在深入,現(xiàn)在已經(jīng)深入到了不再是“學(xué)習(xí)”而是“研究”的范圍。我也不再想僅僅是搞“教學(xué)”而是想和大家“討論”。不過(guò)第一季主要還是教學(xué)吧。能堅(jiān)持著看D2D教程到現(xiàn)在的,應(yīng)該基本能夠?qū)懗鐾暾?D Demo來(lái)了吧。如果有什么問(wèn)題的話,歡迎提出,我在看到后會(huì)立刻回答的……只要你這個(gè)問(wèn)題不太RP的話……
              那么,第二季會(huì)是什么樣子?
              第二季就不再是教學(xué)了,而開(kāi)始我和大家的討論過(guò)程。第二季的第一話,也就是第09話,我將提供一些高級(jí)技巧給大家,并希望有興趣的朋友和我一起進(jìn)行這些技巧的研究。另外在第二季里面,我們還要?jiǎng)?chuàng)建一個(gè)2D圖形引擎。原來(lái)打算給大家講解Medux 2,不過(guò)現(xiàn)在感覺(jué)這東西實(shí)在小兒科,絕對(duì)會(huì)讓大家B4的。那么既然如此,干脆介紹Mercury 3好了,有意見(jiàn)無(wú)?
              透漏一點(diǎn)下一話的內(nèi)容吧:模糊精度和多次紋理渲染,嘿嘿,聽(tīng)上去挺高深的是不?實(shí)際上超級(jí)簡(jiǎn)單,就看你能不能想到而已。
              希望你在看完這一話之后,返回去再把前面的內(nèi)容看看,相信你會(huì)得到新的收獲。搞不好你還能抓出幾個(gè)Bug呢!因?yàn)槲沂窍氲绞裁磳?xiě)什么,沒(méi)個(gè)章法,Bug是難免的。
             


            附加:

            Direct3D中的字體與文本顯示
            圖形系統(tǒng)中為了獲得當(dāng)前運(yùn)行程序的相關(guān)信息,往往需要在屏幕上顯示文本,Direct3D的功能擴(kuò)展接口ID3DXFont對(duì)此提供了方便的解決方法。

             

             

            創(chuàng)建ID3DXFont對(duì)象

            使用接口ID3DXFont繪制文本,首先需要通過(guò)函數(shù)D3DXCreateFont()創(chuàng)建ID3DXFont字體對(duì)象。ID3DXFont接口封裝了Windows字體和Direct3D設(shè)備指針,D3DXCreateFont()函數(shù)通過(guò)Windows字體和Direct3D設(shè)備指針創(chuàng)建ID3DXFont對(duì)象,該函數(shù)的聲明如下:

            Creates a font object for a device and font.

            HRESULT D3DXCreateFont(  LPDIRECT3DDEVICE9 pDevice,  INT Height,  UINT Width,  UINT Weight,  UINT MipLevels,  BOOL Italic,  DWORD CharSet,  DWORD OutputPrecision,  DWORD Quality,  DWORD PitchAndFamily,  LPCTSTR pFacename,  LPD3DXFONT * ppFont);
            Parameters
            pDevice
            [in] Pointer to an IDirect3DDevice9 interface, the device to be associated with the font object.
            Height
            [in] The height of the characters in logical units.
            Width
            [in] The width of the characters in logical units.
            Weight
            [in] Typeface weight. One example is bold.
            MipLevels
            [in] The number of mipmap levels.
            Italic
            [in] True for italic font, false otherwise.
            CharSet
            [in] The character set of the font.
            OutputPrecision
            [in] Specifies how Windows should attempt to match the desired font sizes and characteristics with actual fonts. Use OUT_TT_ONLY_PRECIS for instance, to ensure that you always get a TrueType font.
            Quality
            [in] Specifies how Windows should match the desired font with a real font. It applies to raster fonts only and should not affect TrueType fonts.
            PitchAndFamily
            [in] Pitch and family index.
            pFacename
            [in] String containing the typeface name. If the compiler settings require Unicode, the data type LPCTSTR resolves to LPCWSTR. Otherwise, the string data type resolves to LPCSTR. See Remarks.
            ppFont
            [out] Returns a pointer to an ID3DXFont interface, representing the created font object.
            Return Values
            If the function succeeds, the return value is S_OK. If the function fails, the return value can be one of the following: D3DERR_INVALIDCALL, D3DXERR_INVALIDDATA, E_OUTOFMEMORY.

            Remarks
            The creation of an ID3DXFont object requires that the device supports 32-bit color.

            The compiler setting also determines the function version. If Unicode is defined, the function call resolves to D3DXCreateFontW. Otherwise, the function call resolves to D3DXCreateFontA because ANSI strings are being used.

            If you want more information about font parameters, see The Logical Font.

            示例代碼如下:

            D3DXCreateFont(g_device, 50, 20, 20, 0, FALSE, DEFAULT_CHARSET, 0, 0, 0, "Arial", &g_font);

            posted on 2009-09-12 07:40 RedLight 閱讀(2388) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): 3D渲染技術(shù)

            <2009年11月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            導(dǎo)航

            統(tǒng)計(jì)

            公告


            Name: Galen
            QQ: 88104725

            常用鏈接

            留言簿(3)

            隨筆分類(lèi)

            隨筆檔案

            相冊(cè)

            My Friend

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久99精品国产麻豆不卡| 久久精品亚洲AV久久久无码| 国产视频久久| 伊人伊成久久人综合网777| 久久久无码人妻精品无码| 91精品国产91久久久久久| 久久这里的只有是精品23| 久久久久久夜精品精品免费啦| 精品国产一区二区三区久久| 久久综合给合综合久久| 久久综合给合久久狠狠狠97色| 久久精品一区二区影院| 久久婷婷五月综合色高清| 三级片免费观看久久| 久久精品中文字幕久久| 性欧美大战久久久久久久久| 久久婷婷人人澡人人| 99久久国产主播综合精品| 精品无码久久久久国产| 欧美精品乱码99久久蜜桃| 91久久九九无码成人网站| 婷婷五月深深久久精品| 中文精品久久久久人妻| 久久精品18| 成人国内精品久久久久影院VR| 91精品国产高清91久久久久久| 一本一本久久A久久综合精品| 国产精品久久久久久久久久影院| 久久精品国产清自在天天线| 99久久精品久久久久久清纯| 国产精品久久久久久| 2021精品国产综合久久| 久久精品国产亚洲av影院 | 三级片免费观看久久| 久久精品这里热有精品| 久久九九亚洲精品| 久久亚洲欧美日本精品| 亚洲综合精品香蕉久久网97 | 国产女人aaa级久久久级| 久久久综合九色合综国产| 亚洲狠狠综合久久|