• <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作為講解的語言繼續(xù)D2D教程。

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

            『Why?』

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

            《D3D的變化》

            『界面名稱變化』

              一句話:8改成9就行。

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

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

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

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

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

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

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

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

            『獲取后備緩沖』

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

            SetStreamSource』

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

            SetSamplerState』

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

            SetRenderTarget』

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

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

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

            『其他的一些變化』

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

            《D3DX的變化》

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

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

            『ID3DXSprite』

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

            D3DXMatrixScaling
            D3DXMatrixRotationZ
            D3DXMatrixTranslation

              按照順序調(diào)用這三個(gè)函數(shù)……或許學(xué)過3D的馬上就想到這點(diǎn)了,的確是沒錯(cuò)啦。注意順序哦:Scaling -> Rotation -> Translation,簡稱SRT(看過全金屬狂潮嗎?看過的話這個(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í),這樣寫:

            SetTransform(mat1 * mat2 * mat3);

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

            『ID3DXFont』

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

            引用

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

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

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

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

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

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

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

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

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

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

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

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

              不論通過任何方式發(fā)生了設(shè)備丟失,所有的操作幾乎都會(huì)失效,只有Release()可以用——其實(shí)D3D會(huì)保證有部分操作可以成功,但是也僅僅是“可以”成功而不是“一定”成功,所以你還不如認(rèn)定丟失的時(shí)候全都會(huì)失敗比較好——以及IDirect3DDevice9::TestCooperativeLevel。因此在設(shè)備丟失之后,你應(yīng)該停止整個(gè)游戲循環(huán),而通過反復(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ù)了,終止程序吧。
              按照順序來講,如果游戲在正常運(yùn)行,D3D_OK會(huì)返回;如果發(fā)生了設(shè)備丟失并且在這個(gè)時(shí)候不能恢復(fù),比如全屏幕模式的時(shí)候用戶切換到了Windows桌面,就會(huì)返回D3DERR_DEVICELOST;如果用戶又切換回了游戲,設(shè)備可以恢復(fù)了(還沒恢復(fù)呢!只是“可以”恢復(fù)而已),就會(huì)返回D3DERR_DEVICENOTRESET
              另外,IDirect3DDevice9::Present也會(huì)返回類似的值,不過你最好別指望這個(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)行的過程了。把這個(gè)switch寫在我們游戲框架的GameMain()部分,具體的位置可以看任何一話附帶的源代碼。
              好像我一直沒有講IDirect3DDevice9::Reset的參數(shù)啊?因?yàn)橹挥幸粋€(gè)參數(shù),就是指向D3DPRESENT_PARAMS的指針。把你第一次創(chuàng)建設(shè)備時(shí)使用的D3DPRESENT_PARAMS結(jié)構(gòu)保存起來,供Reset來用。
              OnLostDevice()就是Release掉所有D3DPOOL_DEFAULT的資源,OnResetDevice()就是Create*()恢復(fù)啦!你可能注意到ID3DXFont、ID3DXSprite等等都有同名的方法,就是在這個(gè)時(shí)候調(diào)用的。如果你沒有這么做,也就是說還保留著任何D3DPOOL_DEFAULT的資源的話,IDirect3DDevice9::Reset就一定會(huì)失敗。
              另外在OnResetDevice里面你還要重新進(jìn)行SetRenderState、SetSamplerState等等,Reset之后這些東西也丟失了。實(shí)際上Reset和重新創(chuàng)建一次設(shè)備類似,所不同的是重新創(chuàng)建設(shè)備的話你需要連D3DPOOL_MANAGED的資源也Release掉。這個(gè)話題就不討論了。
              從代碼可以看出來,D3DERR_DEVICELOST時(shí)程序什么都沒做,只是在傻等。我認(rèn)為這是一個(gè)好習(xí)慣,因?yàn)閷?shí)在不能保證在D3DERR_DEVICELOST時(shí)除了Release還能干什么,與其這樣還不如等設(shè)備能用了再說。

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

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

              “干嘛還要制造設(shè)備丟失啊?”如果更改游戲分辨率、色深、切換全屏幕及窗口狀態(tài),進(jìn)行這樣的操作也要通過Reset,同樣的,Reset之前也要釋放掉所有D3DPOOL_DEFAULT資源(其實(shí)嚴(yán)格來說,還有更多的資源也要釋放,不過在2D下基本不會(huì)創(chuàng)建這類資源,你就不用管了)并且調(diào)用ID3DXSprite::OnLostDevice之類的方法。這就是人工制造“設(shè)備丟失”了。實(shí)際上在這個(gè)過程設(shè)備并沒有真正的丟失,只是會(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需要寫到switch外面,也就是別和它攪和的意思-_-bb。而且你只需要OnLostDevice -> Reset -> OnResetDevice。記住:正確的調(diào)用Reset不會(huì)造成設(shè)備丟失,這個(gè)概念別弄混了。

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

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

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

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

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

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

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

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

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


            附加:

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

             

             

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

            使用接口ID3DXFont繪制文本,首先需要通過函數(shù)D3DXCreateFont()創(chuàng)建ID3DXFont字體對(duì)象。ID3DXFont接口封裝了Windows字體和Direct3D設(shè)備指針,D3DXCreateFont()函數(shù)通過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 閱讀(2407) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 3D渲染技術(shù)

            <2008年4月>
            303112345
            6789101112
            13141516171819
            20212223242526
            27282930123
            45678910

            導(dǎo)航

            統(tǒng)計(jì)

            公告


            Name: Galen
            QQ: 88104725

            常用鏈接

            留言簿(3)

            隨筆分類

            隨筆檔案

            相冊(cè)

            My Friend

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久精品一区二区| 色婷婷久久久SWAG精品| 人妻精品久久无码区| 亚洲伊人久久精品影院| 国产精品久久久久影院色| 99久久精品免费| 一本久久知道综合久久| 狠狠色综合久久久久尤物| 久久伊人精品一区二区三区| 蜜臀av性久久久久蜜臀aⅴ麻豆 | 久久久免费精品re6| 一本伊大人香蕉久久网手机| 色综合久久中文字幕综合网| 国内精品伊人久久久久| 久久99热这里只有精品66| 91精品国产91久久久久久青草| 欧美精品九九99久久在观看| 一本大道久久a久久精品综合| 亚洲午夜久久久影院| 看全色黄大色大片免费久久久| 国产精品国色综合久久| 99久久99久久精品国产片果冻| 国内精品欧美久久精品| 欧美一区二区精品久久| 国内精品久久久人妻中文字幕 | 久久婷婷五月综合色高清 | 国产2021久久精品| av国内精品久久久久影院| 一本色道久久99一综合| 久久久久精品国产亚洲AV无码| 久久久久无码中| 久久精品人人做人人爽电影| 亚洲午夜久久久久久久久久| 久久久久国产精品人妻| 伊人色综合久久天天网| 一本一道久久a久久精品综合 | 婷婷久久综合九色综合98| 久久人人爽人人人人片av| 久久亚洲欧美日本精品| 国产美女久久久| 91久久国产视频|