精华内容
下载资源
问答
  • D3d9的一些更新

    千次阅读 2012-10-11 16:31:40
    由于Aug 8造成的D3D9恐惧症已经完全消除了,这一章将会给大家介绍将3D引擎转向D3D9的各个方面,包括终于出现的全屏幕模式。从这章以后,我将使用D3D9作为讲解的语言继续D2D教程。 【OP结束,开始正片】 『Why...
    D3d9的一些更新 (转)
    2010-04-13 21:17
    由于Aug 8造成的D3D9恐惧症已经完全消除了,这一章将会给大家介绍将3D引擎转向D3D9的各个方面,包括终于出现的全屏幕模式。从这章以后,我将使用D3D9作为讲解的语言继续D2D教程。

    【OP结束,开始正片】

    『Why?』

      估计大家首先要问的就是“Why?”为什么要前进到D3D9?理由如下:
    1、D3D9修复了D3D8已知的所有Bug,因此运行起来更稳定,速度也要快。
    2、D3D9提供了许多便利的新功能,虽然绝大多数是面向3D的,但是也有不少2D适用的,比如IDirect3DDevice9::StretchRect,以及对IDirect3DSurface9的改进等等。D3DX库就更多了,比如D3DXSaveSurfaceToFileInMemory,一开始没发现这个函数有啥用处,现在基本离不开了。
    3、HLSL。就像上一话我说的那样,D2D教程以后会有PixelShader的内容。我可不想拿汇编来写Shader,会死人的(祝贺我吧,终于抛弃汇编Shader了……)。虽然说这不是决定性的理由,因为还有Cg什么的,不过我想编写显卡无关的代码,因此我不去研究Cg(反正和HLSL差不多)以及R2VB之类。
    4、ID3DXFont,往下看你就知道了。

    《D3D的变化》

    『界面名称变化』

      一句话:8改成9就行。

    『“创建”型方法的一个统一变化』

      许多Create*()方法,比如创建设备、创建纹理、创建顶点缓冲等等,多了一个HANDLE* pSharedHandle参数,无用,NULL之(看来微软原打算弄个共享句柄之类,不过被D3D10巨大的变化浮云了)

    『创建D3D设备的变化』

      D3DPRESENT_PARAMS的FullScreen_PresentationInterval变成了PresentationInterval,也就是说即使在窗口模式下也可以做到垂直同步来防止撕裂现象(2D的福音啊)。相应的,D3DSWAPEFFECT_COPY_VSYNC消失了,反正这个效果也不咋的,消失了也好。
      要做到垂直同步需要给PresentationInterval赋值D3DPRESENT_INTERVAL_DEFAULT或D3DPRESENT_INTERVAL_ONE。其中D3DPRESENT_INTERVAL_ONE的效果比D3DPRESENT_INTERVAL_DEFAULT好一点,不过相应的也会占用多一点点系统资源……真的只有一点点而已,实在是无所谓的……
      如果不要垂直同步,想要看看实际祯速的话,D3DPRESENT_INTERVAL_IMMEDIATE。
      注意在窗口模式下,你只能使用这三种Present模式,全屏幕模式下就可以使用别的(但是要首先检测D3DCAPS9以查看显卡是否支持)。不过我感觉对99%的游戏来说,有这三个就足够了。
      另外在窗口模式下,BackBufferFormat也可以设置成D3DFMT_UNKNOWN,D3D会自动获取当前桌面的格式设定成后备缓冲的格式,省去GetDisplayMode。实际上,窗口模式下的后备缓冲已经不需要和桌面格式相同,你可以通过IDirect3D9::CheckDeviceFormatConversion来检查,如果这个设备支持这两种颜色格式之间的转换,就可以给程序的后备缓冲设定上不同的格式。我试过在桌面格式为32Bit(D3DFMT_X8R8G8B8)时将程序的后备缓冲格式设置为D3DFMT_R5G6B5(16Bit),发现了速度提升,也就是说这个设定是有意义的。
      可创建的设备类型多了一种D3DDEVTYPE_NULLREF,在安装了D3D SDK的机子上等同于D3DDEYTYPE_REF,在其他的机子上,这种设备实际上没有创建真正意义的D3D设备,只是允许你创建的纹理、表面等资源,但是Render、Present等操作都会无效(实际上这些资源都创建在了D3DPOOL_SCRATCH池里,不管你设定使用的是什么POOL)。也就是说,仅仅在模拟基本的运行而已。你可以用这个设备来编写一个利用D3DX函数库进行图像格式转换的程序,比如把一大堆不同的格式转换成易于D3D9使用的DDS格式。因为实际上没有创建设备,你甚至可以编写成控制台的,通过GetConsoleWindow的方法获得HWND。Mercury 3用的MIF格式的转换器就是这么做出来的。注意D3DDEVTYPE_NULLREF只能用在IDirect3D::CreateDevice时,其他的方法都不行。

    『创建表面的变化』

      创建表面(Surface)的方法变成了IDirect3DDevice9::CreateOffscreenPlainSurface,参数很简单不用多说,需要注意的是可以选择POOL了。

    『设定FVF的变化』

      设定FVF时,原来通过IDirect3DDevice8::SetVertexShader,现在有了一个专门用来设定FVF的方法:IDirect3DDevice9::SetFVF。这是个很好的变化,省得把FVF和Shader弄混(题外话:也就是因为这个变化,让Shader在设备Reset后得以保存,不错不错)

    『获取后备缓冲』

      D3D9现在允许有多个后备缓冲交换链,不过对于2D来说,基本不需要这种东西,IDirect3DDevice9::GetBackBuffer多出来的第一个参数赋值0即可。如果你有兴趣,可以去研究一下这个玩意,有时候可以用来做分场。

    SetStreamSource』

      这个方法的功能被扩展了,对比参数就可以知道,多出来的OffsetInBytes允许你选择一个顶点缓冲的Offset,D3D9将从这个Offset之后开始读取数据。因此你可以把几组用来渲染纹理的正方形顶点存储到一个顶点缓冲里面。

    SetSamplerState』

      这个是D3D9的新方法,把原先SetTextureStageState的一些功能独立了出来,和2D关系最密切的就是纹理过滤了。原先的D3DTSS_MINFILTER变成了D3DSAMP_MINFILTER,相应的D3DTSS_MAGFILTER也变成D3DSAMP_MAGFILTER,D3DTSS_MAXANISOTROPY变成D3DSAMP_MAXANISOTROPY。另外还有更多的,比如纹理寻址等。你去看一下D3DSAMPLERSTATETYPE枚举类型的内容就知道它“迁移”了些什么。
      这个变化对于Shader来说很方便。改成Sampler的东西在PixelShader过程也会有效,而没有更改的东西在PixelShader就不会有效了。D3D8时候把这些全都放在了一起,容易造成混乱。

    SetRenderTarget』

      D3D9现在允许多重RenderTarget存在,不过我们基本上只用一个,RenderTargetIndex设为0,第二个参数仍然是需要设定的表面。与D3D8相同的是,在设定之前仍然需要先通过GetSurfaceLevel获得表面才行。

    『顶点缓冲的锁定』

      注意IDirect3DVertexBuffer9::Lock的第三个参数,从原来的BYTE**变成了void**。也就是这样了……

    『其他的一些变化』

    1、CopyRects变成了UpdateSurface。和UpdateTexture一样,只能从D3DPOOL_SYSTEMMEM拷贝到D3DPOOL_DEFAULT
    2、增加了一个比较有用的IDirect3DDevice9::ColorFill方法,作用是向D3DPOOL_DEFAULT的某个区域填充颜色,和Clear的功能类似,但是在使用目的上要比Clear明确的多,并且由于不牵扯深度缓冲之类,速度要快一些。
    3、增加了一个IDirect3DDevice9::StretchRect方法,通过这个方法就可以在D3DPOOL_DEFAULT的表面或纹理之间进行带过滤器的缩放操作,免去利用Render的过程,非常有用。不过这个方法由于使用了硬件处理,限制较多,请大家仔细看SDK文档的Remarks部分。

    《D3DX的变化》

      D3DX的变化实际上相当的多,但正如我一开始所说,基本都是面向3D的。需要我们注意的有以下几种:
    1、D3DX***FromFile之类的函数支持的图像格式增加了,不过所增加的都是很少见的格式。平时基本上还是用BMP、TGA和PNG就足够。
    2、增加了D3DXSave***ToFileInMemory,将会把文件写入内存。这个函数的作用似乎不是很容易想到,但是如果你要写一个集成了转换、打包功能的工具,这个就很有用了,省去了通过临时文件操作造成的各种问题。另外如果你熟悉某种图形文件的格式的话,还可以通过直接访问这个文件获得RAW信息。注意,这类函数写入的是一个ID3DXBuffer,这个东西很简单,只有两个特定的方法,一看便懂,不再多言。
    3、增加了一个ID3DXLine,可以方便你在2D上画线,创建ID3DXLine的方法是D3DXCreateLine。这个东西也不复杂,使用方法有点像ID3DXSprite,稍微研究一下就能弄懂,注意每次Draw的是D3DPT_LINESTRIP。用它比直接用顶点缓冲的好处是可以方便的打开反锯齿,效果嘛……基本满意。
    4、增加了一个ID3DXRenderToSurface,“理论上来说”方便了利用RenderTarget的过程……不过我感觉反而弄得复杂了。创建的方法是D3DXCreateRenderToSurface,有心情的朋友自己研究看看吧,我就不讲了。

      ID3DXSprite和ID3DXFont在Summer 2004的DX9 SDK(也就是第一版DX9.0c)开始发生了很大变化,下面详述:

    『ID3DXSprite』

      你会发现ID3DXSprite::DrawTransform不见了,取而代之的是其功能被整合到ID3DXSprite::SetTransform里面,也就是说为了缩放和旋转,我们不得不和矩阵打交道了。其实也不会太复杂,因为我们只是做一些矩阵运算,学过线性代数的朋友肯定会很熟悉,就算你不怎么熟悉线性代数,也没关系,D3DX函数库提供了现成的矩阵运算函数,你只要用就行了。

    D3DXMatrixScaling
    D3DXMatrixRotationZ
    D3DXMatrixTranslation

      按照顺序调用这三个函数……或许学过3D的马上就想到这点了,的确是没错啦。注意顺序哦:Scaling -> Rotation -> Translation,简称SRT(看过全金属狂潮吗?看过的话这个单词很好记吧^_^),弄错了可是得不到正确结果的。
      你是不是想到把同一个D3DXMATRIX当作参数使用三次?错啦!你要用矩阵乘法。创建三个D3DXMATRIX,比如mat1、mat2、mat3,分别用这三个函数将其创建为缩放矩阵、旋转矩阵和平移矩阵,然后在ID3DXSprite::SetTransform时,这样写:

    SetTransform(mat1 * mat2 * mat3);

      有够麻烦的是不?ID3DXSprite方便了做3D的,可害苦了做2D的,所以我已经不直接用这个了(什么叫不直接用?往下看)。

    『ID3DXFont』

      大家来欢呼吧!Summer 2004改进的ID3DXFont彻底枪毙掉了上一话那个字体引擎……
      这东西的改进,怎么说呢,应该说是改头换面吧,速度、效果都和以前不是一个数量级。可怜的PixelFont,才存在了一话就要被抛弃了。
      ID3DXFont多出来的几个方法,Preload*()这类的,就是把一些常用的字的字模提前读取到内存里面加快速度,同时还可以使用ID3DXSprite渲染,进一步加快速度。虽然内部仍然有GDI的部分,不过很明显工作方式发生了极大的变化。根据我的估计,这次的ID3DXFont很聪明的利用GDI获得文字的轮廓,然后通过纹理来渲染。这样的速度就快得多了,而且文字质量也得到了很好的控制,基本和直接用GDI的质量相同了。
      由于PreloadCharacters()和PreloadGlyphs()不是那么好理解,一般用PreloadText()就行。建议将所有ASCII字符、标点符号和部分汉字预读进去。这个预读过程略微有点慢,而且根据预读的文字数量和你创建文字的字号,占用的内存也不同。这里给大家一堆文字,你Copy过去就行:

    引用

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

      注意第一个字符是空格哦!把空格预读进去可是很重要的^_^
      看上去并不多,因为要考虑到内存占用及速度,我只预读了一些符号和五笔的一键字。这些字符在24号字时候已经占用了快1MB了,比起PixelFont字库占用的要大得多。天知道ID3DXFont到底预读了些什么……
      PreloadText()的第二个参数不要用strlen,sizeof(strPreloadText)即可。
      然后就是利用ID3DXSprite来渲染。注意ID3DXFont::DrawText的第一个参数就是LPD3DXSPRITE,因此如果要利用ID3DXSprite,要将ID3DXFont::DrawText放到ID3DXSprite::Begin和ID3DXSprite::End之间。这就是我刚才说的不直接用ID3DXSprite的意思,ID3DXFont会完成ID3DXSprite的全部调用,你不用担心。
      另外你应该注意到ID3DXSprite::Begin增加了参数,实际上DX文档里面没说,但是示例里面有,如果想让ID3DXSprite发挥作用并且最大幅度的提升效率,参数上设定D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE即可。意思很明白:打开Alpha过滤和纹理筛选。这里DX文档上有个错误一直没改:文档里给出的是D3DXSprite__SORT_TEXTURE,但是你可以试试,绝对报错。
      剩下的就没啥了,ID3DXFont的使用方法上一话已经讲过。要注意的是D3DXCreateFont和D3DXCreateFontIndirect都发生了变化。D3DXCreateFont已经不再牵扯GDI了,D3DXCreateFontIndirect所使用的结构也变成了D3DXFONT_DESC,相对于LOGFONT结构,除去了一些用不着的参数,增加了一个MipLevels,就是MipMap等级啦,不用多说,2D下只用1。其他的上一话都有。实际上由于D3DXCreateFont已经不再关联GDI,D3DXCreateFontIndirect的存在仅仅是由于历史原因(为了兼容像我这种人的使用习惯),大家还是用D3DXCreateFont吧,省事。
      截图就不贴了,没啥意义。你可能觉得直接向后备缓冲上DrawText还不够好看,那么就先画到一张纹理上,然后将纹理错位渲染到后备缓冲并且打开线型过滤,就可以达到和PixelFont相同的效果了。
      速度嘛……我画了整整一屏幕字,在不缓冲文字的情况下(这个“缓冲文字”和ID3DXFont的文字缓冲可不是一回事啊!看过上一话的都应该知道我这里指的是什么),速度仍然在120FPS以上。或许你会觉得速度还是有点慢,但是,如果用D3D8的ID3DXFont画上这么一屏幕,基本就只剩20FPS了。
      使用ID3DXFont替换掉PixelFont的优势就是可以方便的自定义字体字号了,并且也不再受GB2312字库的限制。所以大家都换了吧……都换了吧……把PixelFont忘了吧……

    『稳定的DX9 SDK版本』

      我现在用的是April 2006,而且应该会用很长时间。August 2006我是肯定不会去用啦!即使我不再恐惧D3D9,也会对这个SDK避让三分的。其实对于2D,我感觉用到April 2006就足够了,之后的DX9 SDK主要在D3DX的3D函数库部分进行更改……其实也是秋后的蚂蚱蹦达不了几天,D3D10马上就要出来了。要说D3D10啊……你还是看我另外一篇日志好了,总之打死我都不拿它做2D。

      实际上仅仅是2D的话,从D3D8转向D3D9并没有多少变化,主要是稳定嘛!只要你不调用一些D3D9专用的功能,即使拿D3D9来做2D,在绝大多数显卡上还是能够运行的。嗯……GF2等级以上吧,GF2之前的,也太老了,无视好了。

    《再上点菜好了:全屏幕模式》

      其实并不是多么复杂的问题,让我拖了这么久……不拖了,这里就教给大家如何做全屏幕模式以及如何处理设备丢失的问题。

    『创建全屏幕模式』

      D3DPRESENT_PARAMS里面,Windowed设定为false,并且一定要设定BackBufferWidth和BackBufferHeight,完毕。
      哈哈,就这么简单,或许早就有人尝试过了,但是你试试按下Alt+Tab,再切换回去,保证你什么都看不到。
      之前曾经说过,DX8之前的版本,在全屏幕下工作比在窗口下容易,到DX8之后就则完全颠倒过来。因为在窗口模式下不用担心设备丢失(除非你更改桌面分辨率),全屏幕模式下就会有这个问题了。下面详述:

    『设备、资源丢失』

      设备丢失会发生在全屏幕模式下切换回桌面时(不论是通过Alt+Tab还是QQ上有人给你发了张图片-_-bbb),而且如果在调用IDirect3DDevice9::Reset(从现在开始就是D3D9了啊!忘记D3D8吧……)的时候发生错误,设备也会丢失。
      设备丢失会造成资源丢失:所有创建在D3DPOOL_DEFAULT池的资源都会丢失,需要重新创建,其内容当然也会消失,需要重写。
      然而创建在D3DPOOL_SYSTEMMEM和D3DPOOL_SCRATCH池的资源不会受到影响。创建在D3DPOOL_MANAGED池的资源也不会丢失,而且在设备重新可用的时候,D3DPOOL_MANAGED池的资源也可以立即投入使用,内容也不会改变。看这个池名字:托管池就能知道,D3D帮你处理了所有问题。
      因此避免设备丢失后资源丢失的简易方法就是将所有资源创建在D3DPOOL_MANAGED池内。不过这并不是个好方法,这意味着不能用渲染对象——记得吗?RenderTarget只能创建在D3DPOOL_DEFAULT。实际上最好的方法是跟踪所有D3DPOOL_DEFAULT资源,比如利用std::list,将所有D3DPOOL_DEFAULT资源勾住,在设备发生丢失的时候释放掉资源,设备可以继续使用的时候重新创建资源,记得把数据写回去。对于其他的池就不用这么折腾了。

    『当设备丢失之后』

      不论通过任何方式发生了设备丢失,所有的操作几乎都会失效,只有Release()可以用——其实D3D会保证有部分操作可以成功,但是也仅仅是“可以”成功而不是“一定”成功,所以你还不如认定丢失的时候全都会失败比较好——以及IDirect3DDevice9::TestCooperativeLevel。因此在设备丢失之后,你应该停止整个游戏循环,而通过反复调用IDirect3DDevice9::TestCooperativeLevel判断设备是否可用。

    『IDirect3DDevice9::TestCooperativeLevel』

      这个方法检测当前的设备状态。返回值有四种:D3D_OK一切正常,D3DERR_DEVICELOST设备丢失,D3DERR_DEVICENOTRESET设备可以Reset。另外还有D3D9新增的D3DERR_DRIVERINTERNALERROR,遇到这个你就完蛋了,基本不可能恢复了,终止程序吧。
      按照顺序来讲,如果游戏在正常运行,D3D_OK会返回;如果发生了设备丢失并且在这个时候不能恢复,比如全屏幕模式的时候用户切换到了Windows桌面,就会返回D3DERR_DEVICELOST;如果用户又切换回了游戏,设备可以恢复了(还没恢复呢!只是“可以”恢复而已),就会返回D3DERR_DEVICENOTRESET
      另外,IDirect3DDevice9::Present也会返回类似的值,不过你最好别指望这个,老老实实的用TestCooperativeLevel。因为Present在设备可以恢复的时候还是返回D3DERR_DEVICELOST(外一句:D3D10的时候TestCooperativeLevel就会完全整合到Present里面了,可喜可贺可喜可贺)

    『处理设备丢失』

      看下面的伪代码:

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

      GameLoop()就是你的游戏运行的过程了。把这个switch写在我们游戏框架的GameMain()部分,具体的位置可以看任何一话附带的源代码。
      好像我一直没有讲IDirect3DDevice9::Reset的参数啊?因为只有一个参数,就是指向D3DPRESENT_PARAMS的指针。把你第一次创建设备时使用的D3DPRESENT_PARAMS结构保存起来,供Reset来用。
      OnLostDevice()就是Release掉所有D3DPOOL_DEFAULT的资源,OnResetDevice()就是Create*()恢复啦!你可能注意到ID3DXFont、ID3DXSprite等等都有同名的方法,就是在这个时候调用的。如果你没有这么做,也就是说还保留着任何D3DPOOL_DEFAULT的资源的话,IDirect3DDevice9::Reset就一定会失败。
      另外在OnResetDevice里面你还要重新进行SetRenderState、SetSamplerState等等,Reset之后这些东西也丢失了。实际上Reset和重新创建一次设备类似,所不同的是重新创建设备的话你需要连D3DPOOL_MANAGED的资源也Release掉。这个话题就不讨论了。
      从代码可以看出来,D3DERR_DEVICELOST时程序什么都没做,只是在傻等。我认为这是一个好习惯,因为实在不能保证在D3DERR_DEVICELOST时除了Release还能干什么,与其这样还不如等设备能用了再说。

      实在懒得管资源的话,全部D3DPOOL_MANAGED好了。至于渲染对象?自己想办法。

    『人工制造“设备丢失”』

      “干嘛还要制造设备丢失啊?”如果更改游戏分辨率、色深、切换全屏幕及窗口状态,进行这样的操作也要通过Reset,同样的,Reset之前也要释放掉所有D3DPOOL_DEFAULT资源(其实严格来说,还有更多的资源也要释放,不过在2D下基本不会创建这类资源,你就不用管了)并且调用ID3DXSprite::OnLostDevice之类的方法。这就是人工制造“设备丢失”了。实际上在这个过程设备并没有真正的丢失,只是会有一段时间处于不可用的状态,此时Reset尚未返回,整个D3D设备就好像死了一样。举个例子,你切换桌面分辨率,会有那么一段时间显示器上什么都不显示,然后很快就正常了。和这个现象是同一个原因。Reset成功后记得恢复资源。
      你可能注意到这里的Reset和上面的Reset不是一回事。的确是这样,这里是为了重设状态而不是恢复设备。因此更改分辨率、色深的Reset需要写到switch外面,也就是别和它搅和的意思-_-bb。而且你只需要OnLostDevice -> Reset -> OnResetDevice。记住:正确的调用Reset不会造成设备丢失,这个概念别弄混了。

    『切换全屏幕模式时的注意事项』

      注意WindowStyle的变化。切换成全屏幕模式后,只能使用WS_POPUP,不然显示会变得怪怪的,你可以通过SetWindowLongPtr函数更改窗口外观,第二个参数指定GWL_STYLE即可。别忘了WS_VISIBLE啊!不然你什么都看不见。

    『更详细的文档』

      我这里只是简单讨论了造成设备丢失的原因及处理方法,更详细的内容你可以参考DX SDK文档的Lost Device文章,人家是权威的。

    【以上,正片结束,后面是ED】

      我们前进到了D3D9,赶上了时代。
      我们创建了全屏幕游戏,赶上了时代。
      我却变得一脑子浆糊,被观众抛弃了。
      哈哈,开玩笑啦,不过这一话很乱倒是真的,因为不论是更新到D3D9还是设备丢失,牵扯的东西都太散太杂,结果弄得这一话也是一盘散沙(居然又没有附带代码)。唉,大家就忍了吧,忍不了的话就来PIA我吧。

      关于更新至D3D9更多的内容,你可以参考SDK文档的《Converting to Direct3D 9》。

    【以上,ED结束,后面是……】

      第一季完结了……
      回过头来看看,从第一话创建一个Windows窗口,到这一话的设备丢失,话题的层次一直在深入,现在已经深入到了不再是“学习”而是“研究”的范围。我也不再想仅仅是搞“教学”而是想和大家“讨论”。不过第一季主要还是教学吧。能坚持着看D2D教程到现在的,应该基本能够写出完整的2D Demo来了吧。如果有什么问题的话,欢迎提出,我在看到后会立刻回答的……只要你这个问题不太RP的话……
      那么,第二季会是什么样子?
      第二季就不再是教学了,而开始我和大家的讨论过程。第二季的第一话,也就是第09话,我将提供一些高级技巧给大家,并希望有兴趣的朋友和我一起进行这些技巧的研究。另外在第二季里面,我们还要创建一个2D图形引擎。原来打算给大家讲解Medux 2,不过现在感觉这东西实在小儿科,绝对会让大家B4的。那么既然如此,干脆介绍Mercury 3好了,有意见无?
      透漏一点下一话的内容吧:模糊精度和多次纹理渲染,嘿嘿,听上去挺高深的是不?实际上超级简单,就看你能不能想到而已。
      希望你在看完这一话之后,返回去再把前面的内容看看,相信你会得到新的收获。搞不好你还能抓出几个Bug呢!因为我是想到什么写什么,没个章法,Bug是难免的。
    D3d9的一些更新

    附加:

    Direct3D中的字体与文本显示
    图形系统中为了获得当前运行程序的相关信息,往往需要在屏幕上显示文本,Direct3D的功能扩展接口ID3DXFont对此提供了方便的解决方法。

    创建ID3DXFont对象

    使用接口ID3DXFont绘制文本,首先需要通过函数D3DXCreateFont()创建ID3DXFont字体对象。ID3DXFont接口封装了Windows字体和Direct3D设备指针,D3DXCreateFont()函数通过Windows字体和Direct3D设备指针创建ID3DXFont对象,该函数的声明如下:

    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);

    展开全文
  • SetRenderState() D3D9的视频卡设备的渲染状态设置方法 下面是一部分可设置的渲染状态: D3DRS_FILLMODE 绘制模式设置,可设置为点,线与面模式3种分别是:(D3DFILL_POINT , D3DFILL_WIREFRAME, D3DFILL_SOLID...

    **

    device->SetRenderState()

    ** D3D9的视频卡设备的渲染状态设置方法
    下面是一部分可设置的渲染状态:
    D3DRS_FILLMODE 绘制模式设置,可设置为点,线与面模式3种分别是:(D3DFILL_POINT , D3DFILL_WIREFRAME, D3DFILL_SOLID)

    D3DRS_CULLMODE 消隐模式,按照三角形单元的顶点绕序进行背面消隐,可设置为(禁用背面消隐D3DCULL_NONE,对顺时针绕序消隐D3DCULL_CW,对逆时针绕序消隐D3DCULL_CCW)

    D3DRS_LIGHTING 光照开关,可设置为true与false,开启光照或禁用光照

    D3DRS_SHADEMODE 着色模式 对顶点的着色模式分2种(平面着色,一个面的颜色根据第一个顶点的颜色值决定D3DSHADE_FLAT,平滑着色,一个面中根据各个顶点的颜色值计算线性插值着色D3DSHADE_GOURAUD,D3DSHADE_PHONG这个不知道是啥子,请指教,好像跟平滑着色一样效果)

    D3DRS_ZWRITEENABLE 深度缓存是否可写入设置 默认为true,设为false为不应许写入,设为false后渲染几个模型时将随渲染的时间决定哪个模型在最前(可见)

    D3DRS_NORMALIZENORMALS 规范化法向量,默认为不打开,设true为开启,false为关闭,使用了自定义的顶点格式中有使用法向量的需要开启

    D3DRS_SPECULARENABLE 启用镜面光,true为开,false为关闭,默认为关闭,因为镜面光为反射光,其计算成本高

    D3DRS_ALPHABLENDENABLE 打开融合,true为开,false为关闭,默认为关闭,使用融合能做出隐身的效果

    D3DRS_SRCBLEND 设定融合因子,使用不同的融合因子和目标融合因子可以做出很多有趣的事情

    D3DRS_DESTBLEND 设定目标融合因子,同上面的组合才能做出很多有趣的事情

    device->SetTransform()设置渲染状态之矩阵

    下面是我用过的一些状态字:
    D3DTS_PROJECTION :设置投影矩阵,将一个透视投影矩阵设置为当前的可观察到的范围,形状及可见度,例如:

    	D3DXMATRIX touying;
    	D3DXMatrixPerspectiveFovLH(&touying, D3DX_PI * 0.5f, dm.Width / dm.Height, 1.0f, 1000.0f);//将投影数据写入矩阵proj  D3DX_PI*0.5f
    	device->SetTransform(D3DTS_PROJECTION, &touying);			//设置投影矩阵
    

    D3DTS_VIEW :设置观察坐标系,告诉视频卡设备,摄像机在哪个位置,摄像机以哪个点为观察中心,世界坐标系中哪个方向是向上(世界正方向),例如:摄像机在世界坐标系中Z轴的负9点,以世界坐标系0,0,0的点为观察中心,y轴的正方向是世界正方向,代码如下

    	D3DXVECTOR3 SXJx{ 0,0,-9 }, SXJy{ 0,0,0 }, SXJz{ 0,1,0 };	//摄像机位置,观察点,世界正方向
    	D3DXMATRIX SXJZD;											//摄像机矩阵
    	D3DXMatrixLookAtLH(&shexiangji, &SXJx, &SXJy, &SXJz);		//合并成一个摄像机矩阵
    	device->SetTransform(D3DTS_VIEW, &shexiangji);				//告诉D3D9使用这个观察坐标系
    

    D3DTS_WORLD :设置世界变换矩阵,告诉视频卡设备,把接下来要渲染的模型按照当前设置的矩阵位移,例如在渲染一个物体前,设置一个向x轴的正方向移动5个单位,在接下来渲染的模型都将移动到这个位置,代码如下:

    	D3DXMATRIX ss;
    	D3DXMatrixTranslation(&ss, 5.0f, 0.0f, 0.0f);				//创建一个平移矩阵
    	device->SetTransform(D3DTS_WORLD, &ss);						//世界变化
    

    目前我就知道这些可设置的渲染状态,还有很多不知道的,我是不会使用SDK的苦逼

    展开全文
  • 转载:D3D9的更新 关于devicelost

    千次阅读 2011-07-01 10:18:00
    http://blog.csdn.net/SeanSeanSeanSeanSean/archive/2009/03/19/4006128.aspx D3d9的一些更新 收藏 由于Aug 8造成的D3D9恐惧症已经完全消除了,这一章将会给大家介绍将3D引擎转向D3D9的各个方面...

    http://blog.csdn.net/SeanSeanSeanSeanSean/archive/2009/03/19/4006128.aspx

     

    D3d9的一些更新 收藏

     由于Aug 8造成的D3D9恐惧症已经完全消除了,这一章将会给大家介绍将3D引擎转向D3D9的各个方面,包括终于出现的全屏幕模式。从这章以后,我将使用D3D9作为讲解的语言继续D2D教程。

    【OP结束,开始正片】

    『Why?』

      估计大家首先要问的就是“Why?”为什么要前进到D3D9?理由如下:
    1、D3D9修复了D3D8已知的所有Bug,因此运行起来更稳定,速度也要快。
    2、D3D9提供了许多便利的新功能,虽然绝大多数是面向3D的,但是也有不少2D适用的,比如IDirect3DDevice9::StretchRect,以及对IDirect3DSurface9的改进等等。D3DX库就更多了,比如D3DXSaveSurfaceToFileInMemory,一开始没发现这个函数有啥用处,现在基本离不开了。
    3、HLSL。就像上一话我说的那样,D2D教程以后会有PixelShader的内容。我可不想拿汇编来写Shader,会死人的(祝贺我吧,终于抛弃汇编Shader了……)。虽然说这不是决定性的理由,因为还有Cg什么的,不过我想编写显卡无关的代码,因此我不去研究Cg(反正和HLSL差不多)以及R2VB之类。
    4、ID3DXFont,往下看你就知道了。

    《D3D的变化》

    『界面名称变化』

      一句话:8改成9就行。

    『“创建”型方法的一个统一变化』

      许多Create*()方法,比如创建设备、创建纹理、创建顶点缓冲等等,多了一个HANDLE* pSharedHandle参数,无用,NULL之(看来微软原打算弄个共享句柄之类,不过被D3D10巨大的变化浮云了)

    『创建D3D设备的变化』

      D3DPRESENT_PARAMS的FullScreen_PresentationInterval变成了PresentationInterval,也就是说即使在窗口模式下也可以做到垂直同步来防止撕裂现象(2D的福音啊)。相应的,D3DSWAPEFFECT_COPY_VSYNC消失了,反正这个效果也不咋的,消失了也好。
      要做到垂直同步需要给PresentationInterval赋值D3DPRESENT_INTERVAL_DEFAULT或D3DPRESENT_INTERVAL_ONE。其中D3DPRESENT_INTERVAL_ONE的效果比D3DPRESENT_INTERVAL_DEFAULT好一点,不过相应的也会占用多一点点系统资源……真的只有一点点而已,实在是无所谓的……
      如果不要垂直同步,想要看看实际祯速的话,D3DPRESENT_INTERVAL_IMMEDIATE。
      注意在窗口模式下,你只能使用这三种Present模式,全屏幕模式下就可以使用别的(但是要首先检测D3DCAPS9以查看显卡是否支持)。不过我感觉对99%的游戏来说,有这三个就足够了。
      另外在窗口模式下,BackBufferFormat也可以设置成D3DFMT_UNKNOWN,D3D会自动获取当前桌面的格式设定成后备缓冲的格式,省去GetDisplayMode。实际上,窗口模式下的后备缓冲已经不需要和桌面格式相同,你可以通过IDirect3D9::CheckDeviceFormatConversion来检查,如果这个设备支持这两种颜色格式之间的转换,就可以给程序的后备缓冲设定上不同的格式。我试过在桌面格式为32Bit(D3DFMT_X8R8G8B8)时将程序的后备缓冲格式设置为D3DFMT_R5G6B5(16Bit),发现了速度提升,也就是说这个设定是有意义的。
      可创建的设备类型多了一种D3DDEVTYPE_NULLREF,在安装了D3D SDK的机子上等同于D3DDEYTYPE_REF,在其他的机子上,这种设备实际上没有创建真正意义的D3D设备,只是允许你创建的纹理、表面等资源,但是Render、Present等操作都会无效(实际上这些资源都创建在了D3DPOOL_SCRATCH池里,不管你设定使用的是什么POOL)。也就是说,仅仅在模拟基本的运行而已。你可以用这个设备来编写一个利用D3DX函数库进行图像格式转换的程序,比如把一大堆不同的格式转换成易于D3D9使用的DDS格式。因为实际上没有创建设备,你甚至可以编写成控制台的,通过GetConsoleWindow的方法获得HWND。Mercury 3用的MIF格式的转换器就是这么做出来的。注意D3DDEVTYPE_NULLREF只能用在IDirect3D::CreateDevice时,其他的方法都不行。

    『创建表面的变化』

      创建表面(Surface)的方法变成了IDirect3DDevice9::CreateOffscreenPlainSurface,参数很简单不用多说,需要注意的是可以选择POOL了。

    『设定FVF的变化』

      设定FVF时,原来通过IDirect3DDevice8::SetVertexShader,现在有了一个专门用来设定FVF的方法:IDirect3DDevice9::SetFVF。这是个很好的变化,省得把FVF和Shader弄混(题外话:也就是因为这个变化,让Shader在设备Reset后得以保存,不错不错)

    『获取后备缓冲』

      D3D9现在允许有多个后备缓冲交换链,不过对于2D来说,基本不需要这种东西,IDirect3DDevice9::GetBackBuffer多出来的第一个参数赋值0即可。如果你有兴趣,可以去研究一下这个玩意,有时候可以用来做分场。

    『SetStreamSource』

      这个方法的功能被扩展了,对比参数就可以知道,多出来的OffsetInBytes允许你选择一个顶点缓冲的Offset,D3D9将从这个Offset之后开始读取数据。因此你可以把几组用来渲染纹理的正方形顶点存储到一个顶点缓冲里面。

    『SetSamplerState』

      这个是D3D9的新方法,把原先SetTextureStageState的一些功能独立了出来,和2D关系最密切的就是纹理过滤了。原先的D3DTSS_MINFILTER变成了D3DSAMP_MINFILTER,相应的D3DTSS_MAGFILTER也变成D3DSAMP_MAGFILTER,D3DTSS_MAXANISOTROPY变成D3DSAMP_MAXANISOTROPY。另外还有更多的,比如纹理寻址等。你去看一下D3DSAMPLERSTATETYPE枚举类型的内容就知道它“迁移”了些什么。
      这个变化对于Shader来说很方便。改成Sampler的东西在PixelShader过程也会有效,而没有更改的东西在PixelShader就不会有效了。D3D8时候把这些全都放在了一起,容易造成混乱。

    『SetRenderTarget』

      D3D9现在允许多重RenderTarget存在,不过我们基本上只用一个,RenderTargetIndex设为0,第二个参数仍然是需要设定的表面。与D3D8相同的是,在设定之前仍然需要先通过GetSurfaceLevel获得表面才行。

    『顶点缓冲的锁定』

      注意IDirect3DVertexBuffer9::Lock的第三个参数,从原来的BYTE**变成了void**。也就是这样了……

    『其他的一些变化』

    1、CopyRects变成了UpdateSurface。和UpdateTexture一样,只能从D3DPOOL_SYSTEMMEM拷贝到D3DPOOL_DEFAULT
    2、增加了一个比较有用的IDirect3DDevice9::ColorFill方法,作用是向D3DPOOL_DEFAULT的某个区域填充颜色,和Clear的功能类似,但是在使用目的上要比Clear明确的多,并且由于不牵扯深度缓冲之类,速度要快一些。
    3、增加了一个IDirect3DDevice9::StretchRect方法,通过这个方法就可以在D3DPOOL_DEFAULT的表面或纹理之间进行带过滤器的缩放操作,免去利用Render的过程,非常有用。不过这个方法由于使用了硬件处理,限制较多,请大家仔细看SDK文档的Remarks部分。

    《D3DX的变化》

      D3DX的变化实际上相当的多,但正如我一开始所说,基本都是面向3D的。需要我们注意的有以下几种:
    1、D3DX***FromFile之类的函数支持的图像格式增加了,不过所增加的都是很少见的格式。平时基本上还是用BMP、TGA和PNG就足够。
    2、增加了D3DXSave***ToFileInMemory,将会把文件写入内存。这个函数的作用似乎不是很容易想到,但是如果你要写一个集成了转换、打包功能的工具,这个就很有用了,省去了通过临时文件操作造成的各种问题。另外如果你熟悉某种图形文件的格式的话,还可以通过直接访问这个文件获得RAW信息。注意,这类函数写入的是一个ID3DXBuffer,这个东西很简单,只有两个特定的方法,一看便懂,不再多言。
    3、增加了一个ID3DXLine,可以方便你在2D上画线,创建ID3DXLine的方法是D3DXCreateLine。这个东西也不复杂,使用方法有点像ID3DXSprite,稍微研究一下就能弄懂,注意每次Draw的是D3DPT_LINESTRIP。用它比直接用顶点缓冲的好处是可以方便的打开反锯齿,效果嘛……基本满意。
    4、增加了一个ID3DXRenderToSurface,“理论上来说”方便了利用RenderTarget的过程……不过我感觉反而弄得复杂了。创建的方法是D3DXCreateRenderToSurface,有心情的朋友自己研究看看吧,我就不讲了。

      ID3DXSprite和ID3DXFont在Summer 2004的DX9 SDK(也就是第一版DX9.0c)开始发生了很大变化,下面详述:

    『ID3DXSprite』

      你会发现ID3DXSprite::DrawTransform不见了,取而代之的是其功能被整合到ID3DXSprite::SetTransform里面,也就是说为了缩放和旋转,我们不得不和矩阵打交道了。其实也不会太复杂,因为我们只是做一些矩阵运算,学过线性代数的朋友肯定会很熟悉,就算你不怎么熟悉线性代数,也没关系,D3DX函数库提供了现成的矩阵运算函数,你只要用就行了。

    D3DXMatrixScaling
    D3DXMatrixRotationZ
    D3DXMatrixTranslation

      按照顺序调用这三个函数……或许学过3D的马上就想到这点了,的确是没错啦。注意顺序哦:Scaling -> Rotation -> Translation,简称SRT(看过全金属狂潮吗?看过的话这个单词很好记吧^_^),弄错了可是得不到正确结果的。
      你是不是想到把同一个D3DXMATRIX当作参数使用三次?错啦!你要用矩阵乘法。创建三个D3DXMATRIX,比如mat1、mat2、mat3,分别用这三个函数将其创建为缩放矩阵、旋转矩阵和平移矩阵,然后在ID3DXSprite::SetTransform时,这样写:

    SetTransform(mat1 * mat2 * mat3);

      有够麻烦的是不?ID3DXSprite方便了做3D的,可害苦了做2D的,所以我已经不直接用这个了(什么叫不直接用?往下看)。

    『ID3DXFont』

      大家来欢呼吧!Summer 2004改进的ID3DXFont彻底枪毙掉了上一话那个字体引擎……
      这东西的改进,怎么说呢,应该说是改头换面吧,速度、效果都和以前不是一个数量级。可怜的PixelFont,才存在了一话就要被抛弃了。
      ID3DXFont多出来的几个方法,Preload*()这类的,就是把一些常用的字的字模提前读取到内存里面加快速度,同时还可以使用ID3DXSprite渲染,进一步加快速度。虽然内部仍然有GDI的部分,不过很明显工作方式发生了极大的变化。根据我的估计,这次的ID3DXFont很聪明的利用GDI获得文字的轮廓,然后通过纹理来渲染。这样的速度就快得多了,而且文字质量也得到了很好的控制,基本和直接用GDI的质量相同了。
      由于PreloadCharacters()和PreloadGlyphs()不是那么好理解,一般用PreloadText()就行。建议将所有ASCII字符、标点符号和部分汉字预读进去。这个预读过程略微有点慢,而且根据预读的文字数量和你创建文字的字号,占用的内存也不同。这里给大家一堆文字,你Copy过去就行:

    引用

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


      注意第一个字符是空格哦!把空格预读进去可是很重要的^_^
      看上去并不多,因为要考虑到内存占用及速度,我只预读了一些符号和五笔的一键字。这些字符在24号字时候已经占用了快1MB了,比起PixelFont字库占用的要大得多。天知道ID3DXFont到底预读了些什么……
      PreloadText()的第二个参数不要用strlen,sizeof(strPreloadText)即可。
      然后就是利用ID3DXSprite来渲染。注意ID3DXFont::DrawText的第一个参数就是LPD3DXSPRITE,因此如果要利用ID3DXSprite,要将ID3DXFont::DrawText放到ID3DXSprite::Begin和ID3DXSprite::End之间。这就是我刚才说的不直接用ID3DXSprite的意思,ID3DXFont会完成ID3DXSprite的全部调用,你不用担心。
      另外你应该注意到ID3DXSprite::Begin增加了参数,实际上DX文档里面没说,但是示例里面有,如果想让ID3DXSprite发挥作用并且最大幅度的提升效率,参数上设定D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE即可。意思很明白:打开Alpha过滤和纹理筛选。这里DX文档上有个错误一直没改:文档里给出的是D3DXSprite__SORT_TEXTURE,但是你可以试试,绝对报错。
      剩下的就没啥了,ID3DXFont的使用方法上一话已经讲过。要注意的是D3DXCreateFont和D3DXCreateFontIndirect都发生了变化。D3DXCreateFont已经不再牵扯GDI了,D3DXCreateFontIndirect所使用的结构也变成了D3DXFONT_DESC,相对于LOGFONT结构,除去了一些用不着的参数,增加了一个MipLevels,就是MipMap等级啦,不用多说,2D下只用1。其他的上一话都有。实际上由于D3DXCreateFont已经不再关联GDI,D3DXCreateFontIndirect的存在仅仅是由于历史原因(为了兼容像我这种人的使用习惯),大家还是用D3DXCreateFont吧,省事。
      截图就不贴了,没啥意义。你可能觉得直接向后备缓冲上DrawText还不够好看,那么就先画到一张纹理上,然后将纹理错位渲染到后备缓冲并且打开线型过滤,就可以达到和PixelFont相同的效果了。
      速度嘛……我画了整整一屏幕字,在不缓冲文字的情况下(这个“缓冲文字”和ID3DXFont的文字缓冲可不是一回事啊!看过上一话的都应该知道我这里指的是什么),速度仍然在120FPS以上。或许你会觉得速度还是有点慢,但是,如果用D3D8的ID3DXFont画上这么一屏幕,基本就只剩20FPS了。
      使用ID3DXFont替换掉PixelFont的优势就是可以方便的自定义字体字号了,并且也不再受GB2312字库的限制。所以大家都换了吧……都换了吧……把PixelFont忘了吧……

    『稳定的DX9 SDK版本』

      我现在用的是April 2006,而且应该会用很长时间。August 2006我是肯定不会去用啦!即使我不再恐惧D3D9,也会对这个SDK避让三分的。其实对于2D,我感觉用到April 2006就足够了,之后的DX9 SDK主要在D3DX的3D函数库部分进行更改……其实也是秋后的蚂蚱蹦达不了几天,D3D10马上就要出来了。要说D3D10啊……你还是看我另外一篇日志好了,总之打死我都不拿它做2D。

      实际上仅仅是2D的话,从D3D8转向D3D9并没有多少变化,主要是稳定嘛!只要你不调用一些D3D9专用的功能,即使拿D3D9来做2D,在绝大多数显卡上还是能够运行的。嗯……GF2等级以上吧,GF2之前的,也太老了,无视好了。

    《再上点菜好了:全屏幕模式》

      其实并不是多么复杂的问题,让我拖了这么久……不拖了,这里就教给大家如何做全屏幕模式以及如何处理设备丢失的问题。

    『创建全屏幕模式』

      D3DPRESENT_PARAMS里面,Windowed设定为false,并且一定要设定BackBufferWidth和BackBufferHeight,完毕。
      哈哈,就这么简单,或许早就有人尝试过了,但是你试试按下Alt+Tab,再切换回去,保证你什么都看不到。
      之前曾经说过,DX8之前的版本,在全屏幕下工作比在窗口下容易,到DX8之后就则完全颠倒过来。因为在窗口模式下不用担心设备丢失(除非你更改桌面分辨率),全屏幕模式下就会有这个问题了。下面详述:

    『设备、资源丢失』

      设备丢失会发生在全屏幕模式下切换回桌面时(不论是通过Alt+Tab还是QQ上有人给你发了张图片-_-bbb),而且如果在调用IDirect3DDevice9::Reset(从现在开始就是D3D9了啊!忘记D3D8吧……)的时候发生错误,设备也会丢失。
      设备丢失会造成资源丢失:所有创建在D3DPOOL_DEFAULT池的资源都会丢失,需要重新创建,其内容当然也会消失,需要重写。
      然而创建在D3DPOOL_SYSTEMMEM和D3DPOOL_SCRATCH池的资源不会受到影响。创建在D3DPOOL_MANAGED池的资源也不会丢失,而且在设备重新可用的时候,D3DPOOL_MANAGED池的资源也可以立即投入使用,内容也不会改变。看这个池名字:托管池就能知道,D3D帮你处理了所有问题。
      因此避免设备丢失后资源丢失的简易方法就是将所有资源创建在D3DPOOL_MANAGED池内。不过这并不是个好方法,这意味着不能用渲染对象——记得吗?RenderTarget只能创建在D3DPOOL_DEFAULT。实际上最好的方法是跟踪所有D3DPOOL_DEFAULT资源,比如利用std::list,将所有D3DPOOL_DEFAULT资源勾住,在设备发生丢失的时候释放掉资源,设备可以继续使用的时候重新创建资源,记得把数据写回去。对于其他的池就不用这么折腾了。

    『当设备丢失之后』

      不论通过任何方式发生了设备丢失,所有的操作几乎都会失效,只有Release()可以用——其实D3D会保证有部分操作可以成功,但是也仅仅是“可以”成功而不是“一定”成功,所以你还不如认定丢失的时候全都会失败比较好——以及IDirect3DDevice9::TestCooperativeLevel。因此在设备丢失之后,你应该停止整个游戏循环,而通过反复调用IDirect3DDevice9::TestCooperativeLevel判断设备是否可用。

    『IDirect3DDevice9::TestCooperativeLevel』

      这个方法检测当前的设备状态。返回值有四种:D3D_OK一切正常,D3DERR_DEVICELOST设备丢失,D3DERR_DEVICENOTRESET设备可以Reset。另外还有D3D9新增的D3DERR_DRIVERINTERNALERROR,遇到这个你就完蛋了,基本不可能恢复了,终止程序吧。
      按照顺序来讲,如果游戏在正常运行,D3D_OK会返回;如果发生了设备丢失并且在这个时候不能恢复,比如全屏幕模式的时候用户切换到了Windows桌面,就会返回D3DERR_DEVICELOST;如果用户又切换回了游戏,设备可以恢复了(还没恢复呢!只是“可以”恢复而已),就会返回D3DERR_DEVICENOTRESET。
      另外,IDirect3DDevice9::Present也会返回类似的值,不过你最好别指望这个,老老实实的用TestCooperativeLevel。因为Present在设备可以恢复的时候还是返回D3DERR_DEVICELOST(外一句:D3D10的时候TestCooperativeLevel就会完全整合到Present里面了,可喜可贺可喜可贺)

    『处理设备丢失』

      看下面的伪代码:

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

      GameLoop()就是你的游戏运行的过程了。把这个switch写在我们游戏框架的GameMain()部分,具体的位置可以看任何一话附带的源代码。
      好像我一直没有讲IDirect3DDevice9::Reset的参数啊?因为只有一个参数,就是指向D3DPRESENT_PARAMS的指针。把你第一次创建设备时使用的D3DPRESENT_PARAMS结构保存起来,供Reset来用。
      OnLostDevice()就是Release掉所有D3DPOOL_DEFAULT的资源,OnResetDevice()就是Create*()恢复啦!你可能注意到ID3DXFont、ID3DXSprite等等都有同名的方法,就是在这个时候调用的。如果你没有这么做,也就是说还保留着任何D3DPOOL_DEFAULT的资源的话,IDirect3DDevice9::Reset就一定会失败。
      另外在OnResetDevice里面你还要重新进行SetRenderState、SetSamplerState等等,Reset之后这些东西也丢失了。实际上Reset和重新创建一次设备类似,所不同的是重新创建设备的话你需要连D3DPOOL_MANAGED的资源也Release掉。这个话题就不讨论了。
      从代码可以看出来,D3DERR_DEVICELOST时程序什么都没做,只是在傻等。我认为这是一个好习惯,因为实在不能保证在D3DERR_DEVICELOST时除了Release还能干什么,与其这样还不如等设备能用了再说。

      实在懒得管资源的话,全部D3DPOOL_MANAGED好了。至于渲染对象?自己想办法。

    『人工制造“设备丢失”』

      “干嘛还要制造设备丢失啊?”如果更改游戏分辨率、色深、切换全屏幕及窗口状态,进行这样的操作也要通过Reset,同样的,Reset之前也要释放掉所有D3DPOOL_DEFAULT资源(其实严格来说,还有更多的资源也要释放,不过在2D下基本不会创建这类资源,你就不用管了)并且调用ID3DXSprite::OnLostDevice之类的方法。这就是人工制造“设备丢失”了。实际上在这个过程设备并没有真正的丢失,只是会有一段时间处于不可用的状态,此时Reset尚未返回,整个D3D设备就好像死了一样。举个例子,你切换桌面分辨率,会有那么一段时间显示器上什么都不显示,然后很快就正常了。和这个现象是同一个原因。Reset成功后记得恢复资源。
      你可能注意到这里的Reset和上面的Reset不是一回事。的确是这样,这里是为了重设状态而不是恢复设备。因此更改分辨率、色深的Reset需要写到switch外面,也就是别和它搅和的意思-_-bb。而且你只需要OnLostDevice -> Reset -> OnResetDevice。记住:正确的调用Reset不会造成设备丢失,这个概念别弄混了。

    『切换全屏幕模式时的注意事项』

      注意WindowStyle的变化。切换成全屏幕模式后,只能使用WS_POPUP,不然显示会变得怪怪的,你可以通过SetWindowLongPtr函数更改窗口外观,第二个参数指定GWL_STYLE即可。别忘了WS_VISIBLE啊!不然你什么都看不见。

    『更详细的文档』

      我这里只是简单讨论了造成设备丢失的原因及处理方法,更详细的内容你可以参考DX SDK文档的Lost Device文章,人家是权威的。

    【以上,正片结束,后面是ED】

      我们前进到了D3D9,赶上了时代。
      我们创建了全屏幕游戏,赶上了时代。
      我却变得一脑子浆糊,被观众抛弃了。
      哈哈,开玩笑啦,不过这一话很乱倒是真的,因为不论是更新到D3D9还是设备丢失,牵扯的东西都太散太杂,结果弄得这一话也是一盘散沙(居然又没有附带代码)。唉,大家就忍了吧,忍不了的话就来PIA我吧。

      关于更新至D3D9更多的内容,你可以参考SDK文档的《Converting to Direct3D 9》。

    【以上,ED结束,后面是……】

      第一季完结了……
      回过头来看看,从第一话创建一个Windows窗口,到这一话的设备丢失,话题的层次一直在深入,现在已经深入到了不再是“学习”而是“研究”的范围。我也不再想仅仅是搞“教学”而是想和大家“讨论”。不过第一季主要还是教学吧。能坚持着看D2D教程到现在的,应该基本能够写出完整的2D Demo来了吧。如果有什么问题的话,欢迎提出,我在看到后会立刻回答的……只要你这个问题不太RP的话……
      那么,第二季会是什么样子?
      第二季就不再是教学了,而开始我和大家的讨论过程。第二季的第一话,也就是第09话,我将提供一些高级技巧给大家,并希望有兴趣的朋友和我一起进行这些技巧的研究。另外在第二季里面,我们还要创建一个2D图形引擎。原来打算给大家讲解Medux 2,不过现在感觉这东西实在小儿科,绝对会让大家B4的。那么既然如此,干脆介绍Mercury 3好了,有意见无?
      透漏一点下一话的内容吧:模糊精度和多次纹理渲染,嘿嘿,听上去挺高深的是不?实际上超级简单,就看你能不能想到而已。
      希望你在看完这一话之后,返回去再把前面的内容看看,相信你会得到新的收获。搞不好你还能抓出几个Bug呢!因为我是想到什么写什么,没个章法,Bug是难免

    展开全文
  • D3D9学习笔记之颜色

    2019-09-13 13:06:23
    学习目标: 掌握 Direct3D 中颜色的描述方式 理解三角形单元的着色模式 颜色的表示: ...在 Direct3D 中,颜色用 RGB 三元组来表示...RGB数据可用两种不同的结构来保存,第一种是 D3DCOLOR,它实际上与 DWORD(un...

    学习目标:

    • 掌握 Direct3D 中颜色的描述方式
    • 理解三角形单元的着色模式

    颜色的表示:
    在 Direct3D 中,颜色用 RGB 三元组来表示。将颜色分解为红色(Red),绿色(Green),蓝色(Blue),这三个分量的加性混合决定了最终的颜色。我们可用该三个分量的不同组合来表示上百万种颜色。
    RGB数据可用两种不同的结构来保存
    第一种是结构是 D3DCOLOR,它实际上与 DWORD(unsigned long )类型完全相同,共32位。D3DCOLOR类型中的各位被分成4个8位项,每项存储了一种颜色分量的亮度值。
    分配顺序从左至右是 8位给Aloha——8位给红色——8位给绿色——8位给蓝色。
    由于每种颜色的分量均占用一个字节,所以每个分量的亮度值范围在0-255区间内,接近0的值表示亮度低,接近255的值表示亮度高。
    占用:关于 Alpha分量暂时不理解,以后再做补充。

    颜色宏:

    #define D3DCOLOR_XRGB(r,g,b)	D3DCOLOR_ARGB(0xff,r,g,b)
    

    要指定每个颜色分量的值,并将其插入到 D3DCOLOR 类型的恰当位置上,需要借助位运算。Direct3D 提供了 D3DCOLOR_ARGB 宏帮助我们完成这样的工作。该宏中,前3个参数分别对应3种颜色分量,第4个参数对应 Alpha分量,每个参数必须在0-255区间取值,其调用方法如下:

    D3DCOLOR brightRed = D3DCOLOR_ARGB(255,255,0,0);
    D3DCOLOR someColor = D3DCOLOR_ARGB(255,144,87,201);
    

    也可以用宏 D3DCOLOR_XRGB 来代替 D3DCOLOR_ARGB,二者很相似,前者总是将 Alpha参数设为255,所以前者不接受 Alpha 参数,调用方法如下:

    D3DCOLOR xrgb = D3DCOLOR_XRGB(255,255,10);
    

    第二种结构是 D3DCOLORVALUE 在该结构中,用单精度浮点型数来度量每个颜色的亮度值,亮度值的取值范围为0~1,0表示没有亮度,1表示最大亮度。
    我们可以用结构 D3DXCOLOR 代替 D3DCOLORVALUE,前者不但包含了与后者相同的数据成员,而且还提供了一组有用的构造函数和重载运算符,为颜色的运算提供了便利。此外,因为这两种结构所包含的数据成员相同,所以这两种结构可以相互转换。
    提示:D3DCOLORVALUE 和 D3DXCOLOR 结构都有4个浮点型成员,这样可以将颜色表达成一个4D向量,标记为(r,g,b,a)。颜色向量的加法,减法以及比例运算与常规的向量完全相同,而颜色向量的点积和叉积没有实际意义,但是对应分量相乘确是有意义的。所以在类 D3DXCOLOR 中,颜色的乘法定义为对应分量分别相乘。

    顶点颜色:
    图元的颜色由构成该图元的顶点颜色所决定。所以,我们必须为顶点数据结构添加一个表示颜色的数据成员。注意,此处无法使用 D3DCOLORVALUE 结构,因为 Direct3D 希望用一个32位的值来描述顶点的颜色。

    struct ColorVertex{
    	float x,y,z;						//3D顶点
    	D3DCOLOR color;						//颜色
    	static const DWORD FVF;				//自定义顶点结构类型
    }
    const DWORD ColorVertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;			//初始化顶点结构构型成员
    

    着色:
    在光栅化过程中,需要对多边形进行着色。着色规定了如何利用顶点的颜色来计算构成图元的像素颜色。
    两种着色模式:平面着色 和 平滑着色
    平面着色:每个图元的每个像素都被一致的赋予该图元的第一个顶点所指定的颜色。所以,由3个顶点构成的三角形将是红色的,原因是第一个顶点是红色的。使用平面着色模式时,第二个和第三个顶点的颜色都将被忽略。
    平面着色容易使物体出现块状,这是因为各颜色之间没有平滑的过渡。一种更好的着色模式是 Gouraud着色,也称平滑着色,在平滑着色模式下,图元中各像素的颜色值由各顶点的颜色经线性插值得到。
    着色模式由 Direct3D 的状态机控制

    //设置为平面着色模式,三角形单元的颜色由第一个顶点决定
    Device->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_FLAT);
    //设置为平滑着色模式,线性插值着色
    Device->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_GOURAUD);
    

    在着色模式下应将灯光关闭,因为你没有设置灯光,如果有可以忽略

    device->SetRenderState(D3DRS_LIGHTING, false);//true为开,false为关
    
    展开全文
  • 这里叙述融合技术的作用及原理,待写。。。 学习目标: 理解融合原理以及如何运用融合技术 了解 Direct3D 支持的各种融合模式 理解如何用 Alpha 分量控制图元的透明度 ...
  • D3D9中设备提交的实现细节,包括全屏,窗口模式始终的注意细节等,有些设置不当回极大的影响程序性能,特别是swap effect的设置。
  • D3D中截图方法

    千次阅读 2010-05-04 18:35:00
    在渲染完所有东西后,Present之前获得BackBuffer表面然后用D3DX的函数保存void ScreenShot (char *filename){ IDirect3DSurface9... //生成固定颜色模式的离屏表面(Width和 Height为屏幕或窗口的宽高) D3D9De
  • Future 模式

    2019-03-24 17:31:55
    Future 模式说白了就是异步执行任务,同步获取结果,当然也可以升级为异步执行任务,任务执行完成后执行回调操作。 文章地址: ...mid=2247483818&...sn=c2d9f6ef447d3affc40e394ea4c8bdb8&chksm=fc103...
  • 这是一个可在D3D9画面内显示ime输入法窗口的演示程序,目前支持搜狗拼音及QQ拼音,你可以在此程序基础上继续扩展支持的输入法。打开demo后在按alt+enter可切换全屏,画面中间有输入框可测试效果。
  • 声明:此文章翻译自DirectX 9.0C OCT 2006 SDK的Direct3D For C++帮助文档的Enabling Direct3D Debug Information主题,前面部分有些没有翻译的。 在#include <D3D9.h>语句前面加上以下这条语句即可...
  • 转 - dx8和dx9的差异

    2019-07-24 14:58:05
    由于Aug 8造成的D3D9恐惧症已经完全消除了,这一章将会给大家介绍将3D引擎转向D3D9的各个方面,包括终于出现的全屏幕模式。从这章以后,我将使用D3D9作为讲解的语言继续D2D教程。【OP结束,开始正片】『Why?』 ...
  • win7上帝模式

    2014-05-24 18:04:44
    mht.{3050F3D9-98B5-11CF-BB82-00AA00BDCE0B} mshta.{3050f4d8-98B5-11CF-BB82-00AA00BDCE0B} 我的文档.{450D8FBA-AD25-11D0-98A8-0800361B1103} XML.{48123bc4-99d9-11d1-a6b3-00c04fd91555} 回收站(满).{5ef4...
  • 【转】数据依赖与关系模式规范化

    千次阅读 2010-01-13 02:00:00
    http://online.hhu.edu.cn/jpkc/POD/N3/%BD%B2%CA%DA%CC%E1%B8%D9/LO-C10-%CA%FD%BE%DD%D2%C0%C0%B5%D3%EB%B9%D8%CF%B5%C4%A3%CA%BD%B9%E6%B7%B6%BB%AF.htm 10.1 关系设计方法学概述
  • 音频分析仪 这是我的一个非常古老的项目(我在高中时就开始进行这项工作)。 该应用程序从Direct Sound Capture来源捕获音频数据,对其进行英尺处理以及一些后... 仍然可以在Windows 10上使用D3D9在64位模式下运行:)
  • 游戏模式要求应用程序调用ParsecHostSubmitFrame函数之一(支持OpenGL,D3D9和D3D11)和ParsecHostSubmitAudio 。 通过ParsecHostPollInput轮询输入,从而像暴露在本地一样暴露输入事件。 在游戏模式下,Parsec只能...
  • cegui告捷

    千次阅读 2009-02-26 21:04:00
    忙活了3天时间,瞅了一遍cegui,...本来这个问题不该出现的,但是我刚开始在debug模式编译debug的lib库,出现了“没有d3dx9d_37.dll”的提示,变态的d3d9居然后面跟个37,害得我偷懒用了release模式的库,最终导致了
  • VMR9实现放大缩小

    2021-02-15 12:47:38
    编者:李国帅 qq:9611153 微信lgs9611153 时间:2012/05/03 若使用vmr9,测试了一下,需要使用...d3d9.h> #include <streams.h> #include <strmif.h> #include <control.h> #include <..
  • Unity客户端笔试题

    2015-05-12 18:03:17
    3.画出D3D9可编程渲染管线渲染流程示意图? 4.String/StringBuilder 区别? 5.说static,const,virtual,abstract,override,这几个关键字在C#中是什么意思? 6.写出三种设计模式,并说说在哪些情况下适用
  • DX9教程一

    千次阅读 2006-01-01 03:35:00
    #pragma comment(lib,"d3d9.lib") //---------------------------------------------------------------------------- //定义为全屏模式 //----------------------------------------------------
  • e374 63 d9 a8 38 3b d3 e6 4c 8c 23 34 4e 20 51 93 5e 6d b4 7a 22 9b 4c f2 d3 e38c c4 f8 3 6f 47 40 f4 f8 45 9b 83 f3 83 6 31 d0 0 17 82 83 dc 67 f9 62 77 e3a5 90 3b d9 ec f3 55 96 b8 d9 db 79 55 f1 ...
  • appId:'D3D9B9AA45B56F6E424F57EFB36B0XXX', } }) import { Performance, axiosReport, defaultReport, fetchReport, jqueryReport, noneReport } from 'web-report' // 使用 defaultReport({ domain:'...
  • 欢迎进入命令模式,你可以输入"help"命令获取帮助 > 2020-06-03 10:50:41.120 I MediaServer[3429] main.cpp:331 start_main | 已启动http api 接口 2020-06-03 10:50:41.120 I MediaServer[3429]...
  • KKcapture v2.1.8 免费VIP版,亲测 可用

    热门讨论 2012-02-20 00:46:09
    * 解决使用d3d9的游戏使用软件时崩溃的问题 * 解决偶尔弹出对话框报网络问题,录制功能无法使用的问题。 KKcapture v1.0.3 TOP↑ * 解决部分游戏无法显示帧率的问题。 * 解决弹出对话框报网络问题,录制功能...
  • 30天成为软文高手 完整版

    热门讨论 2012-03-07 17:23:27
    第二部分课程10分册:软文模式 B1 《观点软件》 B2 《问题软文》 B3 《事件软文》 B4 《名家软文》 B5 《热门软文》 B6 《通讯软文》 B7 《技巧软文》 B8 《研究软文》 B9 《数据软文》 B10 《其它各类...

空空如也

空空如也

1 2 3
收藏数 44
精华内容 17
关键字:

d3d9模式