2.1 |格蒙皮信息Q?/font>首先Q在Mesh{}单元中,在原有的普通网格顶Ҏ据基上,新增了XSkinMeshHeader{}l构Q以及多个SkinWeights{}l构。用以描q各个骨骼的蒙皮信息?/p>
其中QXSkinMeshHeader是LQD一实例Q如下:
XSkinMeshHeader { 2,//一个顶点可以受到骨骼媄响的最大骨骼数,可用于计共同作用时减少遍历ơ数 4,//一个三角面可以受到骨骼影响的最大骨骼数。这个数字对g点混合计算提出了基本要求?br>35 //当前Mesh的骨骼L?br>}
׃每个骨骼的蒙皮信息都需要用SkinWeightsl构Lqͼ所以有多少块骨|在Mesh中就有多个SkinWeights对象?br>注意Q一般把SkinWeights视作Mesh的一部分。这UMesh又称Skinned Mesh (蒙皮|格)
SkinWeights l构如下Q?br>{ STRING transformNodeName; //骨骼?br> DWORD nWeights; //权重数组的元素个敎ͼ卌骨骼相关的顶点个?br> array DWORD vertexIndices[nWeights];//受该骨骼控制的顶点烦引,实际上定义了该骨骼的蒙皮 array float weights[nWeights]; //蒙皮各顶点的受本骨骼影响的权?br> Matrix4x4 matrixOffset; //骨骼偏移矩阵Q用来从初始Mesh坐标Q反向计顶点在子骨骼坐标系中的初始坐标?br>} 在有的书中,把上面的matrixOffset叫骨骼权重矩阵,是不恰当的。应该称为骨骼偏Uȝ阉|较合适?/p>
[问题] 在整个动画过E中Q子骨骼q动矩阵的数值是不断变化的。上面的骨骼偏移矩阵变化吗?有没有必要重新计?它在什么时候用? {:各骨骼的偏移矩阵matrixOffset专门用来从原始Mesh数据计算出各点相对于骨骼坐标系的原始坐标。在l制前,把它与当前变换矩늛乘,可以得到该骨骼的当前的最l变换矩c?MQ骨骼偏Uȝ阉|与原始Mesh点数值相兌的,在整个动画过E中是不变的Q也不应该变。在动画q程中变化是当前骨骼变换矩阵Q可?X中的AnimatonKey中的各时ȝ阵得到。这个矩阵乘法在CZ中的对应代码如下Q?br>D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
卻ID3DXMatrixMultiply(输出最l世界矩? 该骨骼的偏移矩阵, 该骨骼的变换矩阵)
2.2 骨骼层次信息
在X文g中,Frame是基本的l成单元。又U框架Frame?一?x可以有多个Frame?注意此处的Frame不是帧,与没什么关p?
框架Frame允许嵌套Q这样就存在父子框架了。而ƈ列的框架Q称为兄弟框架。这两种关系l合在一P卛_以纵深,又可以ƈ列,形成一U层ơ结构。这U结构,可用二叉树描q?/p>
每个框架l构的最前面Q有一个FrameTransformMatrix矩阵数据Q描qC该框架相对于父框架的变换矩阵。也是_该框架中的坐标,与该矩阵怹Q可转换为父框架坐标pȝ坐标?br>q种层次l构Q得X文g能描q许多复杂的物体。如地Ş场景?/p>
在骨骼动L件中Q框架结构可直接拿来描述人物骨骼的层ơ结构。框架的名字通常为对应的骨骼名?br>?#8220;左上?>左前?>手掌->手指”Ş成一个父子骨骼链。而左上臂与右上臂是ƈ行关pR?/p>
数据CZQ?D:\D9XSDK\Samples\Media\tiny.x
Frame ...{ .....
Frame Bip01_R_Calf { //子骨?br> FrameTransformMatrix { 1.000000,-0.000691,-0.000000,0.000000,0.000691,1.000000,-0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,119.231522,0.000021,-0.000011,1.000000;; }
Frame Bip01_R_Foot {//--孙子骨骼 FrameTransformMatrix { 0.988831,0.124156,0.082452,0.000000,-0.122246,0.992109,-0.027835,0.000000,-0.085257,0.017445,0.996206,0.000000,119.231476,-0.000039,0.000023,1.000000;; }
....~进 } }
[问题] 查看CZtiny.x文gQ发现只有根框架下有一个MeshQ包含了所有顶点信息。其它各个Frame都没有Mesh数据。怎么理解Q?br>{: 一般来_每个动画文g只有一个Mesh|格Q包含物体所有顶点信息?br> 其它FrameQ只是借用来描q各骨骼的层ơ信?没必要再定义骨骼|格。每块骨骼对应的蒙皮点信息Q由根Mesh中的相应骨骼的SkinWeights中蒙皮顶点烦引描q的。在动画q程中,各个点的新坐标Q要借助SkinWeights中的点索引来进行重新计?/p>
2.3 动画信息Q?/font> ׃pdAnimatonKeyl成Q数据示例如下:
AnimationKey { 4;--动画cd 4表示矩阵 62; --动画帧数Q即下面矩阵个数 0;16;1.000000,-0.000691,-0.000000,0.000000,0.000691,1.000000,0.000000,0.000000,0.000000,-0.000000,1.000000,0.000000,119.231514,-0.000005,0.000001,1.000000;;, 80;16;0.992696,-0.120646,-0.000000,0.000000,0.120646,0.992696,0.000000,0.000000,-0.000000,-0.000000,1.000000,0.000000,119.231514,0.000002,-0.000002,1.000000;;,
..上面U数字表C时刻tick,兰数字表C数值的个数?br> ...其它各时ȝ?..
{ Bip01_R_Calf }--对应的骨骼对象引?br> }
注意Q?br>(1)每块骨骼都有一个AnimationKey{}. (2)在上面数据结构中Q主要保存了各典型时ȝ该骨骼相对于父的变换矩阵. (3)?时刻的矩阵,与该骨骼对应的前面的Frame所对应的矩阉|相同的。如Frame Bip01_R_Calf{}中的变换矩阵Q与Bip01_R_Calf所对应的AnimationKey 的第0时刻矩阵是一L。这说明Q在以后动画q行ӞDX会提供一U功能,用AnimatonKey中的对应数据h初始的变换矩?也可能启用关键插值算?。这个功能对应于CZ中的m_pAnimController->SetTime(...)语句?/p>
?怎样从X文g加蝲骨骼动画信息Q?/strong>3.1 负责加蝲的函敎ͼ 可能有多U加载方式,在此以SDK中的CZ为准Q叙qCU标准加载方式,需要用到DX函数D3DXLoadMeshHierarchyFromX(),函数字面意思是dMesh层次信息?br>HRESULT WINAPI D3DXLoadMeshHierarchyFromX( LPCSTR Filename, //.x文g?br> DWORD MeshOptions, //Mesh选项Q一般选D3DXMESH_MANAGED LPDIRECT3DDEVICE9 pD3DDevice, //指向D3D讑֤Device LPD3DXALLOCATEHIERARCHY pAlloc, //自定义数据容?/strong> LPD3DXLOADUSERDATA pUserDataLoader, //一般选NULL LPD3DXFRAME *ppFrameHierarchy, //q回根Frame指针Q指向代表整个骨架的Frame层次l构 LPD3DXANIMATIONCONTROLLER *ppAnimController //q回相应的动L制器 );
q个函数后面的两个输出参数很重要Q也很好理解Q但输入参数中的自定义数据容器是怎么回事呢? 原来Q鉴于动L据的复杂性,需要你配合完成加蝲q程。比如你是否用到自定义扩展结构,Mesh{数据保存在哪里Q怎样使用戯己创建容器,自己军_卸蝲{等? DX提供了ID3DXALLOCATEHIERARCHY接口Q提供了q个自定义的ZQ你重蝲q个接口的虚函数Q在加蝲q程中,它就像回调函数那栯作?/p>
你需要像下面q样建立一个自定义数据容器c: class CAllocateHierarchy: public ID3DXAllocateHierarchy { public: STDMETHOD(CreateFrame)(THIS_ LPCTSTR Name, LPD3DXFRAME *ppNewFrame); STDMETHOD(CreateMeshContainer)(THIS_ LPCTSTR Name, LPD3DXMESHDATA pMeshData, LPD3DXMATERIAL pMaterials, LPD3DXEFFECTINSTANCE pEffectInstances, DWORD NumMaterials, DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer); STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree); STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER pMeshContainerBase); CAllocateHierarchy(CMyD3DApplication *pApp) :m_pApp(pApp) {} public: CMyD3DApplication* m_pApp; };
[问题] 上面的STDMETHOD是什么意思? {:相当于virtual HRESULT __stdcall 的宏?lt;评论> 因ؓq种c要与D3D的COM接口打交道,不仅仅在C++内部使用Q所以,所有类Ҏ必须做成stdcall的,可对外开攄?br>#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method #define STDMETHODCALLTYPE __stdcall q样当写一个函数STDMETHOD(op1(int i)) 展开后成为: virtual HRESULT __stdcall op1(int i);
3.2 自定义数据容器以及具体的dq程: Ҏ.X文gQ在加蝲q程中,主要有两斚w数据需要保存,一个是骨架Frame信息Q一个是|格蒙皮Mesh信息。这两个信息保存在如下结构中?/p>
框架信息(对应于骨? typedef struct _D3DXFRAME { LPSTR Name; D3DXMATRIX TransformationMatrix; //本骨骼的转换矩阵
LPD3DXMESHCONTAINER pMeshContainer; //本骨骼所对应Mesh数据
struct _D3DXFRAME *pFrameSibling; //兄弟骨骼 struct _D3DXFRAME *pFrameFirstChild; //子骨?br>} D3DXFRAME, *LPD3DXFRAME;
自定义数据容?其数据来源由上面接口的CreateMeshContainer()函数提供 typedef struct _D3DXMESHCONTAINER { LPSTR Name; //容器?br> D3DXMESHDATA MeshData; //Mesh数据,可创建SkinMesh取代q个Mesh LPD3DXMATERIAL pMaterials; //材质数组 LPD3DXEFFECTINSTANCE pEffects; DWORD NumMaterials;//材质?br> DWORD* pAdjacency; //L三角形数l?br> LPD3DXSKININFO pSkinInfo; //蒙皮信息,其中?x中的各个skinweight蒙皮点索引及各骨骼偏移矩阵{?br> struct _D3DXMESHCONTAINER *pNextMeshContainer; } D3DXMESHCONTAINER, *LPD3DXMESHCONTAINER;
[评论] .在动L件中Q框枉常用来描述骨骼。可以把Frame视做骨骼Q所以不l加区分?br>.在上面D3DXFRAMEl构?pFrameSibling, pFrameFirstChild两个指针Q常用于递归函数中,遍历整个骨架?br>.在D3DXFRAMEl构中有一个pMeshContainer指针Q难道框架与Mesh是一一对应的吗Q?br>有一个框?骨骼)有一个Mesh吗?怎么.X文g中只有一个Mesh?N加蝲时拆开存放? {?从D3DXFramel构上看Q每个Frame都有一个pMeshContainer指针。这有三种解释Q?br> W一U,加蝲到内存后所有的pMeshContainer都指向同一个全局Mesh W二U,加蝲到内存后Q只有一个主框架的pMeshContainer不ؓI,其它Frame的pMeshContainer均ؓNULLQ因为在.X中,它们没有定义自己的Mesh W三U,加蝲到内存后QD3DMesh拆分Q分开到各骨骼所对应的FrameQ每个Frame都有自己的Mesh?br> q个问题我以前也不是很清楚,通过查看CZ源码及跟t发玎ͼ正确解释应该是第2U。唯一的一个全局Mesh存放在Frame "body"下的无名Frame中。而其它Frame׃没有自己专门的Mesh而指向NULL. 应该大致如此。这个问题之所以让人困l,是因Z后箋代码上看Q在渲染DrawFrameӞ是遍历每一个frame分别l制它们对应的Mesh. 如果对应于同一个meshQ就l制多遍。如果对应各自meshQ那么变换矩阉|么l织q算{等。所以,ҎW二U解释,׃只有一个pMeshContainer不ؓNULLQ所以参与绘制及蒙皮的只有这一个MeshContainerQh体所有顶Ҏ据及蒙皮信息都在q个mesh中?br>所以,dtiny.x文g后,会生多个D3DXFRAME对象Q但只有一个D3DXMESHCONTAINER对象?/p>
在示例代码的CMyD3DApplication::InitDeviceObjects()中,? hr = D3DXLoadMeshHierarchyFromX(strMeshPath, D3DXMESH_MANAGED, m_pd3dDevice, &Alloc, NULL, &m_pFrameRoot, &m_pAnimController); if (FAILED(hr)) return hr; 其中的Alloc是就自定义的数据容器对象。m_pFrameRoot是根骨骼Q对遍历很重要。m_pAnimController是动L制器Q对h矩阵很重要?/p>
你在q行完这句话后,下一个断点,观察m_pFrameRootQ会发现如下内容Q?/p>
m_pFrameRoot 0x00c59380 {Name=0x00c53630 "Scene_Root" .....} //Ҏ?br>pMeshContainer 0x00000000 pFrameSibling 0x00000000 pFrameFirstChild 0x00c59428 {Name=0x00c53ca8 "body" pMeshContainer=0x00000000...}//子框?骨骼body +--- pMeshContainer 0x00000000 +--- pFrameSibling 0x01419f00 {Name=0x00c5ffd8 "Box01" pMeshContainer=0x00000000 ...}//兄弟框架 +--- pFrameFirstChild 0x00c594d0 {Name=0x00000000 pMeshContainer=0x00c59828 //子框?--该框架就?x中含有唯一全局Mesh的无名框?/p>
可见,在内存中的Frame布局是与.x中一一对应的。除了pFrameFirstChild 0x00c594d0q个地方的Frame中的pMeshContainer不ؓI,其它框架的这个mesh指针都是I倹{?br>另外一点可以看出,q不是每个Frame都对׃块骨|有的是别的用途。也是说Frame对象的个数可能多于骨骼数?/p>
3.3 分析CAllocateHierarchyc?/font> 下面l箋研究自定义数据容器CAllocateHierarchyQ顾名思义Q该cL在加载过E中自行分配层次数据I间。它?个成员,都是重蝲D3D的接口虚函数?br>它的成员CreateFrame()是用来创建D3DXFrame对象的,而CreateMeshContainer()是用来创建Mesh数据对象的。你可以在这两个函数中下断点Q发现CreateFrame会运行多ơ,而CreateMeshContainer只运行一ơ,再次验证了上面的说法?/p>
值得注意的是Q示例对上面的D3DXFRAMEQD3DXMESHCONTAINER两个l构做了扩展Q分别代之以D3DXFRAME_DERIVEDl构和D3DXMESHCONTAINER_DERIVEDl构Q以集中存储数据方便E序处理?/p>
CreateFrame()处理比较单,你只是new一个Frame对象I间Q填入传q来的NameQ其它内容由DX负责l护填充?/p>
CreateMeshContainer()较ؓ复杂。它的Q务一是保存传入的|格数据数据Q二是根据这些数据及蒙皮信息调用GenerateSkinnedMesh()函数生成蒙皮|格。只有这个新的BlendMesh才能在Render()时支持顶Ҏ合,完成蒙皮的显C。在D3DXMESHCONTAINER_DERIVEDl构中,用pOrigMesh保存旧的Mesh普通网g息。而Meshdata.Mesh则指向新产生的BlendMesh
在这个函CQ多ơ用CAddRef() Q对COM不熟悉的新手Ҏ困惑。D3D是COMlgQ它在服务进E中q行Q而不在当前的客户q程中。在DXlgq行q程中,要创Zpd接口对象Q如CreateDevice()q回接口指针Q这些接口及其占用内存什么时候释放,要通过“引用计数”的技术来解决。AddRef()l这个接口指针的计数?Q而Release()会将之减1。一旦减?Q表C没有客户用了Q相关的接口释放了?由此可知Q每ơ调用Rlease()后,q不一定会释放内存Q而是当引用计数归0旉攑ֆ存?br>q样Q对接口指针的用,像l护堆栈的^衡一P要仔l,而且按照某种U定规则使用?/p>
但^时D3D~程中,怎么不用AddRef()呢?q是׃一个接口指针,如ID3DDeviceQ或VertexBuf指针Q都是D3DXCreate出来?在Create时候,在内部已l事先AddRef()了,你就不需要再做这工作了。只要你在不用时Q调?p指针->Relase()释放了。一般编E,特别是小型示例程序,都是初始化时建立一ơ,关闭旉放,都遵守了q种U定Q所以不存在q种问题?/p>
但在CreateMeshContainer()函数中,以多U方式用了指针Q在局部指针变量中来回传递,所以问题复杂化了。在COM~程中约定,M时候地接口指针赋?复制)Q都要AddRef()Q在指针变量l束生命期前Q再Release(). 但许多程序员都不是严D么做。因为在局部变量用完就废了Q先AddRef()增加计数再Release()减少Q和直接使用最后是{效的。几乎是多此一举。这与编E习惯有关系。一旦引用计C对,如果没有l一的习惯,不好排查。在CreateMeshContainer()中,Ҏ口指针的使用有三U方式,例D如下Q?/p>
方式一Q不使用AddRef()。和普通指针一P临时变量是左|接口指针是右|直接赋g用。如: pMesh = pMeshData->pMesh; q是׃pMesh是局部变量,它只是时引用一下,没必要ؓ它先AddRef()Q后Release()?/p>
方式二:隐式的用AddRef()?׃用到了一些内部有AddRef()动作的函敎ͼp按照COMU定Q在子程序结束前Release() pMesh->GetDevice(&pd3dDevice);//此处d3d讑֤引用计数已经? .... SAFE_RELEASE(pd3dDevice);//--此处引用计数减1Qƈ不是真的释放d3d讑֤ 在本例中Qpd3dDevice在GetDevice()中已lAddref()q了Q所以,在退出CreateMeshContainer()前,必须pd3dDevice->Release()
方式三:昑ּ的用AddRef()?如果一个指针|不是由D3DXCreate出来的,而是通过赋值方式复制给一个全局变量或长期变量的?所以,可以通过AddRef()的方式来延迟该对象的释放 。因为,如果不AddRef()Q极有可能在函数q回该对象就可能释放了。它像一个加油站Q得传入对象的寿命廉臌己控制范围内。用了AddRef()Q就要在相关的Destroy中添加Release()?/p>
在本函数Q有三处q样的语句: pMeshContainer->MeshData.pMesh = pMesh; pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; pMesh->AddRef(); .... pMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef();
pMeshContainer->pOrigMesh = pMesh; pMesh->AddRef(); ....
来在DestroyMeshContainer()中,要释放这些指针: .... SAFE_RELEASE( pMeshContainer->MeshData.pMesh ); SAFE_RELEASE( pMeshContainer->pSkinInfo ); SAFE_RELEASE( pMeshContainer->pOrigMesh );
׃q些指针值的创徏、更改等都是用户自己l营的,所以务必要加前后吻合,在CreateMeshContainer()中AddRef()Q在DestroyMeshContainer()中Release().
再来看数据的保存部分?br>在CreateMeshContainer()的传入参CQ有pMeshData,pMaterials,pEffectInstances,NumMaterials,pAdjacency,pSkinInfo 你需要把q些数据保存到自qD3DXMESHCONTAINER对象中。ƈ且其中的所有数l所需的空间都要在全局堆中new出来。所以在该代码中Q有如下new: pMeshContainer = new D3DXMESHCONTAINER_DERIVED;//自定义的扩展数据容器对象 memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED));//初始化pMeshContainer,? ... pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials];//准备保存材质 pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];//准备创徏U理对象。它声明在扩展部分?br>pMeshContainer->pAdjacency = new DWORD[NumFaces*3];//准备保存L三角形数l?NumFaces = pMesh->GetNumFaces();
然后Q对数据q行memcpy保存。pEffectInstances׃在绘制中不需要,q没q行保存。对于没有脓囄赋以默认材质属性?br>值得注意的是Q所有这些newQ必dDestroyMeshContainer()时进行delete.
接下来的处理中,如果发现Mesh的FVF中没有法向量Q要用CloneMeshFVF()重徏MeshQ计顶点^均法向量。以备光照处理?/p>
最后,我们看看蒙皮信息pSkinInfo的处理。这是重头戏?br>如果发现pSkinInfo!=NULLQ就准备着手从各个蒙皮骨骼信息创徏SkinMesh. 首先Q用扩展容器l构D3DXMESHCONTAINER_DERIVED中的各属性保存原Mesh指针|pMeshContainer->pOrigMesh = pMesh, 因ؓ接下来我们要创徏SkinMesh替代原Mesh.然后Q把SkinInfo中的各骨骼的偏移矩阵保存到pMeshContainer->pBoneOffsetMatrices?br> cBones = pSkinInfo->GetNumBones(); pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones]; ..... 每个“骨骼偏移矩阵”pBoneOffsetMatrices,在将来DrawMeshContainer()中是必须要用的。因为原始Mesh中的点数据乘以“骨骼偏移矩阵”Q再乘以“变换矩阵”Q才能求得各骨骼点在世界坐标系中的坐标?卻I 骨骼上各点在世界坐标pM的新坐标=初始|格中的各点坐标*骨骼偏移矩阵*骨骼当前的变换矩?br> 其中Q?#8220;初始|格中的各点坐标*骨骼偏移矩阵” = 骨骼上各点初始时d该骨骼坐标系中的局部坐?/p>
做了以上工作后,调用GenerateSkinnedMesh(pMeshContainer)Q创建SkinMesh. 接下来,我们看看GenerateSkinnedMesh()做了哪些工作?/p>
3.4 怎样生成蒙皮|格SkinMesh? GenerateSkinnedMesh()分析
׃要重定义pMeshContainer->MeshData.pMeshQ所以先SAFE_RELEASE( pMeshContainer->MeshData.pMesh ); 释放原pMesh
在这个函CQ是Ҏ当前l图方式讄q行加蝲数据的。因为顶Ҏ合,有无索引的顶Ҏ合,有含索引的顶Ҏ合,所使用的函数和对应的SkinMesh数据内容也有所不同?br>在示例中Q自定义了枚举m_SkinningMethodQ主要分为D3DNONINDEXED和D3DINDEXEDQ以有纯软g渲染{。运行示例后Q你可以选择菜单中的Options选择不同的渲染方式?/p>
我们着重分析一下带索引的蒙皮网根{在E序中,是D3DINDEXED相关的部分?br>if (m_SkinningMethod == D3DINDEXED){ ....}
注意! CZ默认工作在D3DNONINDEXED?如果要跟tD3DINDEXED部分的代?必须选择菜单中的Options选择indexed!
最主要的,要通过DX的ConvertToIndexedBlendedMesh()函数Q生成支?#8220;索引点混合”的SkinMesh.有关索引点混合的技术,你可以在DXSDK帮助文g中搜?#8220;Indexed Vertex Blending”主题Q对着英文和插囑ְqQ确有收莗?/p>
要想用硬件对点q行混合Q那么参与合者不能太多。也是说同时媄响一个顶点的骨骼C能多。我们假定一个顶Ҏ多同时受4个骨骼的影响Q也是同时最多有4个骨骼矩阵参与加权求和)Q那么同时媄响一个三角Ş面的骨骼数最多就?*4=12个?br>我们用NumMaxFaceInfl表示影响一个三角面的最多骨骼矩阉|Q那么,通过调用pSkinInfo->GetMaxFaceInfluences()获取q个数|一般也?-4。如果这个数值太大,我们强制使用NumMaxFaceInfl = min(NumMaxFaceInfl, 12);来最多取?2?/p>
用NumMaxFaceInfl q个数值干什么呢Q?我们用来它分析当前的昑֍倒底行不行?/p>
if (m_d3dCaps.MaxVertexBlendMatrixIndex + 1 < NumMaxFaceInfl)//如果昑֍达不到该要求 { //很奇怪?005q底买的GeForce 6600GT昑֍Q竟然m_d3dCaps.MaxVertexBlendMatrixIndex=0, 不支持烦引顶Ҏ合!是驱动问题还是怎么了? //但它支持非烦引合。或者,也许要用HLSL支持混合。看hQ?D~程要多考虑?br> .. pMeshContainer->UseSoftwareVP = true;//用Y件渲染顶炏V显然不实用?br>} else { pMeshContainer->NumPaletteEntries = min( ( m_d3dCaps.MaxVertexBlendMatrixIndex + 1 ) / 2, pMeshContainer->pSkinInfo->GetNumBones() );//--什么意思? pMeshContainer->UseSoftwareVP = false;//采用g点混合?br> Flags |= D3DXMESH_MANAGED; }
[评论] 在上面有一行代? pMeshContainer->NumPaletteEntries = min( ( m_d3dCaps.MaxVertexBlendMatrixIndex + 1 ) / 2,pMeshContainer->pSkinInfo->GetNumBones() ); 管作者加了大D|释,q是让h一头雾水。其实,我们做一个实验,反尔更能理解它的用途?br>W一步,你在q句话后面下一个断点,看一下在你机器上q个数倹{我的ATI 9550昑֍机器上是19。比tiny.x中的骨骼?5很多?br>W二步,你将上面=双瞎填一个大?的数字,比如6。编译后照样q行。而且效果上几乎看不出M差别?br>Z么会q样呢? 我们在绘制代码部分,看看q个数Dv什么作用?br>在DrawMeshContainer()代码中,我们查找D3DINDEXED相关的部分。在mesh各子集的DrawSubset()之前Q有如下代码Q?br> for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++) { // first calculate all the world matrices for (iPaletteEntry = 0; iPaletteEntry < pMeshContainer->NumPaletteEntries; ++iPaletteEntry) { iMatrixIndex = pBoneComb[iAttrib].BoneId[iPaletteEntry]; if (iMatrixIndex != UINT_MAX) { D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] ); m_pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( iPaletteEntry ), &matTemp ); } } ... } 下面仔细评估一下这些代? 先注意看其中奇怪的D3DTS_WORLDMATRIX()宏,我们以前q没q样用过。它是做什么用的呢Q通过查DXSDK帮助Q我们在Geometry Blending主题中找到相兌明,q在"Indexed Vertex Blending"主题中给Z内部实现原理。原来,当你用m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);开启了索引点混合后,在硬件上启用了“palette of matrices”Q即矩阵寄存器组Q它最多支持同?56个烦引。就像过ȝ256色调色板来表现彩色一栗D3DTS_WORLDMATRIX()宏就是有256-511q?56个数表示矩阵索引受?/p>
q些矩阵参与如下计算Q?/p>
V最l顶点位|?V*M[索引?]*权重1 + V*M[索引?]*权重2 + ....+V*M[索引n]*(1-其它权重?
q个公式的来源,怿大家在众多资料上见过Q不赘述?当然Q我们也可以用程序完成这个蒙皮计过E,但逐个读顶点却很麻烦。现在是q件代劳了。我们只讄阵就行了?br>我们用m_pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( iPaletteEntry ), &matTemp );q种方式讑֮各烦引对应的矩阵?/p>
那么权重呢?我们怎么设?原来在上面所说的DX提供的ConvertToIndexedBlendedMesh()函数中,生成SkinMeshӞ各网格顶Ҏ式FVF已经有变化了Q增加了新格式,D3DFVF_XYZB2QD3DFVF_LASTBETA_UBYTE4Q用以记录顶点对应的权重g及矩늃引。如?br>struct VERTEX { float x,y,z; float weight; DWORD matrixIndices; float normal[3]; }; #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4 |D3DFVF_NORMAL);
D3DFVF_LASTBETA_UBYTE4对应于DWORD数|用于矩阵索引Ӟ每个字节表示一个烦引,最多可以允?个烦引,同时?个矩阵参于该点的混合。如果一ơ绘制中涉及?块骨骼矩阵,你可以把q?个矩阵全部用SetTransform讄到矩阵寄存器中,但每个顶点在渲染Ӟ最多用其中的4个。由此可知,pMeshContainer->NumPaletteEntriesq个数|定了一DrawSubsetl制所用到的矩阵个敎ͼ个数多Q在一绘制中可以纳入的更多点。所以,当我们减pMeshContainer->NumPaletteEntriesq个数值时QpMeshContainer->NumAttributeGroups数值就会增加。也是_一绘制中所允许涉及的骨骼数少Q那么子集的数量NumAttributeGroups׃增加Q需要多l几?br>你可以在此下断点观察Q当NumPaletteEntries=19ӞNumAttributeGroups=3 当NumPaletteEntries=6ӞNumAttributeGroups=12 当NumPaletteEntries=4ӞNumAttributeGroups=31Q几乎和无烦引时的分l一样多了?/p>
点中的权重weight存放了它当前骨骼的权重。(一个顶点对应的多个骨骼权重怎么存放Q是不是在当前子集中有多个同L点Q权重不同,对应的矩늃引不同,然后混合Q?/p>
׃所qͼConvertToIndexedBlendedMesh()是一个很重要函数Q由DX自动Mesh点分组成多个子集,以便DrawSubset. 你必L它的q回参数都记录下来,在绘制时使用?/p>
? 怎样l制昄动画Q?/strong>
DrawFrame()用来l制整个X框架。它遍历各个框架Q找到Mesh不ؓI的q行l制。(其实整个.x中通常只有一个不为空Q见上文所qͼ DrawMeshContainer()是绘制函数?/p>
4.1 怎样开启顶Ҏ合? 注意应用有关的Vertex Blending技术。如在烦引方式的l制中, m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, pMeshContainer->NumInfl - 1); 其实是设定了D3DVBF_2WEIGHTS或D3DVBF_3WEIGHTS 注意要m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);
4.2 矩阵的刷斎ͼ 首先Q在FrameMove()调用m_pAnimController->SetTime()讄当前旉(或在DX9.0c中用AdvanceTime()讄旉?Q从而刷新各个pFrame->TransformationMatrixQ即骨骼转换矩阵 其次Q调用UpdateFrameMatrices()做乘法篏U,计算出各骨骼坐标pd根世界{换矩c?br>最后,在绘制前Q将该{换矩阵左乘偏Uȝ阵,得到最l的转换矩阵?br> D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
由此可见Q你如果注释掉了m_pAnimController->SetTimeQ画面肯定停了?/p>
4.3 l制输出 是在DrawMeshContainer()中,调用SkinMesh的DrawSubsetq行l制。一些细节内容如D3DTS_WORLDMATRIX(),在上面已l有说明Q不再罗嗦?/p>
4.4 关于CZ中多U绘制方式分?/font> 在示例中Q用C多种渲染方式Q包括传l的非烦引顶Ҏ合,q有新兴的HLSL方式。而且我发玎ͼATI RADEON 9550 昑֍MaxVertexBlendMatrixIndex=37Q而h格更高的Gefoce 6600GT MaxVertexBlendMatrixIndex竟然?Q不支持index vertex blendingQ?br>所以,q是有必要分析一下该CZ中各Uvertex blending方式的处理,以便掌握多种l制方式适应不同昑֍?br>l测试,CZ中所涉及的多U方式,由慢到快Q依ơ是以下几种Q?br> SOFTWARE, D3DNONINDEXED, D3DINDEXED, D3DINDEXEDVS, D3DINDEXEDHLSLVS,
从最慢的SW到最快的HLSLQ大U相?0%Q有时会大到40%?差别不是特别悬殊的原因,主要是顶Ҏ合ƈ不是瓉?/p>
关于点处理方式Q是在创建D3D讑֤时指定的。共有三U方式: D3DCREATE_SOFTWARE_VERTEXPROCESSING 软g点q算 (?sw vp) D3DCREATE_HARDWARE_VERTEXPROCESSING g点q算。必Lq项才支持有HAL (?hw vp) D3DCREATE_MIXED_VERTEXPROCESSING 混合点q算Q即g+软g (?mixed vp)
一旦用D3DCREATE_HARDWARE_VERTEXPROCESSING方式创徏讑֤Q就只能在硬件方式下q行点处理。如果调用m_pd3dDevice->SetSoftwareVertexProcessing(TRUE)来切换到软g点处理QHRESULT会返回失败?br> 所以,如果你对客户的显卡没有够的信息Q就用D3DCREATE_MIXED_VERTEXPROCESSING方式创徏讑֤。它默认工作方式是HAL。一旦发现进行某U绘制时g能力不够Q就可以调用调用m_pd3dDevice->SetSoftwareVertexProcessing(TRUE)切换到Y件模式。在CZ中就是这么做的,启动CZ后,q行在mixed模式下?/p>
在Gefoce6600GT昑֍中,׃D3DINDEXED方式不支持,采用了Y件合方式,在这U方式下速度甚至比SOFTWARE慢。HLSLq好Q还是最快?/p>
要确定设备的g点处理能力Q可以参考D3DCAPS9l构的VertexProcessingCaps成员。可以获取下列属?br>MaxActiveLightsQMaxUserClipPlanesQMaxVertexBlendMatricesQMaxStreamsQMaxVertexIndex
(1)D3DNONINDEXED方式Q?/p>
首先看GenerateSkinnedMesh()中怎样创徏蒙皮|格的?br>q种方式下,用ConvertToBlendedMesh()建立蒙皮|格Q而不是ConvertToIndexBlendedMesh()
Zl制蒙皮Q在q个函数中对Mesh各子集的点再次q行的分l。分l的标准是各点Q或三角面)所涉及的骨骼矩阵个C过pMeshContainer->NumInfl个?q个数字是由在ConvertToBlendedMesh()Ӟ由参数pMaxFaceInflq回?。一个Mesh子集可能被拆开成多个分l?最后,分组的属性保存在pBoneCombinationBuf中,如子集ID,该子集的各骨骼IDQv始三角面Q三角面个数{供l制时用,分组的个C存在pMeshContainer->NumAttributeGroups中?/p>
接下来检查每个分l所涉及的骨骼数Q是不是过g允许的最大合矩阉|---MaxVertexBlendMatrices。如果超q了把所有分l截Z大部分,前一部分用硬件合,后一部分采用软g混合。而且Q一旦发现有需要Y件合,要采用CloneMeshFVF(D3DXMESH_SOFTWAREPROCESSING|...)的方式重新生成网根{?/p>
再来看绘刉分DrawMeshContainer()
用pBoneComb指向骨骼分组属性,扫描各分l。找出其中骨骼数满g性能的用q行l制?br>然后开启Y仉Ҏ染m_pd3dDevice->SetSoftwareVertexProcessing(TRUE)Q对那些骨骼数超出硬件性能的进行绘制?br>SetSoftwareVertexProcessing()需要当前d3d讑֤以D3DCREATE_MIXED_VERTEXPROCESSING方式创徏?/p>
(2)D3DINDEXEDQ这U方式上面分析过了,从略。用pMeshContainer->UseSoftwareVP表示是否采用软gl制?br>值得注意的是在这U方式下Q一旦硬件性能不Q会d使用软g点渲染Q而不是像上面一hZ部分?/p>
(3)D3DINDEXEDVSQD3DINDEXEDHLSLVS q种情况下用了着色器和高U着色语a。超出本文主旨,讨论从略?/p>
(4)SOFTWARE--软g方式Q?让h有些qhQ与上面的m_pd3dDevice->SetSoftwareVertexProcessing(TRUE)有何区别Q?/p>
从代码看Q这U方式下反而比较简单。GenerateSkinnedMesh()中, 先直接从原始Mesh克隆一个Mesh,然后d它的材质属性数l。开辟一个空间m_pBoneMatricesQ用以存攑块骨骼的转换矩阵?/p>
在绘制时Q从pMeshContainer中的变换矩阵乘以偏移矩阵Q放在pBoneMatrices中。把q个矩阵数组Q以原Mesh的顶点作为源点Q以新克隆的MeshData.pMesh做ؓ目标点Q调用pSkinInfo->UpdateSkinnedMesh()Q用软g方式计算各骨骼顶点的C|?相当于Y件计方式蒙??/p>
然后调用MeshData.pMesh->DrawSubset()l制?/p>
可见Q在SOFTWARE方式下,最l顶点的渲染q是HAL方式的,只不q蒙皮计是pY件完成的。它和上面的m_pd3dDevice->SetSoftwareVertexProcessing(TRUE)直接讄软g点渲染q是有区别的?/p>
]]>IDirect3DDevice9::SetClipPlane http://www.shnenglu.com/Leaf/archive/2009/10/11/98317.html大渊?/dc:creator>大渊?/author>Sun, 11 Oct 2009 08:34:00 GMT http://www.shnenglu.com/Leaf/archive/2009/10/11/98317.html http://www.shnenglu.com/Leaf/comments/98317.html http://www.shnenglu.com/Leaf/archive/2009/10/11/98317.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/98317.html http://www.shnenglu.com/Leaf/services/trackbacks/98317.html HRESULT SetClipPlane( DWORD Index , CONST float * pPlane ); 虽然DX SDK上面有,但还是有很多朋友不喜Ƣ看那些拉丁字母Q我也顺便就记录一下吧?br> 参数Q?br>W一个是索引Q不用说了?br> W二个是存着 A B C D的数l?br>q个数组最后会用来构徏 Ax+By+Cz+Dw = 0;q面?br> 然后点会根据自已的位置(x,y,z,w)来进行判断。如果Ax+By+Cz+Dw >= 0。则表示在^面前方,保留。反之则在后方,被裁剪掉?br> 值得注意的时Q在固定线使用q面裁剪的时候,是在世界坐标pM处理的?br> 而用SHADER的时候,是在裁剪I间中处理的。(即顶点输出的时候的坐标p) 貌似q是太抽象。比如顶点输入坐标是pos 此时的坐标变换阵是WVP,?Output.pos = mul(pos,WVP); 那么Q此时的裁剪I间是Output.pos对应的坐标系I间?/strong> 另外Q默认情况下D3DRS_CLIPPLANEENABLE 是没有打开的,应该在SetRenderState中手工打开? 值得注意的是QD3DXPLANEq行矩阵变换的时候,要将需要乘的那个矩阵进行求逆和转置Q再怹。SDK中代码如?br>
D3DXPLANE planeNew; D3DXPLANE plane( 0 , 1 , 1 , 0 ); D3DXPlaneNormalize( & plane, & plane); D3DXMATRIX matrix; D3DXMatrixScaling( & matrix, 1.0f , 2.0f , 3.0f ); D3DXMatrixInverse( & matrix, NULL, & matrix); D3DXMatrixTranspose( & matrix, & matrix); D3DXPlaneTransform( & planeNew, & plane, & matrix);
上面的D3DXPLANE plane(0,1,1,0)如果你觉得不直观的话QDX提供了以下一些生成PLANE的函?br>
D3DXPLANE * D3DXPlaneFromPoints( D3DXPLANE * pOut, CONST D3DXVECTOR3 * pV1, CONST D3DXVECTOR3 * pV2, CONST D3DXVECTOR3 * pV3 );
上面的PV1 PV2 PV3则是q面上的三个炏V这个函数可以很Ҏ地求得一个三角Ş所在的q面?br>
D3DXPLANE * D3DXPlaneFromPointNormal( D3DXPLANE * pOut, CONST D3DXVECTOR3 * pPoint, CONST D3DXVECTOR3 * pNormal );
pPoint为^面上的一个点?pNormal是^面的法线方向?br>比如Q你惛_Z个水q_^面,q且朝上?则可以将pPoint传入0Q?Q? 而pNormal传入0,1,0卛_?br>
]]> 关于图象的拉伔R?/title> http://www.shnenglu.com/Leaf/archive/2009/10/10/98276.html大渊?/dc:creator>大渊?/author>Sat, 10 Oct 2009 13:25:00 GMT http://www.shnenglu.com/Leaf/archive/2009/10/10/98276.html http://www.shnenglu.com/Leaf/comments/98276.html http://www.shnenglu.com/Leaf/archive/2009/10/10/98276.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/98276.html http://www.shnenglu.com/Leaf/services/trackbacks/98276.html <如果H口的视囑大小和SwapChain的大不一Q那么DirectX通过Stretch Blit来自动处理图像的伸羃变化。尽这可能q不令h期待Q因在视囑变大的时候将D囑փ的模p?gt; 你说的这个问?要怎么才能解决Q? 有位博友q样问过Q因为最q少有上博客Q于是没有回{及Ӟ误谅,我这里只能说说我们现在的解决办法?br> 当后台缓冲区的分辨率和视囑不统一的时候,会导致拉伸现象,使画面变得模p?br> 首先说个题外话: 正因为变得模p,因此有h故意后台缓冲区做得比视区稍大一点,q样来抗锯Q至于效果如何,没有真正见过Q有兴趣的可以试试?br> 下面说说解决办法?br>我们的解军_法也很简单,分三步 1Q窗口改变的时候,告诉讑֤H口大小改变?br>2Q按改变后的H口重徏~冲区?br>3。强制设备丢失,q新加载需要的资源?br> ׃在做q个之前Q设备丢失已l做好了Q于是就偷了个懒Q窗口改变的时候就传入H口大小Qƈreset q样讑֤强制处于丢q态?br> 不知道有没有说清楚,反正主要的就是要重徏~冲区,q处理设备丢失问题。。?
]]> 如何避免VS2005下的d3d9types.h(1385) warning C4819 http://www.shnenglu.com/Leaf/archive/2009/08/24/94310.html大渊?/dc:creator>大渊?/author>Mon, 24 Aug 2009 12:51:00 GMT http://www.shnenglu.com/Leaf/archive/2009/08/24/94310.html http://www.shnenglu.com/Leaf/comments/94310.html http://www.shnenglu.com/Leaf/archive/2009/08/24/94310.html#Feedback 1 http://www.shnenglu.com/Leaf/comments/commentRss/94310.html http://www.shnenglu.com/Leaf/services/trackbacks/94310.html 用VS2005+DirectX9 SDKQ手头测试过的是2004q?0月的DirectX SDK?006q?月的DirectX SDKQ编译游戏会出现以下warningQ?/p>
--------------------------------------------------------------------------------
d:\microsoft directx 9.0 sdk (october 2004)\include\d3d9types.h(1385) : warning C4819: The file contains a character that cannot be represented in the current code page (936). Save the file in Unicode format to prevent data loss
-------------------------------------------------------------------------------- 要修正这个问题,不必要存为UTF8的文Ӟ而是搜烦_D3DDEVINFO_VCACHEQ然后会看到Q?/p>
typedef struct _D3DDEVINFO_VCACHE ...{ DWORD Pattern; /**//* bit pattern, return value must be FOUR_CC(? ? ? ? */ DWORD OptMethod; /**//* optimization method 0 means longest strips, 1 means vertex cache based */ DWORD CacheSize; /**//* cache size to optimize for (only required if type is 1) */ DWORD MagicNumber; /**//* used to determine when to restart strips (only required if type is 1)*/ } D3DDEVINFO_VCACHE, *LPD3DDEVINFO_VCACHE; 那四个ؕ码的L可以了
参考了http://gamep.mmoh.jp/e39255.html
本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/SONIC3D/archive/2007/11/01/1861794.aspx
]]> ?深入理解D3D9 http://www.shnenglu.com/Leaf/archive/2009/08/13/93109.html大渊?/dc:creator>大渊?/author>Wed, 12 Aug 2009 16:29:00 GMT http://www.shnenglu.com/Leaf/archive/2009/08/13/93109.html http://www.shnenglu.com/Leaf/comments/93109.html http://www.shnenglu.com/Leaf/archive/2009/08/13/93109.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/93109.html http://www.shnenglu.com/Leaf/services/trackbacks/93109.html 文章来源Q?a >http://www.cnblogs.com/effulgent/archive/2009/02/10/1387438.html 深入理解D3D9对图形程序员来说意义重大Q我把以前的一些学习笔记都汇总v来,希望Ҏ友们有些所帮助Q因为是零散W记Q思\很杂Q还请包c?/p>
其实只要你能完美理解D3DLOCK、D3DUSAGE、D3DPOOL、LOST DEVICE、QUERY、PresentQ)、BeginSceneQ)、EndSceneQ){概念,q是理解D3D9了, 不知道大家有没有同感。有如下几个问题Q如果你能圆满回{就过养IQ?br>1?nbsp; D3DPOOL_DEFAULT ?span lang=EN-US>D3DPOOL_MANAGED ?span lang=EN-US>D3DPOOL_SYSTEMMEM?span lang=EN-US>D3DPOOL_SCRATCH到底有何本质区别Q?br>2?nbsp; D3DUSAGE的具体怎么使用Q?br>3?nbsp; 什么是AdapterQ什么是D3D Device Q?span lang=EN-US>HAL Device ?span lang=EN-US>Ref Device 有何区别Q?span lang=EN-US>Device 的类型又?span lang=EN-US>Vertex Processing cd有什么关p?4?nbsp; APPQ?span lang=EN-US>CPU Q?span lang=EN-US>RUNTIME ?span lang=EN-US>DRIVER ?span lang=EN-US>GPU 是如何协同工作的Q?span lang=EN-US>D3D API 是同步函数还是异步函敎ͼ5?nbsp; Lost Device到底发生了什么?Z么在讑֤丢失?span lang=EN-US>D3DPOOL_DEFAULTcd资源需要重新创建?
?span lang=EN-US>D3D中有三大对象Q他们是D3D OBJECT ?span lang=EN-US>D3D ADAPTER?span lang=EN-US>D3D DEVICE?span lang=EN-US>D3D OBJECT很简单,是一个?span lang=EN-US>D3D功能?span lang=EN-US>COM对象Q其提供了创?span lang=EN-US>DEVICE和枚?span lang=EN-US>ADAPTER的功能?span lang=EN-US>ADAPTER是对计算机图形硬件和软g性能的一个抽象,其包含了DEVICE ?span lang=EN-US>DEVICE则是D3D 的核心,它包装了整个囑Ş水线Q包括变换、光照和光栅化(着ԌQ根?span lang=EN-US>D3D版本不同Q流水线也有区别Q比如最新的D3D10 包含了新的GS 几何处理。图形管U的所有功能由DRIVER 提供Q?span lang=EN-US>DIRVER分两c,一U是GPU gDRIVER Q另一U是软gDRIVER Q这是Z么在D3D 中主要有两类DEVICE Q?REF?span lang=EN-US>HAL Q?span lang=EN-US>REF DEVICEӞ囑Ş线的光栅化功能pY?span lang=EN-US>DRIVER?span lang=EN-US>CPU上模拟的Q?span lang=EN-US>REF DEVICE从名字就可以看出q个l硬件厂商做功能参考用的,所以按常理它应该是全Y件实玎ͼ具备全部DX 标准功能。而?span lang=EN-US>HAL DEVICEӞRUNTIME 则将使用HAL g层控?span lang=EN-US>GPU来完成变换、光照和光栅化,而且只有HAL DEVICE 中同时实Cg点处理和Y仉点处理(REF DEVICE 一般不能用硬仉点处理,除非自己在驱动上做手脚,比如PERFHUD Q。另外还有个一个不常用?span lang=EN-US>SOFTWARE DEVICEQ用户可以?span lang=EN-US>DDI~写自己的Y件图形驱动,然后注册q系l,之后便可在程序中使用?/span>
查系lY件硬件性能?br>在程序的开始我们就要判断目标机的性能Q其主要程是: 定要用的缓冲格?br>GetAdapterCount() GetAdapterDisplayMode
GetAdapterIdentifier // 得到适配器描q?br>CheckDeviceType //判断指定适配器上的设备是否支持硬件加?br>GetDeviceCaps //指定讑֤的性能Q主要判断是否支持硬仉点处?span lang=EN-US>(T&L)GetAdapterModeCount // 得到适配器上指定~冲格式所有可用的昄模式EnumAdapterModes //枚D所有显C模?br>CheckDeviceFormat CheckDeviceMultiSampleType 详细使用请参考DX文?span lang=EN-US>
WINDOWS囑Şpȝ的主要分为四层:囑Ş应用E序?span lang=EN-US>D3D RUNTIME?span lang=EN-US>SOFTWARE DRIVER?span lang=EN-US>GPU。此四层是按功能来分的,实际上他们之间界限ƈ不如此明,比如RUNTIME中其实也包含?span lang=EN-US>USER MODE?span lang=EN-US>SOFTWARE DRIVERQ详l结构这里不再多说。而在RUNTIME里有一个很重要的结构,叫做command bufferQ当应用E序调用一?span lang=EN-US>D3D APIӞRUNTIME 调用{换成讑֤无关的命令,然后命令缓冲到q个COMMAND BUFFER 中,q个BUFFER 的大是Ҏd负蝲动态改变的Q当q个BUFFER 满员之后Q?span lang=EN-US>RUNTIME 会让所有命?span lang=EN-US>FLUSH ?span lang=EN-US>KERNEL 模式下的驱动中,而驱动中也是有一?span lang=EN-US>BUFFER 的,用来存储已被转换成的g相关的命令,D3D 一般只允许其缓冲最?span lang=EN-US>3 个的图形指令,而且RUNTIME ?span lang=EN-US>DRIVER都会?span lang=EN-US>BUFFER中的命o做适当优化Q比如我们在E序中连l设|同一?span lang=EN-US>RENDER STATEQ我们就会在调试信息中看到如下信?#8220;Ignoring redundant SetRenderState - X ”Q这便是RUNTIME 自动丢弃无用的状态设|命令。在D3D9 中可以?span lang=EN-US>QUERY机制来与GPU q行异步工作Q所?span lang=EN-US>QUERY是查询命oQ用来查?span lang=EN-US>RUNTIME?span lang=EN-US>DRIVER或?span lang=EN-US>GPU的状态,D3D9 中的QUERY 对象有三U状态,SIGNALED ?span lang=EN-US>BUILDING?span lang=EN-US>ISSUEDQ当他们处于I闲状态后会将查询状态置?span lang=EN-US>SIGNALED STATEQ查询分开始和l束Q查询开始表C对象开始记录应用程序所需数据Q当应用E序指定查询l束后,如果被查询的对象处于I闲状态,则被查询对象会将查询对象|于SIGNALED 状态?span lang=EN-US>GetData则是用来取得查询l果Q如果返回的?span lang=EN-US>D3D_OK则结果可用,如果使用D3DGETDATA_FLUSH 标志Q表C将COMMAND BUFFER 中的所有命令都发送到DRIVER 。现在我们知?span lang=EN-US>D3D APIl大部分都是同步函数Q应用程序调用后Q?span lang=EN-US>RUNTIME只是单的其加入?span lang=EN-US>COMMAND BUFFERQ可能有Z疑惑我们如何定帧率Q又如何分析GPU 旉呢?对于W一个问题我们要看当一帧完毕,也就?span lang=EN-US>PRESENT()函数调用是否被阻塞,{案是可能被d也可能不被阻塞,要看RUNTIME 允许~冲中存在的指o数量Q如果超q额度,?span lang=EN-US>PRESENT函数会被d下来Q如?span lang=EN-US>PRESENT完全不被dQ当GPU 执行J重的绘制Q务时Q?span lang=EN-US>CPU工作q度会大大超q?span lang=EN-US>GPUQ导致游戏逻辑快于囑Ş昄Q这昄是不行的。测?span lang=EN-US>GPU工作旉是g很麻烦的事,首先我们要解军_步问题,要测?span lang=EN-US>GPU旉Q首先我们必让CPU ?span lang=EN-US>GPU异步工作Q在D3D9 中可以?span lang=EN-US>QUERY机制做到q点Q让我们看看Accurately Profiling Driect3D API Calls 中的例子: IDirect3DQuery9* pQueryEvent;
//1. 创徏事gcd的查询事?br>m_pD3DDevice->CreateQuery( D3DQUERYTYPE_EVENT, &pQueryEvent);//2. ?span lang=EN-US>COMMAND BUFFER 中加入一个查询结束的标记Q此查询默认开始于CreateDevice pQueryEvent->Issue(D3DISSUE_END);//3. ?span lang=EN-US>COMMAND BUFFER 中的所有命令清I到DRIVER 中去Qƈ循环查询事g对象转换?span lang=EN-US>SIGNALED 状态,?span lang=EN-US>GPU 完成CB 中所有命令后会将查询事g状态进行{换?br>while(S_FALSE == pQueryEvent->GetData( NULL, 0, D3DGETDATA_FLUSH) ) ; LARGE_INTEGER start, stop; QueryPerformanceCounter(&start); SetTexture(); DrawPrimitive(); pQueryEvent->Issue(D3DISSUE_END); while(S_FALSE == pQueryEvent->GetData( NULL, 0, D3DGETDATA_FLUSH) ) ; QueryPerformanceCounter(&stop);
1.W一个GetData调用使用了D3DGETDATA_FLUSH标志Q表CCOMMAND BUFFER中的l制命o都清I到DRIVER中去Q当GPU处理完所有命令后会将q个查询对象状态置SIGNALED?br>2.设备无关的SETTEXTURE命o加入到RUNTIME的COMMAND BUFFER中?br>3.设备无关的DrawPrimitive命o加入到RUNTIME的COMMAND BUFFER中?br>4.设备无关的ISSUE命o加入到RUNTIME的COMMAND BUFFER中?br>5.GetData会将BUFFER中的所有命令清I到DRIVER中去Q注意这是GETDATA不会{待GPU完成所有命令的执行才返回。这里会有一个从用户模式到核心模式的切换?br>6.{待DRIVER所有命令都转换为硬件相x令,q填充到DRIVER BUFFER中后Q调用从核心模式q回到用h式?br>7.GetData循环查询 查询对象 状态。当GPU完成所有DRIVER BUFFER中的指o后会改变查询对象的状态?/span>
如下情况可能清空RUNTIME COMMAND BUFFERQƈ引v一个模式切换: 1.Lock methodQ某些条件下和某些LOCK标志Q?/p>
2.创徏讑֤、顶点缓册Ӏ烦引缓冲和U理 3.完全释放讑֤、顶点缓册Ӏ烦引缓冲和U理资源 4.调用ValidateDevice 5.调用Present 6.COMMAND BUFFER已满 7.用D3DGETDATA_FLUSH调用GetData函数
对于D3DQUERYTYPE_EVENT的解释我不能完全理解Q?span>Query for any and all asynchronous events that have been issued from API calls Q明白的朋友一定告诉我Q只知道?span lang=EN-US>GPU 处理?span lang=EN-US>D3DQUERYTYPE_EVENT cd查询?span lang=EN-US>CB 中加入的D3DISSUE_END 标记后,会将查询对象状态置SIGNALED 状态,所?span lang=EN-US>CPU {待查询一定是异步的。ؓ了效率所以尽量少?span lang=EN-US>PRESENT 之前使用BEGINSCENE ENDSCENE 对,Z么会影响效率Q原因只能猜,可能EndScene 会引?span lang=EN-US>Command buffer flush q样会有一个执行的模式切换Q也可能会引发D3D RUNTIME对MANAGED资源的一些操作。而且ENDSCENE 不是一个同步方法,它不会等?span lang=EN-US>DRIVER把所有命令执行完才返回?nbsp;
D3D RUTIME的内存类型,分ؓ3U,VIDEO MEMORYQ?span lang=EN-US>VMQ?span lang=EN-US>AGP MEMORY Q?span lang=EN-US>AM Q和SYSTEM MEMORY Q?span lang=EN-US>SM Q,所?span lang=EN-US>D3D 资源都创建在q?span lang=EN-US>3 U内存之中,在创源时Q我们可以指定如下存储标志,D3DPOOL_DEFAULT ?span lang=EN-US>D3DPOOL_MANAGED?span lang=EN-US>D3DPOOL_SYSTEMMEM?span lang=EN-US>D3DPOOL_SCRATCH?span lang=EN-US>VM是位于昑֍上的昑֭Q?span lang=EN-US>CPU只能通过AGP ?span lang=EN-US>PCI-Eȝ讉K刎ͼd速度都是非常慢的Q?span lang=EN-US>CPUq箋?span lang=EN-US>VME微快于读,因ؓCPU ?span lang=EN-US>VM时会?span lang=EN-US>CACHE中分?span lang=EN-US>32?/span>64 个字节(取决?span lang=EN-US>CACHE LINE长度Q的写缓Ԍ当缓冲满后会一ơ性写?span lang=EN-US>VMQ?span lang=EN-US>SM是pȝ内存Q?span lang=EN-US>CPUd都非常快Q因?span lang=EN-US>SM是被CACHE ?span lang=EN-US>2U缓冲的Q但GPU 却不能直接访问到pȝ~冲Q所以创建在SM 中的资源Q?span lang=EN-US>GPU是不能直接用的Q?span lang=EN-US>AM是最ȝ的一个类型,AM 实际也存在于pȝ内存中,但这部分MEM 不会?span lang=EN-US>CPU CACHEQ意味着CPU dAM 都会写来?span lang=EN-US>CACHE MISSING然后才通过内存ȝ讉KAM Q所?span lang=EN-US>CPUdAM 相比SM 会比较慢Q但q箋的写会稍微快于读Q原因就?span lang=EN-US>CPU?span lang=EN-US>AM使用?#8220;write combining ”Q而且GPU 可以直接通过AGP ?span lang=EN-US>PCI-Eȝ讉KAM ?nbsp;
如果我们使用D3DPOOL_DEFAULT来创源,则表CD3D RUNTIMEҎ我们指定的资源用方法来自动使用存储cdQ一般是VM?span lang=EN-US>AMQ系l不会在其他地方q行额外备䆾Q当讑֤丢失后,q些资源内容也会被丢失掉?span>但系lƈ不会在创建的时候用D3DPOOL_SYSTEMMEM或D3DPOOL_MANAGED来替换它Q注意他们是完全不同的POOLcdQ创建到D3DPOOL_DEFAULT中的U理是不能被CPU LOCK的,除非是动态纹理。但创徏在D3DPOOL_DEFAULT中的VB IB RENDERTARGET BACK BUFFERS可以被LOCK。当你用D3DPOOL_DEFAULT创徏资源Ӟ如果昑֭已经使用完毕Q则托管资源会被换出昑֭来释放够的I间?nbsp;D3DPOOL_SYSTEMMEM?span lang=EN-US>D3DPOOL_SCRATCH 都是位于SM 中的Q其差别是?span lang=EN-US>D3DPOOL_SYSTEMMEM Ӟ资源格式受限?span lang=EN-US>Device 性能Q因源很可能会被更新?span lang=EN-US>AM ?span lang=EN-US>VM 中去供图形系l用,?span lang=EN-US>SCRATCH 只受RUNTIME 限制Q所以这U资源无法被囑Şpȝ使用?span> D3DRUNTIME会优化D3DUSAGE_DYNAMIC 资源Q一般将其放|于AM中,但不敢完全保证。另外ؓ什么静态纹理不能被LOCKQ动态纹理却可以Q都关系到D3D RUNTIME的设计,在后面D3DLOCK说明中会叙述?/span>
D3DPOOL_MANAGED 表示?span lang=EN-US>D3D RUNTIME来管理资源,被创建的资源会有2 份拷贝,一份在SM 中,一份在VM/AM 中,创徏的时候被攄L ?span lang=EN-US>SMQ在GPU 需要用资源时D3D RUNTIME 自动数据拷贝到VM 中去Q当资源?span lang=EN-US>GPU修改后,RUNTIME 在必要时自动其更新?span lang=EN-US>SM中来Q而在SM 中修改后也会?span lang=EN-US>UPDATE?span lang=EN-US>VMM。所以被CPU 或?span lang=EN-US>GPU频发修改的数据,一定不要用托类型,q样会生非常昂늚同步负担。当LOST DEVICE 发生后,RESET ?span lang=EN-US>RUNTIME会自动利?span lang=EN-US>SM中的COPY 来恢?span lang=EN-US>VM中的数据Q因为备份在SM 中的数据q不是全部都会提交到VM 中,所以实际备份数据可以远多于VM 定wQ随着资源的不断增多,备䆾数据很可能被交换到硬盘上Q这?span lang=EN-US>RESET的过E可能变得异常缓慢,RUNTIME l每?span lang=EN-US>MANAGED资源都保留了一个时间戳Q当RUNTIME 需要把备䆾数据拯?span lang=EN-US>VM中时Q?span lang=EN-US>RUNTIME会在VM 中分配显存空_如果分配p|Q表C?span lang=EN-US>VM已经没有可用I间Q这?span lang=EN-US>RUNTIME会?span lang=EN-US>LRU法Ҏ旉戳释攄兌源,SetPriority 通过旉x讄资源的优先Q最q常用的资源拥有高的优先Q这?span lang=EN-US>RUNTIME通过优先U就能合理的释放资源Q发生释攑马上又要使用q种情况的几率会比较,应用E序q可以调?span lang=EN-US>EvictManagedResources强制清空VM 中的所?span lang=EN-US>MANAGED资源Q这样如果下一帧有用到MANAGED 资源Q?span lang=EN-US>RUNTIME需要重新蝲入,q样Ҏ能有很大媄响,qx一般不要用,但在兛_转换的时候,q个函数是非常有用的Q可以消?span lang=EN-US>VM中的内存片?span lang=EN-US>LRU法在某些情况下有性能~陷Q比如绘制一帧所需资源量无法被VM 装下的时候(MANAGED Q,使用LRU 法会带来严重的性能波动Q如下例子:
BeginScene(); Draw(Box0); Draw(Box1); Draw(Box2); Draw(Box3); Draw(Circle0); Draw(Circle1); EndScene(); Present();
假设VM 只能装下其中5个几何体的数据,那么ҎLRU 法Q在l制Box3 之前必须清空部分数据Q那清空的必然是Circle0 ……Q很昄清空Box2 是最合理的,所以这?span lang=EN-US>RUNTIME使用MRU 法处理后箋Draw Call 能很好的解决性能波动问题Q但资源是否被用是?span lang=EN-US>FRAME为单位来的Qƈ不是每个DRAW CALL 都被记录Q每?span lang=EN-US>FRAME的标志就?span lang=EN-US>BEGINSCENE/ENDSCENE对,所以在q种情况下合理?span lang=EN-US>BEGINSCENE/ENDSCENE对可以很好的提高VM 不够情况下的性能。根?span lang=EN-US>DX文的提C我们还可以使用QUERY 机制来获得更多关?span lang=EN-US>RUNTIME MANAGED RESOURCE信息Q但好像只在RUNTIME DEBUG 模式下有用,理解RUNTIME 如何MANAGE RESOURCE 很重要,但编写程序的时候不要将q些l节暴露出来Q因些东襉K是经怼变的。最后还要提醒的是,不光RUNTEIME ?span lang=EN-US>MANAGE RESOURCEQ?span lang=EN-US>DRIVER也很可能也实Cq些功能Q我们可以通过D3DCAPS2_CANMANAGERESOURCE 标志取得DRIVER 是否实现资源理功能的信息,而且也可以在CreateDevice 的时候指?span lang=EN-US>D3DCREATE_DISABLE_DRIVER_MANAGEMENT来关?span lang=EN-US>DRIVER资源理功能?nbsp;
D3DLOCK 探烦D3D RUNTIME 工作
如果LOCK DEFAULT 资源会发生什么情况呢Q?span lang=EN-US>DEFAULT资源可能?span lang=EN-US>VM?span lang=EN-US>AM中,如果?span lang=EN-US>VM中,必须在系l内容中开辟一个时缓冲返回给数据Q当应用E序数据填充到临时~冲后,UNLOCK 的时候,RUNTIME 会将临时~冲的数据传回到VM 中去Q如果资?span lang=EN-US>D3DUSAGE属性不?span lang=EN-US>WRITEONLY的,则系l还需要先?span lang=EN-US>VM里拷贝一份原始数据到临时~冲区,q就是ؓ什么不指定WRITEONLY 会降低程序性能的原因?span lang=EN-US>CPU?span lang=EN-US>AM也有需要注意的地方Q因?span lang=EN-US>CPU?span lang=EN-US>AM一般是WRITE COMBINING Q也是说将写缓冲到一?span lang=EN-US>CACHE LINE上,?span lang=EN-US>CACHE LINE满了之后?span lang=EN-US>FLUSH?span lang=EN-US>AM中去Q第一个要注意的就是写数据必须?span lang=EN-US>WEAK ORDER的(囑Ş数据一般都满q个要求Q,据说D3DRUNTIME ?span lang=EN-US>NV DIRVER有点?span lang=EN-US>BUGQ就是在CPU 没有FLUSH ?span lang=EN-US>AMӞGPU 开始绘制相兌源生的错误Q这时请使用SFENCE {指?span lang=EN-US>FLUSH CACHE LINE。第二请量一ơ写满一?span lang=EN-US>CACHE LINEQ否则会有额外gq,因ؓCPU 每次必须FLUSH 整个CACHE LINE 到目标,但如果我们只写了LINE 中部分字节,CPU 必须先从AM 中读取整?span lang=EN-US>LINE长数?span lang=EN-US>COMBINE后重?span lang=EN-US>FLUSH。第三尽可能序写,随机写会?span lang=EN-US>WRITE COMBINING反而变成篏赘,如果是随机写资源Q不要?span lang=EN-US>D3DUSAGE_DYNAMIC创徏Q请使用D3DPOOL_MANAGED Q这样写会完全在SM 中完成?/p>
普通纹理(D3DPOOL_DEFAULT Q是不能被锁定的Q因为其位于VM 中,只能通过UPDATESURFACE ?span lang=EN-US>UPDATETEXTURE来访问,Z?span lang=EN-US>D3D不让我们锁定静态纹理,却让我们锁定静?span lang=EN-US>VB IB呢?我猜可能有2 个方面的原因Q第一是U理矩阵一般十分庞大,且纹理在GPU 内部已二l方式存储;W二是纹理在GPU 内部是以NATIVE FORMAT 方式存储的,q不是明?span lang=EN-US>RGBA格式。动态纹理因明这个纹理需要经怿改,所?span lang=EN-US>D3D会特别存储对待,高频率修改的动态纹理不适合用动态属性创建,在此分两U情况说明,一U是GPU 写入?span lang=EN-US>RENDERTARGETQ一U是CPU 写入?span lang=EN-US>TEXTURE VIDEOQ我们知道动态资源一般是攄?span lang=EN-US>AM中的Q?span lang=EN-US>GPU讉KAM 需要经q?span lang=EN-US>AGP/PCI-EȝQ速度?span lang=EN-US>VM慢许多,?span lang=EN-US>CPU讉KAM 又较SM 慢很多,如果资源为动态属性,意味着GPU ?span lang=EN-US>CPU讉K资源会持l的延迟Q所以此c资源最好以D3DPOOL_DEFAULT ?span lang=EN-US>D3DPOOL_SYSTEMMEM各创Z份,自己手动q行双向更新更好。千万别 RENDERTARGET ?span lang=EN-US>D3DPOOL_MANAGED 属性创建,q样效率极低Q原因自己分析。而对于改动不太频J的资源则推荐?span lang=EN-US>DEFAULT创徏Q自己手动更斎ͼ因ؓ一ơ更新的效率损失q比GPU 持箋讉KAM 带来的损p?nbsp;
不合理的LOCK 会严重媄响程序性能Q因Z?span lang=EN-US>LOCK需要等?span lang=EN-US>COMMAND BUFFER前面的绘制指令全部执行完毕才能返回,否则很可能修Ҏ在用的资源Q从LOCK q回C改完?span lang=EN-US>UNLOCKq段旉GPU 全部处于I闲状态,没有合理使用GPU ?span lang=EN-US>CPU的ƈ行性,DX8.0 引进了一个新?span lang=EN-US>LOCK标志D3DLOCK_DISCARDQ表CZ会读取资源,只会全写资源Q这样驱动和RUNTIME配合来了个瞒天过P立即q回l应用程序另外块VM地址指针Q而原指针在本ơUNLOCK之后被丢弃不再用,q样CPU LOCK无需{待GPU使用资源完毕Q能l箋操作囑Ş资源Q顶点缓冲和索引~冲Q,q技术叫VB IB换名QrenamingQ?/span>
很多困惑来源于底层资料的不Q相信要是MS开放D3D源码Q开N动接口规范,NV / ATI昄开N动和g架构信息Q这些东西就很容易弄明白了?/p>
Z做个书的q告 《h工智能:一U现代方法》中文版 卓越|已l有货,AI巨作Q不q阅读需要相当的基础Q对思维非常有启q,想买的朋友不要错q。后面我会将学习重点从图形{到AI上来Q对AI有兴的朋友一起交?/p>
]]> Direct3D9 中的Gamma矫正 http://www.shnenglu.com/Leaf/archive/2009/08/13/93107.html大渊?/dc:creator>大渊?/author>Wed, 12 Aug 2009 16:17:00 GMT http://www.shnenglu.com/Leaf/archive/2009/08/13/93107.html http://www.shnenglu.com/Leaf/comments/93107.html http://www.shnenglu.com/Leaf/archive/2009/08/13/93107.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/93107.html http://www.shnenglu.com/Leaf/services/trackbacks/93107.html Gamma校正 在D3D9中?br> 可以指明一张纹理是不是Gamma 2.2QsRGB) 较正.驱动E序会在SetTexture的时候将其{换到U性的Gamma以进行融合操作。或者采样器会在查询的时候将其变为线性数据?br> 可以指明像素线在输出到渲染目标的时候是否将Gamma校正变换回sRGBI间?br> 所有其它颜?clear color, material color, vertex color, etcQ都被假定ؓU性空间中。应用程序可以用像素着色器指o对写入到帧缓存中的颜色进行Gamma校正。线性化操作只对RGB通道有效Q忽略ALPHA通道?br> 不是所有的表面格式都可以线性化。只有通过 IDirect3D9::CheckDeviceFormat (参数为D3DUSAGE_QUERY_SRGBREAD Q的格式才可以被U性化。除此之外,采样状态D3DSAMP_SRGBTEXTURE 也会被忽略。只有无W号U理格式支持q种变换。无W号U理格式是指仅包含有R G B ?L成分的纹理格式。如果包含ALPHA通道Q那它将被忽略。如果合的格式支持sRGBU性化Q那么只有无W号通道有效。理x冉|g在纹理过滤前实现U性化。但在D3D9中,g只有在纹理过滤后才允许线性化?br> 不是所有的表面都可以被写进sRGBI间Q只有通过用D3DUSAGE_QUERY_SRGBWRITEq行IDirect3D9::CheckDeviceFormat 试的表面格式才能进行线性化。另外,渲染状态中的D3DRS_SRGBWRITEENABLE标志会被忽略。每个通道8位的无符号RGB格式是比较适合的格式?br>理想圎ͼg会在线性空间上q行帧缓存融合操作。但实际上硬件只能在像素线处理后,帧缓存融合前q行。这意味着在sRGB中进行~存融合操作会导致错误的l果。当清除渲染目标时。D3DRS_SRGBWRITEENABLE 标志 is Honored.对于g支持多渲染目标或多元素纹理的情况Q只有第一个渲染目标和W一个元素会被写入缓存?br> API变化
API Changes
// New sampler state (DWORD) 新的采样器状?
// If this is nonzero, the texture is linearized on lookup.
如果它非0Q纹理在查询是线性化?
D3DSAMP_SRGBTEXTURE // Default FALSE 默认为假
// New render state (DWORD)
新的渲染状?
D3DRS_SRGBWRITEENABLE // Default FALSE 默认为假
// New usage flags
新的使用标志
D3DUSAGE_QUERY_SRGBWRITE
D3DUSAGE_QUERY_SRGBREAD
H口下的交换?/pre>
Zq行正确的融合操作,应用E序保存他们的交换链在线性空间中的后台缓冲区是非常必要的。因为桌面通常情况下是不在U性空间的。所以需要在后台~冲区内ҎC前q行Gamma校正?/pre>
应用E序可以通过新增额外的缓冲区来自我校正,q把他自已正的l果从线性空间复制到后台~冲区。当驱动Gamma校正作ؓ部分昄的时候,是可以避免用额外的~冲区的?
]]> IDirect3DDevice9::Reset p|的原?/title> http://www.shnenglu.com/Leaf/archive/2009/08/11/92897.html大渊?/dc:creator>大渊?/author>Tue, 11 Aug 2009 06:22:00 GMT http://www.shnenglu.com/Leaf/archive/2009/08/11/92897.html http://www.shnenglu.com/Leaf/comments/92897.html http://www.shnenglu.com/Leaf/archive/2009/08/11/92897.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/92897.html http://www.shnenglu.com/Leaf/services/trackbacks/92897.html 摘自: http://www.gamedev.net/community/forums/topic.asp?topic_id=146731
1) One of the parameters you pass is probably not possible on the hardware, e.g. a depth buffer format which won't work with the back buffer format. 你传入的D3DPRESENT_PARAMETERS和你的硬件不W,可能是深度格式与你的后台~冲格式不匹配。通常情况下我们是先前的D3DPRESENT_PARAMETERS保存QRESET的时候传入,若是q种情况Q则不必担心q个问题
2) The debug D3D runtime will tell you exactly "why": 把DirectX Control Pannel中的Direct3D开试模式,q行q后Q编译器的信息提C框里会输出原因Q多半是因ؓ位于D3DPOOL_DEFAULT中的内容未释攑֮而导致的
a. When you install the DirectX SDK you get the option to install the debug or retail runtime, if you're developing software, always choose debug.
安装SDK的时候,你可以选则是调式还是运行模式,如果你是软g开发,通常选择?/div>
b. Go to the control panel and open the DirectX applet. 到SDK中把DirectX Control Pannel程序打开
c. Go to the Direct3D tab and put the "debug output level" slider to maximum.
把DirectX Control Pannel中的Direct3D开试模?/div>
d. Run your application in the debugger (if using MSVC, press F5) and repeat whatever process causes it to fail. 在调试状态下q行你的E序Q重复处理导致你出错的地?br>
e. Once it fails, close the app if necessary and return to MSVC, now look in the "output" pane (usually at the bottom). D3D will tell you about everything noteworthy, from information about its DLL being attached to your application, to warnings about things which may harm performance to the full reason why it gave an error.
如果发现p|了,关掉调试,在输Z息面板中D3D会告诉你是什么原因导致你p|的?/div>
f. If your application creates its D3D device in PURE mode, creating it in non-PURE mode should enable more checking and reporting.
如果你的E序创徏的时候的D3D讑֤是PURE模式Q那在创建的时候改为非PURE模式Q这样你在上面的控制面板中得到的信息会更多?/div>
]]>
译 D3DPOOL http://www.shnenglu.com/Leaf/archive/2009/08/11/92850.html大渊?/dc:creator>大渊?/author>Mon, 10 Aug 2009 16:34:00 GMT http://www.shnenglu.com/Leaf/archive/2009/08/11/92850.html http://www.shnenglu.com/Leaf/comments/92850.html http://www.shnenglu.com/Leaf/archive/2009/08/11/92850.html#Feedback 4 http://www.shnenglu.com/Leaf/comments/commentRss/92850.html http://www.shnenglu.com/Leaf/services/trackbacks/92850.html 边看边写下来的,肯定译得不好,有要看的就一?/h1>
D3DPOOL
Defines the memory class that holds the buffers for a resource. q句不用译
typedef enum D3DPOOL
{
D3DPOOL_DEFAULT = 0,
D3DPOOL_MANAGED = 1,
D3DPOOL_SYSTEMMEM = 2,
D3DPOOL_SCRATCH = 3,
D3DPOOL_FORCE_DWORD = 0x7fffffff,
} D3DPOOL, *LPD3DPOOL;
Constants 帔R
D3DPOOL_DEFAULT
Resources are placed in the memory pool most appropriate for the set of usages requested for the given resource. This is usually video memory, including both local video memory and AGP memory. The D3DPOOL_DEFAULT pool is separate from D3DPOOL_MANAGED and D3DPOOL_SYTEMMEM, and it specifies that the resource is placed in the preferred memory for device access. Note that D3DPOOL_DEFAULT never indicates that either D3DPOOL_MANAGED or D3DPOOL_SYSTEMMEM should be chosen as the memory pool type for this resource. Textures placed in the D3DPOOL_DEFAULT pool cannot be locked unless they are dynamic textures or they are private, FOURCC, driver formats. To access unlockable textures, you must use functions such as IDirect3DDevice9::UpdateSurface , IDirect3DDevice9::UpdateTexture , IDirect3DDevice9::GetFrontBufferData , and IDirect3DDevice9::GetRenderTargetData . D3DPOOL_MANAGED is probably a better choice than D3DPOOL_DEFAULT for most applications. Note that some textures created in driver-proprietary pixel formats, unknown to the Direct3D runtime, can be locked. Also note that - unlike textures - swap chain back buffers, render targets, vertex buffers, and index buffers can be locked. When a device is lost, resources created using D3DPOOL_DEFAULT must be released before calling IDirect3DDevice9::Reset . For more information, see Lost Devices .
When creating resources with D3DPOOL_DEFAULT , if video card memory is already committed, managed resources will be evicted to free enough memory to satisfy the request. 资源被放入内存池中多半是Zl被h的资源腾Z用的I间?通常是显存,包括昑֍道内存中的AGP部分?font style="BACKGROUND-COLOR: #0a246a" color=#ffffff>D3DPOOL_DEFAULT 是从MANGED和SYSTEMMEM中分d来的。它指明了被攑օ此中的资源是用来被设备访问。注意,D3DPOOL_DEFAULT 没有意味着MANAGED或SYSTEMMEM会被选择用来存储资源Q这是一个独立的部分。放?font style="BACKGROUND-COLOR: #0a246a" color=#ffffff>D3DPOOL_DEFAULT 中的U理不可以被LOCK除非是动态纹理或是私有纹理。FOURCCQ驱动格式,Z讉K未锁定的U理Q我们必ȝIDirect3DDevice9::UpdateSurface , IDirect3DDevice9::UpdateTexture , IDirect3DDevice9::GetFrontBufferData , and IDirect3DDevice9::GetRenderTargetData .函数。显Ӟ对于许多应用E序来说QMANAGED是更好的选择?br>注意Q许多纹理是以私有的格式创徏的。运行时D3Dq不知道。是可以被加锁的。同时应该注意,不像U理Q交换链后台~冲区,渲染目标Q顶点缓Ԍ索引~冲是可以被加锁的。当讑֤丢失的时候,使用D3DPOOL_DEFAULT 创徏的资源必要在调用Reset之前释放。可以参看D3D的LostDevice. 当?font style="BACKGROUND-COLOR: #0a246a" color=#ffffff>D3DPOOL_DEFAULT 创徏资源Qƈ且显卡的内存有限的时候,MANAGED中的资源会被清除以释放_的内存来满需求?br>
D3DPOOL_MANAGED
Resources are copied automatically to device-accessible memory as needed. Managed resources are backed by system memory and do not need to be recreated when a device is lost. See Managing Resources for more information. Managed resources can be locked. Only the system-memory copy is directly modified. Direct3D copies your changes to driver-accessible memory as needed.
在MANAGED中的当有需要的时候,会被自动复制到设备的可访问内存。MANAGED资源在系l内存中是有备䆾的,于是当设备丢q时候,不需要重新创建。参?a href="mk:@MSITStore:D:\Program%20Files\Microsoft%20DirectX%20SDK%20(October%202006)\Documentation\DirectX9\directx9_c.chm::/managing_resources.htm">Managing Resources 。MANAGED资源可以被加锁,只有pȝ内存中的备䆾是直接被修改的。当有必要的时候,D3D复制你所修改的内容到pȝ可访问区
D3DPOOL_SYSTEMMEM
Resources are placed in memory that is not typically accessible by the Direct3D device. This memory allocation consumes system RAM but does not reduce pageable RAM. These resources do not need to be recreated when a device is lost. Resources in this pool can be locked and can be used as the source for a IDirect3DDevice9::UpdateSurface or IDirect3DDevice9::UpdateTexture operation to a memory resource created with D3DPOOL_DEFAULT .
被放|在SYSTMMEM中的资源是典型地不可?D直接讉K的。这U内存分配消耗系l的RAM但是不减RAM的可用页。在讑֤丢失的时候,q些资源不需要再ơ创建。在q个内存池中的资源可以被加锁Q可以被用来?strong>IDirect3DDevice9::UpdateSurface or IDirect3DDevice9::UpdateTexture L作以D3DPOOL_DEFAULT . 方式创徏的资?
D3DPOOL_SCRATCH
Resources are placed in system RAM and do not need to be recreated when a device is lost. These resources are not bound by device size or format restrictions. Because of this, these resources cannot be accessed by the Direct3D device nor set as textures or render targets. However, these resources can always be created, locked, and copied.
q种资源被放在系l的RAM中,讑֤丢失时候不用重新创建。这U资源不受设备大和格式的限制。ؓ此,q种资源不能被D3D讉KQ也不能讄为纹理或渲染目标。但是,q种资源L可以被创建,加锁和复制?
D3DPOOL_FORCE_DWORD
Forces this enumeration to compile to 32 bits in size. Without this value, some compilers would allow this enumeration to compile to a size other than 32 bits. This value is not used.
强制~译器?2位来~译q个枚D量。若没有q个|一些编译器允许这个枚举以?2位的方式~译。这个值未被用?/dd>
Remarks 评论
All pool types are valid with all resources. This includes: vertex buffers, index buffers, textures, and surfaces. 所有的内存池类型对所有的资源有效。包括:点~冲Q烦引缓ԌU理Q表面?br> 剩下的一些内容就是各U类型的资源对各U渲染目标的效性。参见SDK以下为FancyBit对D3DUSAGE的翻译,׃和D3DPOOL兌较强Q故贴在此里Q十分感谢FancyBit 他的主页是:http://hi.baidu.com/148332727 希望大家多多交流Q共同进?br>
]]> [转]关于Direct3D多窗口编E的一翻?/title> http://www.shnenglu.com/Leaf/archive/2009/08/10/92824.html大渊?/dc:creator>大渊?/author>Mon, 10 Aug 2009 09:32:00 GMT http://www.shnenglu.com/Leaf/archive/2009/08/10/92824.html http://www.shnenglu.com/Leaf/comments/92824.html http://www.shnenglu.com/Leaf/archive/2009/08/10/92824.html#Feedback 4 http://www.shnenglu.com/Leaf/comments/commentRss/92824.html http://www.shnenglu.com/Leaf/services/trackbacks/92824.html In DirectX 8, support for rendering to multiple windows is provided through the creation of additional swap chains. However, there are currently no examples of this in the SDK, and the documentation is a bit vague. This article is provided to fill the gaps, and will explain the steps you need to take to write an application that will render multiple views in separate windows.
在DX8中,对多H口的支持是通过创徏更多的Swap Chains来提供的。SDK中没有相关的例子而且文也只是泛泛而谈。这文章就是ؓ了解册个问题,它将向您展示应当如何一步步地实现在多个分离H口中渲染多个视图?/p>
Step 1 - Setting Up The Parent Frame
W一步:讄父框架窗?/p>
In an application with multiple views, we start with a top level frame that will contain child windows in its client area to display various views. Once the parent frame parent frame has been created, we create our Direct3D device interface, specifying windowed mode and setting the top level window handle as the focus window:
在多视图的应用程序中Q我们需要从最高层ơ的框架——这个框架将包含所有在他用户区之内的子视图H口——开始我们的旅程。当父框架创建的时候,我们需要创建Direct3D Device接口Qؓ其指定用窗口模式,而且讄q最高层ơ的H口句柄作ؓ“焦点H口”的句柄:
g_pD3D=Direct3DCreate8(D3D_SDK_VERSION);
if (!g_pD3D) return -1;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
// Use the current display mode. 使用当前的显C模?/p>
D3DDISPLAYMODE mode;
if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT , &mode))) {
SAFE_RELEASE(g_pD3D);
return -1;
}
d3dpp.BackBufferFormat = mode.Format;
d3dpp.BackBufferWidth = mode.Width;
d3dpp.BackBufferHeight = mode.Height;
d3dpp.EnableAutoDepthStencil=TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
// m_hWnd is handle to top level window m_hWnd是最高层H口的句?/p>
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice) ) ) {
SAFE_RELEASE(g_pD3D);
return -1;
}
Note that for simplicity the above code does not test depth format, instead choosing a fixed format. Your application should determine a compatible depth format for the format of the rendering target.
注意上面代码处于单考虑q没有去试深度~存的格式(Qdepth formatQ,而只是选择了一个确定的格式QD3DFMT_D16Q。您的程序应该ؓ需要渲染的Render Target选择一个可接受的深度缓存格式?/p>
The device has a frame buffer, which the child views will be rendered into, as well as a depth buffer which will be shared among the views. The frame buffer and depth buffer are sized to the full screen resolution, to allow for the fact that the window may later be resized. Otherwise, window size changes would require resetting the device and re-creating the swap chains.
Device都需要有帧缓存,q样子视图才能进行渲染,同时Q深度缓冲也应当被不同的视图q行׃n。~存和深度缓存都被设|ؓ全屏q大,以考虑到可能窗口会被改变大的情况。如果不的话Q窗口改变大的时候,需要Reset Device和重新创建Swap Chain?/p>
Step 2 - Setting Up View Windows
W二步:讄子视囄?/p>
Now we are ready to create our view windows, and associate them with swap chains that can be rendered to the device. Once the windows have been created, the following code generates a swap chain for the child window:
现在我们可以准备创徏我们的子H口也就是视囄口,q把它们与交换链兌以得他们可以被渲染到Device上。当H口创徏后,下面的代码将为子H口创徏一个交换链Q?/p>
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
// Use the current display mode. 使用当前的显C模?/p>
D3DDISPLAYMODE mode;
g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT , &mode);
d3dpp.BackBufferFormat = mode.Format;
// m_hWnd contains child window handle m_hWnd储存子窗口的句柄
d3dpp.hDeviceWindow=m_hWnd;
// m_pSwapChain is IDirect3DSwapChain * m_pSwapChain是一个IDirect3DSwapChain*对象
g_pd3dDevice->CreateAdditionalSwapChain(&d3dpp, &m_pSwapChain);
After executing this code, the m_pSwapChain variable will contain a pointer to an IDirect3DSwapChain interface, which contains a frame buffer corresponding to the client area of the child window. This process is performed for each view window, so that that there is a swap chain for each view window.
l过q些代码之后Qm_pSwapChain变量储存了IDirect3DSwapChain接口的指针,q个接口储存子H口视图区所对应的~冲?/p>
Step 3 - Rendering a View
W三步:渲染视图
Prior to rendering each view, we must direct the device to render to the appropriate frame buffer, using the SetRenderTarget() method. We pass the back buffer from the window's swap chain, while using the depth buffer that was originally created with the device:
在渲染每个视囄口之前,我们必须使得Device来渲染对应的帧缓Ԍq我们就需要用到SetRenderTargetҎ。我们向其中传入子窗口SwapChain交换铄后备~冲BackBufferQ以及用最开始跟着Device一起创建的深度~冲?/p>
LPDIRECT3DSURFACE8 pBack=NULL,pStencil=NULL;
m_pSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBack);
g_pd3dDevice->GetDepthStencilSurface(&pStencil);
g_pd3dDevice->SetRenderTarget(pBack,pStencil);
pBack->Release();
pStencil->Release();
Note that we release the stencil and backbuffer pointers after we use them, because the GetBackBuffer() and GetDepthStencilSurface() functions call AddRef() on these interfaces to increment their reference counters. Failing to release them would lead to a memory leak.
注意我们必须Release掉Stencil和BackBuffer的指针,因ؓGetBackBuffer和GetDepthStencilSurfaceq两个函数都会调用COM的AddRefҎQ来增加相应COM接口的引用计敎ͼ因此如果不删除它们,会D内存泄露?/p>
We are now ready to render the view. Rendering is performed within a scene in the normal manner, except that we call Present() on the swap chain interface rather than the device interface:
我们现在已经做好准备渲染视图H口了。渲染的Ҏ看v来和我们q_用的Ҏ差不多,只是有一点:我们现在需要调用Swap Chain的接口,而不是Device的接口?/p>
g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,0x00000000,1.0,0);
if (SUCCEEDED(g_pd3dDevice->BeginScene())) {
// rendering code goes here 渲染代码写在q里
g_pd3dDevice->EndScene();
}
m_pSwapChain->Present(NULL,NULL,NULL,NULL);
Step 4 - Handling Resize of Child Views
W四步,子窗口的Resize问题
DirectX will automatically deal with changes in the child view by using a stretch blit to present the swap chain if the dimensions have client area is not the same size as the swap chain's frame buffer. However, this may not be desirable, as it will cause aliasing if the client area is increased in size.
如果H口的视囑大小和SwapChain的大不一Q那么DirectX通过Stretch Blit来自动处理图像的伸羃变化。尽这可能q不令h期待Q因在视囑变大的时候将D囑փ的模p?/p>
]]> 转:U理矩阵 http://www.shnenglu.com/Leaf/archive/2009/08/07/92552.html大渊?/dc:creator>大渊?/author>Fri, 07 Aug 2009 09:05:00 GMT http://www.shnenglu.com/Leaf/archive/2009/08/07/92552.html http://www.shnenglu.com/Leaf/comments/92552.html http://www.shnenglu.com/Leaf/archive/2009/08/07/92552.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/92552.html http://www.shnenglu.com/Leaf/services/trackbacks/92552.html [转]U理矩阵
U理坐标变换
Direct3D提供了对生成的纹理坐标进行坐标变换的功能Q与点坐标变换相类|可以指定一?x4的纹理坐标变换矩阵,把它与生成的U理坐标怹Q然后将变换之后的纹理坐标输Direct3D渲染水Uѝ用纹理坐标变换可以对U理坐标q行诸如q移、旋转和~放{三l变换。纹理坐标变换对于生成一些特D效果是非常有用的,它不用直接修攚w点的U理坐标。例如可以通过一个简单的q移矩阵对纹理坐标进行变换,从而物体表面上的U理不断变换位置Q生动L果。纹理坐标自动生成在三维囑ŞE序中最q泛的应用是环境映射?/p>
可通过函数IDirect3DDevice9::SetTransform()来设|?x4的纹理坐标变换矩阵,它以D3DTS_TEXTURE0~ D3DTS_TEXTURE7作ؓW一个参敎ͼ表示讄U理?~7的纹理矩c下列代码对U理?讄了一个将U理坐标u、v~小到原来一半的U理矩阵Q?/p>
D3DXMATRIX mat; D3DXMatrixIdentity(&mat); mat._11 = 0.5f; mat._22 = 0.5f; pd3dDevice->SetTransform(D3DTS_TEXTURE0, &mat);
下面的代码将原来的纹理坐标^U(1.0, 1.0, 0Q个单位?/p>
D3DXMATRIX mat; D3DXMatrixIdentity(&mat); mat._41 = 1.0f; mat._42 = 1.0f; mat._43 = 0.0f; pd3dDevice->SetTransform(D3DTS_TEXTURE0, &mat);
CZE序通过下列代码对自动生成的U理坐标q行变换Q?/p>
// texture coordinate transform D3DXMATRIX mat_texture, mat_scale, mat_trans; D3DXMatrixIdentity(&mat_texture); D3DXMatrixScaling(&mat_scale, 0.5f, -0.5f, 1.0f); D3DXMatrixTranslation(&mat_trans, 0.5f, 0.5f, 1.0f); mat_texture = mat_texture * mat_scale * mat_trans; pd3dDevice->SetTransform(D3DTS_TEXTURE0, &mat_texture);
要看效果和完整代?br>M面这个主?br>
http://www.cnblogs.com/billwillman/articles/1232081.html 注:U理矩阵很好很强大。可以做单的_天空盒背景等效果?br>更ؓ严重的是Q还能做出流光效果,像《蜀门》上的服效果。?br>
]]> [转]D3D中的渲染到纹?/title> http://www.shnenglu.com/Leaf/archive/2009/07/24/91094.html大渊?/dc:creator>大渊?/author>Fri, 24 Jul 2009 15:38:00 GMT http://www.shnenglu.com/Leaf/archive/2009/07/24/91094.html http://www.shnenglu.com/Leaf/comments/91094.html http://www.shnenglu.com/Leaf/archive/2009/07/24/91094.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/91094.html http://www.shnenglu.com/Leaf/services/trackbacks/91094.html D3D中的渲染到纹?/font>
http://www.cnblogs.com/flying_bat/
渲染到纹理是D3D中的一wU技术。一斚wQ它很简单,另一斚w它很强大q能产生很多Ҏ效果?比如说发光效果,环境映射Q阴影映,都可以通过它来实现。渲染到U理只是渲染到表面的一个g伸。我们只需再加些东西就可以了。首先,我们要创造一个纹理,q且做好一些防范措施。第二步我们可以把适当的场景渲染到我们创徏的纹理上了。然后,我们把这个纹理用在最后的渲染上?br> ?main.cpp 首先我们得声明所需要的对象。当然我们需要一张用来渲染的U理。此外,我们q需要两个Surface对象。一个是用来存储后台~冲区,一个用来当U理的渲染对象。后面我再详l介l它们。另外我们还需要两个矩阵,一个是用来当纹理的投媄矩阵Q另一个是存储原来的矩c?br> LPDIRECT3DTEXTURE9 pRenderTexture = NULL; LPDIRECT3DSURFACE9 pRenderSurface = NULL,pBackBuffer = NULL; D3DXMATRIX matProjection,matOldProjection; 现在我们来创建纹理。前两个参数是纹理的宽度和高度,W三个参数是U理的多U渐q纹理序列参敎ͼ在这里是设ؓ1Q第四个参数非常重要而且必须设ؓD3DUSAGE_RENDERTARGETQ表明我们所创徏的纹理是用来渲染的。剩下的参数是指纹理格式,点~冲区的内存位置Q和一个指向纹理的指针。当U理是用来当渲染对象Ӟ点~冲区的内存位置必须设ؓD3D_DEFAILT?br> g_App.GetDevice()->CreateTexture(256,256,1,D3DUSAGE_RENDERTARGET,D3DFMT_R5G6B5,D3DPOOL_DEFAULT,&pRenderTexture,NULL); Z讉KU理内存对象Q我们需要一个Surface对象Q因为D3D中的U理是用q样的一个Surface来存储纹理数据的。ؓ了得到纹理表面的Surface,我们需要调用方法GetSurfaceLevel() 。第一个参数我们设?Q第二个参数Z个指向surface对象的指针?br> pRenderTexture->GetSurfaceLevel(0,&pRenderSurface); 下一步就是创Z个适合U理l数的投q阵,因ؓU理的横U|和后台缓冲区的不一栗?br> D3DXMatrixPerspectiveFovLH(&matProjection,D3DX_PI / 4.0f,1,1,100); 在我们的循环渲染之前Q我们必M存后台缓冲区和它的投qc?br> g_App.GetDevice()->GetTransform(D3DTS_PROJECTION,&matOldProjection); g_App.GetDevice()->GetRenderTarget(0,&pBackBuffer); 渲染循环函数可以分ؓ两个部分。第一部分是渲染到U理的过E。因此,渲染对象必须设ؓU理表面。然后我们就可以把东西渲染到q个对象上了。渲染到另一个表面上和正常地渲染到后台缓冲区差不多。只有一点不同,那就是先不调用PrensentQ)函数Q因为纹理上的内容ƈ不需要显C在屏幕上。象qx一P我们先要重置表面颜色~冲区,q且调用BeginSence()和EndSence()Ҏ。ؓ了能够适当的渲染,我们必须讄和纹理表面相W的投媄矩阵。否则最后的图象可能被扭?br> //render-to-texture g_App.GetDevice()->SetRenderTarget(0,pRenderSurface); //set new render target g_App.GetDevice()->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(100,100,100),1.0f,0); //clear texture g_App.GetDevice()->BeginScene(); g_App.GetDevice()->SetTexture(0,pPyramideTexture); D3DXMatrixRotationY(&matRotationY,fRotation); D3DXMatrixTranslation(&matTranslation,0.0f,0.0f,5.0f); g_App.GetDevice()->SetTransform(D3DTS_WORLD,&(matRotationY * matTranslation)); g_App.GetDevice()->SetTransform(D3DTS_PROJECTION,&matProjection); //set projection matrix g_App.GetDevice()->SetStreamSource(0,pTriangleVB,0,sizeof(D3DVERTEX)); g_App.GetDevice()->DrawPrimitive(D3DPT_TRIANGLELIST,0,4); g_App.GetDevice()->EndScene(); 渲染循环的第二部分就是渲染最后场景的q程Q也是昄到屏q上的过E)。渲染对象重新设为后台缓冲区Q投q阵重新设为原来的投媄矩阵。由于纹理已l准备好了,所以它和纹理层0相关联?br> //render scene with texture g_App.GetDevice()->SetRenderTarget(0,pBackBuffer); //set back buffer g_App.GetDevice()->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0); g_App.GetDevice()->BeginScene(); g_App.GetDevice()->SetTexture(0,pRenderTexture); //set rendered texture g_App.GetDevice()->SetTransform(D3DTS_WORLD,&matTranslation); g_App.GetDevice()->SetTransform(D3DTS_PROJECTION,&matOldProjection); //restore projection matrix g_App.GetDevice()->SetStreamSource(0,pQuadVB,0,sizeof(D3DVERTEX)); g_App.GetDevice()->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2); g_App.GetDevice()->EndScene(); g_App.GetDevice()->Present(NULL,NULL,NULL,NULL); 最后我们通过调用Release()Ҏ释放Surface对象?br> pRenderSurface->Release(); pRenderSurface = NULL; pBackBuffer->Release(); pBackBuffer = NULL; 渲染到纹理能让你做很多事情,但是你必L意一些限制。首先深度缓冲区必须L大于或等于渲染对象的大小。此外,渲染对象和深度缓冲区的格式必M致?/p>
]]> 关于材质~辑器的l构 http://www.shnenglu.com/Leaf/archive/2009/06/05/86846.html大渊?/dc:creator>大渊?/author>Fri, 05 Jun 2009 05:32:00 GMT http://www.shnenglu.com/Leaf/archive/2009/06/05/86846.html http://www.shnenglu.com/Leaf/comments/86846.html http://www.shnenglu.com/Leaf/archive/2009/06/05/86846.html#Feedback 2 http://www.shnenglu.com/Leaf/comments/commentRss/86846.html http://www.shnenglu.com/Leaf/services/trackbacks/86846.html 一直不知道~辑器的l构是如何的。有没有哪位大大耐心讲解一下。或者给一个结构图也行 谢谢啦! 试着用DXUT写了一下,初步军_以下功能Q由于不熟悉DXUTQ捣鼓了半天才弄出来 1、读取一个模型文?br>2、分析模型文Ӟ取得其subset个数Q取得每个subset的材?br>3、根据选中的subset调整其材?br>4、保存编辑好的材质到二进制文件中Q后~名暂定ؓ *.mtrl 效果囑֦?br>至于调节材质的那里,q有一U方案是调用shoosecolor面板Q那h较直观,但操作复杂。不知道是slider好还是面板好 暂时用slider 有谁能告诉我Q下拉列表那里,怎么能让他向上跑吗? 向下跑会遮住一些,不得不调整大?/p>
]]> l于使现了基于GPU计算的粒子效? http://www.shnenglu.com/Leaf/archive/2009/05/20/83430.html大渊?/dc:creator>大渊?/author>Tue, 19 May 2009 16:46:00 GMT http://www.shnenglu.com/Leaf/archive/2009/05/20/83430.html http://www.shnenglu.com/Leaf/comments/83430.html http://www.shnenglu.com/Leaf/archive/2009/05/20/83430.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/83430.html http://www.shnenglu.com/Leaf/services/trackbacks/83430.html q是看看C++吧,Z可持l发展~~~
]]> XFile的骨骼动?/title> http://www.shnenglu.com/Leaf/archive/2009/05/17/83232.html大渊?/dc:creator>大渊?/author>Sun, 17 May 2009 15:52:00 GMT http://www.shnenglu.com/Leaf/archive/2009/05/17/83232.html http://www.shnenglu.com/Leaf/comments/83232.html http://www.shnenglu.com/Leaf/archive/2009/05/17/83232.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/83232.html http://www.shnenglu.com/Leaf/services/trackbacks/83232.html 读SDK中那SkinMesh的源代码真费,到目前还对一些细节不明了Q但是ȝ是会单地应用那个CSinMeshcMQƈ生让Tiny动了h Tiny很出名哦Q是DX SDK的代a人。哈哈,看看他的照片吧`~ 哈哈Q感觉还不错Q增加了人物控制后,更安逸~~
]]> ZBuffer与WBuffer http://www.shnenglu.com/Leaf/archive/2009/04/24/80969.html大渊?/dc:creator>大渊?/author>Fri, 24 Apr 2009 09:49:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/24/80969.html http://www.shnenglu.com/Leaf/comments/80969.html http://www.shnenglu.com/Leaf/archive/2009/04/24/80969.html#Feedback 1 http://www.shnenglu.com/Leaf/comments/commentRss/80969.html http://www.shnenglu.com/Leaf/services/trackbacks/80969.html Depth-BufferQ深度缓存)有两U:Z-Buffer ?W-BufferQ这里讨两种深度~存的区别,以及如何在两者之间{换?br> w 的含?br> 3DI间点的坐标是(xQyQzQ,Z使矩阵乘法具有^Ud换的功效Q我们用4DI间中的点(xQyQzQwQ来表示3DI间中的点(x'Qy'Qz'Q,q两个不同空间点之间的关pLQ?br> x' = x / w y' = y / w z' = z / w 像这L四维I间点表CZl空间点Q或者说?n + 1 l空间点表示 n l空间点的方法叫?“齐次坐标表示?#8221;?br> 实际使用中,在模?>世界转换、世?>视图转换q程中,w 通常保持不变QL{于一Q这P齐次坐标的前三个分量是对应3DI间点的三个坐标分量。但是,l过投媄变换后,w 得C个比例|比如Q一般的透视投媄变换矩阵是: | W 0 0 0 | | 0 H 0 0 | | 0 0 Q 1 | | 0 0 -QZn 0 | 其中 Zn = q裁剪面 z 坐标 Zf = q裁剪面 z 坐标 W = 2 * Zn / 视口宽度 H = 2 * Zn / 视口高度 Q = Zf / (Zf - Zn) 点QxQyQzQ?Q乘以此矩阵Qw 便不再是一Q而对应的3DI间点坐标(x / wQy / wQz / wQ将出现一个羃放效果。同Ӟ因ؓ w 的值通常?z 坐标成正比(比如l过上面q个矩阵的变换,w 的值其实就?z 坐标的|Q所以经q投影变换,物体会生近大远的效果?br> Z-Buffer ?W-Buffer 的区?br> 单的_z-buffer ?w-buffer 的区别就是前者保存的是点?z 坐标Q而后者保存的是点?w 坐标?br> 具体的说Q两者因Z存的值有不同的含义,所以表现出来的实际效果也会有差别?br> z-buffer 保存的是l过投媄变换后的 z 坐标Q前面说q,投媄后物体会产生q大q小的效果,所以距ȝ睛比较近的地方,z 坐标的分辨率比较大,而远处的分L率则比较,换句话说Q投影后?z 坐标在其值域上,对于d眼睛的物理距d化来_不是U性变化的Q即非均匀分布Q,q样的一个好处是q处的物体得C较高的深度分辨率Q但是远处物体的深度判断可能会出错?br> w-buffer 保存的是l过投媄变换后的 w 坐标Q?w 坐标通常跟世界坐标系中的 z 坐标成正比,所以变换到投媄I间中之后,其g然是U性分布的Q这h处还是近处的物体Q都有相同的深度分L率,q是它的优点Q当Ӟ~点是不能用较高的深度分L率来表现q处的物体?br> 从硬件实现角度来_几乎所有的g3D加速卡都支?z-bufferQ?w-buffer 的支持没?z-buffer 那么q泛。另外,早期?Direct3D 版本看v来也不支?w-buffer?br> Z-Buffer ?W-Buffer 之间的{?br> Ҏ上面的矩阵变换,可以很容易的导出?w-buffer 转换?z-buffer 的公式: zDepth = Q * ( wDepth - Zn ) / wDepth = Zf / ( Zf - Zn ) * ( wDepth - Zn ) / wDepth q个转换公式有什么用处?举个例子Q?DS MAX 使用的是 w-bufferQ如果从 3DS MAX 中导出深度信息到 Direct3D 中,作ؓ预渲染的背景使用Q就有可能用C面这个{换。当Ӟ如果?D3D 中?w-bufferQ问题就不大了,但是如果使用 z-bufferQ不l过q样的{换,渲染l果׃出错?/p>
]]> 通过高度囄成地形时候出现的p画面 http://www.shnenglu.com/Leaf/archive/2009/04/24/80968.html大渊?/dc:creator>大渊?/author>Fri, 24 Apr 2009 09:43:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/24/80968.html http://www.shnenglu.com/Leaf/comments/80968.html http://www.shnenglu.com/Leaf/archive/2009/04/24/80968.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/80968.html http://www.shnenglu.com/Leaf/services/trackbacks/80968.html q有一个带有金属感?#8220;艺术?#8221; 真的好神奇~~ 不过呢,我那地Ş生成q是没实玎ͼ很囧~~
]]> W一ơ实现水面渲染(U理动画ҎQ?/title> http://www.shnenglu.com/Leaf/archive/2009/04/22/80705.html大渊?/dc:creator>大渊?/author>Wed, 22 Apr 2009 04:26:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/22/80705.html http://www.shnenglu.com/Leaf/comments/80705.html http://www.shnenglu.com/Leaf/archive/2009/04/22/80705.html#Feedback 1 http://www.shnenglu.com/Leaf/comments/commentRss/80705.html http://www.shnenglu.com/Leaf/services/trackbacks/80705.html 只是q没有实现倒媄Q下ơ再做?br> 虽然大虾很多Q但像我q样自己捣鼓的也同样存在Q那我就说说怎么实现的吧Q也Z理清自己的思\
我说说我的实现方法吧
std::vector<IDirect3DTexture9 *> vecTexture(0); //q个是用来存储我们的几十张U理?/div>
先把他们全部加蝲q去?/div>
然后我们先画一个矩形(略)
然后我们Ҏ下面q个来动态切换纹?/div>
Direct3DTexture9* Texture = NULL;
float timeElapsed = 0;
DWORD dwFrameSpeed = 0;
timeElapsed += timeDelta*FrameSpeed;//timeDelta是两ơ渲染的间隔旉
if(timeElapsed>vecTexture.size()) timeElapsed = 0; Texture = vecTexture[(int)timeElapsed];
接下来我们就可以讄U理Q然后渲染那个矩形就可以了?/div>
如果要水呈透明效果Q只要和地Şq行ALPHA混合p了,混合参数自己多调两下?/div>
]]>
为DEMO加入雑效果 http://www.shnenglu.com/Leaf/archive/2009/04/20/80522.html大渊?/dc:creator>大渊?/author>Mon, 20 Apr 2009 03:58:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/20/80522.html http://www.shnenglu.com/Leaf/comments/80522.html http://www.shnenglu.com/Leaf/archive/2009/04/20/80522.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/80522.html http://www.shnenglu.com/Leaf/services/trackbacks/80522.html 雑效果 首先来看看我们可以设|哪些参?br>1、D3DFOGSTART、D3DFOGEND表示雄起始和结束距?br>2、D3DFOGDENSITY 雄度 3、D3DFOGCOLOR 雄颜色 4、D3DFOGTABLEMODE、D3DFOGVERTEXMODE 雄模式Q第一个ؓ像素雑Q第二个为顶炚w?/p>
首先看看雑的方E?/p>
Color = f * Color(scene) + (1-f) * color(fog)
Color(scene):背景?br>Color(fog): 雾色 f:雑参数Q随观察点的距离的增大而减,从而可知最后得到的颜色Q当观察点越q时Q雾色占的比例越大?/p>
雾有四种方式 D3DFOG_NONE 用雑效果 D3DFOG_EXP 雑效果随指数增?f = 1/(e^density) D3DFOG_EXP2 同上Q不q公式变?f = 1/(e^(density^2)) D3DFOG_LINEAR U性雾 f = (end-d)/(end-start) d 为当前计点与观察点距离
现在我们来看如何实现雑 首先开启雾化效?br>Device->SetRenderState(D3DRS_FOGENABLE,true); 然后我们要设|雾化的模式和公?br>Device->SetRenderState(DEDRS_FOGTABLEMODE,D3DFOG_LINEAR); q里我将其设|成了像素雾和线性,同样可以其换成上面介绍的其它模式和公式 接下来我们就要设|雾化参C Device->SetRenderState(D3DRS_FOGCOLOR,oxffffffff);//讄成白?/p>
讄start end float start= 50,end = 400; Device->SetRenderState(D3DRS_FOGSTART,*(DWORD*)&start); Device->SetRenderState(D3DRS_FOGEND,*(DWORD*)&end); 讄度 float density = 0.001f;//0.0 -- 1.0 Device->SetRenderState(D3DRS_FOGDENSITY,*(DWORD*)&density);
q样,我们的设|就完了,只要雾化设|放入我们渲染场景中,可以看到雾化效果了. 但应该注意以下几?br>-----------------------------------------line A B C \ | / \ / \ | / \ / \ d / \ / \ | / \ / P ------------------------------------------ 雑效果是以刚刚上面讲的 d 作ؓ计算标准,所?我们从P点看到A ,B ,C三点的雾化效果是一L,而按常理,A ,C的雾应该更浓才对. 很显?q让我们惛_,D3D会有对应的处理办? D3D提供了基于发散的雑效果,雑随观察点的距d大而增?像点光?不过,q要求我们的g支持,所以在讄前应该检?br>D3DCAPS9 caps; Device->GetDeviceCaps(&caps);
if(caps.RasterCaps&D3DPRASTERCAPS_FOGRANGE) Device->SetRenderState(D3DRS_RANGEFOGENABLE,true);
把这个增加到雑讄中即可~~~
已经12点了,估计人有Ҏ,也讲不明白些什么东西了,到此为止
]]> 透明U理和^面阴隐DEMO http://www.shnenglu.com/Leaf/archive/2009/04/19/80444.html大渊?/dc:creator>大渊?/author>Sun, 19 Apr 2009 06:40:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/19/80444.html http://www.shnenglu.com/Leaf/comments/80444.html http://www.shnenglu.com/Leaf/archive/2009/04/19/80444.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/80444.html http://www.shnenglu.com/Leaf/services/trackbacks/80444.html 加入了媄子后的效?br> 渲染树目U理之前Q进行如下设|?br>Device->SetRenderState(D3DRS_ALPHABLENDENABLE,true); Device->SetRenderState(D3DRS_SCRBLEND,D3DBLEND_SCRALPHA); Device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSCRALPHA); Device->SetRenderState(D3DRS_ALPHATESTENABLE,true); Device->SetRenderState(D3DRS_ALPHAREF,0x0); Device->SetRenderState(D3DRS_ALPHAFUNC,D3DCMP_GREATEREQUAL); 渲染阴媄的时候,使用的是同一U理Q但需q行如下讄 Device->SetRenderState(D3DRS_SCRBLEND,D3DBLEND_INVSCRALPHA); 调了一下午Q才调出q阴影,隑־呀~~`
]]> 3D DEMO的初步实?/title> http://www.shnenglu.com/Leaf/archive/2009/04/18/80354.html大渊?/dc:creator>大渊?/author>Sat, 18 Apr 2009 07:42:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/18/80354.html http://www.shnenglu.com/Leaf/comments/80354.html http://www.shnenglu.com/Leaf/archive/2009/04/18/80354.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/80354.html http://www.shnenglu.com/Leaf/services/trackbacks/80354.html D3DMULTISAMPLE_0_SAMPLES
D3DMULTISAMPLE_4_SAMPLES l于成功地把天空盒,公告板,MESHQ纹理等一L在了一个工E中Q哈哈,虽然比较白啦Q但q是很有成就感?
]]> q面阴隐Q用模版~存防止二次融合Q?/title> http://www.shnenglu.com/Leaf/archive/2009/04/18/80325.html大渊?/dc:creator>大渊?/author>Sat, 18 Apr 2009 02:02:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/18/80325.html http://www.shnenglu.com/Leaf/comments/80325.html http://www.shnenglu.com/Leaf/archive/2009/04/18/80325.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/80325.html http://www.shnenglu.com/Leaf/services/trackbacks/80325.html 而对于一个三l物体来_当多个部分投影到q面上时Q会产生叠加效果Q导致某一部位颜色较深Q而此时我们可以通过模版~存来防止二ơ融合,从而避免这cȝ象的产生?br>Device->Clear(0,0,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,0xfff0000,1.0,0); Device->SetRenderState(D3DRS_STENCILENABLE,true); Device->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_EQUAL); Device->SetRenderState(D3DRS_STENCILREF,0x0); Device->SetRenderState(D3DRS_STENCILMASK,0xffffffff); Device->SetRenderState(D3DRS_STENCILWRITEMASK,0xffffffff); Device->SetRenderState(D3DRS_STENCILZFAIL,D3DSTENCILOP_KEEP); Device->SetRenderState(D3DRS_STENCILFAIL,D3DSTENCILOP_KEEP); Device->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_INCR); 首先开启模?测试规则设|ؓ"相等",模版参考设|ؓ0,p|时候不更改,成功的时候增?. ׃我们已经模版缓存清0 ,于是,当第一ơ写入模版的时?试L成功?模版值加1.而当W二ơ写入的时?模版g模版参考g相等,试便会p|,从而阻止了再次写入~存. Device->SetRenderState(D3DRS_ALPHABLENDENABLE,true); Device->SetRenderState(D3DRS_SCRBLEND,D3DBLEND_SCRALPHA); Device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCAPHA); Device->SetRenderState(D3DRS_ZENABLE,false); //使用D3DXMatrixShadow(&S,&linghtDirection,&groundplane); //S为最后输出的矩阵,然后是光U方?然后是要l制阴媄的^?br> //l制 //最后做收尾工作 Device->SetRenderState(D3DRS_ZENABLE,true); Device->SetRenderState(D3DRS_ALPHABLENDENABLE,false); Device->SetRenderState(D3DRS_STENCILENABLE,false);
]]> 从Xfile加蝲MESH模型 http://www.shnenglu.com/Leaf/archive/2009/04/18/80326.html大渊?/dc:creator>大渊?/author>Sat, 18 Apr 2009 02:02:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/18/80326.html http://www.shnenglu.com/Leaf/comments/80326.html http://www.shnenglu.com/Leaf/archive/2009/04/18/80326.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/80326.html http://www.shnenglu.com/Leaf/services/trackbacks/80326.html 首先介绍ID3DXBuffer 接口 此类型有两个Ҏ LPVOID ID3DXBuffer::GetBufferPointer();//q回指向~存中数据v始位|的指针 DWORD ID3DXBuffer::GetBufferSize()//q回~存的大?单位为字?br> 下面函数用于创徏一个空的ID3DXBuffer对象 HRESULT D3DXCreateBuffer(DWORD NumBytes, LPD3DBUFFER *ppBuffer);
再来介绍一个D3DXMATRIALl构 typedef struct D3DXMATERIAL { D3DMATERIAL9 Mat3D; //存储材质 LPSTR pTextureFilename;//存储U理路径?br>}D3DXMATERIAL; 再来看看一个重要的函数 HRESULT D3DXLoadMeshFromX( LPCSTR pFilename,//文g?br>DWORD Options,//创徏|格时所使用的标?br>LPDIRECT3DDEVICE9 *pDevice, LPD3DXBUFFER *ppAdjacency,//L表信?br>LPD3DXBUFFER *ppMaterials,//材质和纹理信? D3DXMATRIALl构 LPD3DXBUFFER *ppEffectInstances,// PDWORD pNumMaterials,//材质数目 LPD3DXMESH *ppMesh//q回填充好的Mesh对象 }; 下面是一个实用的例子 class MyMesh { ........... private: ID3DXMesh* Mesh = 0; std::vector<D3DMATERIAL9> Mtrls(0); std::vector<IDirect3DTexture9*> Textures(0); ...... }; bool MyMesh::LoadMyMesh( LPCSTR pName,IDirect3DDevice9* Device) { ID3DXBuffer* adjBuffer = 0; ID3DXBuffer* mtrlBuffer = 0; DWORD numMtrls = 0; HRESULT hr = D3DXLoadMeshFromX(pName,D3DXMESH_MANAGED,Device,&adjBuffer,&mtrlBuffer,0,&numMtrls,&Mesh); if(FAILED(hr)) { ::MessageBox(NULL,"D3DXLoadFromX() - FAILED",0,0); return false; } if(mtrlBuffer!=0&&numMtrls!=0) //如果有材?br> { D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();//GetBufferPointer() Z适合各种cd,因ؓq回VOID*cd 需要强制{?br> for(int i = 0;i<numMtrls;i++) { //得到的材质没有环境光,我们得自己加?让它{于漫射?br> mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse; Mtrls.push_back(mtrls[i].MatD3D); } if(mtrls[i].pTextureFilename!=0)//U理不ؓI?br> IDirect3DTexture9* tex = 0; D3DXCreateTextureFromFile(Device,mtrls.pTextureFilename,&tex); Textures.push_back(tex); } else { Textures.push_back(0); } } adjBuffer->Release(); mtrlBuffer->Release(); return true; } //加蝲好后,讄好矩?可以进行绘制了.׃Mesh是分多子集的,所以要一个一个渲?br>void MyMesh::DrawMyMesh(IDreict3DDevice9* Deivice) { for(int i =0;i<Mtrls.size();i++) { Device->SetMaterial(&Mtrls[i]); Device->SetTexture(0,Textures[i]); Mesh->DrawSubset(i); } }
]]> 用模版缓存实现镜面效?/title> http://www.shnenglu.com/Leaf/archive/2009/04/18/80324.html大渊?/dc:creator>大渊?/author>Sat, 18 Apr 2009 02:01:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/18/80324.html http://www.shnenglu.com/Leaf/comments/80324.html http://www.shnenglu.com/Leaf/archive/2009/04/18/80324.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/80324.html http://www.shnenglu.com/Leaf/services/trackbacks/80324.html 首先模版缓存清I?br>Device->Clear( 0, 0, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, //清空模版~存Q深度缓?br> 0ff000000,//颜色 1.0f, 0)//清空后的模版~存?br> //接下来就是模版缓存进行设|?br>Device->SetRenderState(D3DRS_STENCILENABLE,true) //开启模版缓?br>Device->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_ALWAYS);//模版测试设|ؓL成功Q因为我们是在画镜面Q不镜面如何,都要M?br>Device->SetRenderState(D3DRS_STENCILREF,0x1);//讄模版参考gؓ1Q这样将会用0x1来标记镜面区?br>Device->SetRenderState(D3DRS_STENCILMASK,0xffffffff);//讄模版掩码Q?xffffffff表示不屏蔽Q何位 Device->SetRenderState(D3DRS_STENCILWRITEMASK,0xffffffff)//模版写掩?br>Device->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_REPLACE);//当模版测试成功时Q便用模版参考|0x1Q去替换~存中的?br>Device->SetRenderState(D3DRS_ZWRITEENALBE,false);//关闭深处~存的写功能Q以侉K止对q存的更改 Device->SetRenderState(D3DRS_ALPHABLENDENABLE,true);//开启ALPHA混合功能 Device->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ZERO);//源融合因子讄为(0Q?Q?Q?Q; Device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE);//目标融合因子设|ؓ(1,1,1,1); //在这里画镜面,此时的镜面会通过模版~存q行l制,q且模版~存中的代表镜面的部分被标记?x1,而其它区域ؓ0; //接下来就要绘制我们的物体?br>Device->SetRenderState(D3DRS_ZWRITEEABLE,true);//重新开启ZWRITE Device->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_EQUAL);//模版测试规则设|ؓ相等 Device->SetRenderState(D3DRS_STENCILZFAIL,D3DSTENCILOP_KEEP); Device->SetRenderState(D3DRS_STENCILFAIL,D3DSTENCILOP_KEEP);//q两排表C如果深度和模版试p|,则不Ҏ版中的内容作更改 Device->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_KEEP);//若测试成功也不对其作更改 //使用D3DXMatrixReflect(&R,&plane);求出物体的镜?其中plane为镜面^? //若此时绘L们会看不到物?因ؓ物体的深度大于镜面的深度,于是我们要清I深度缓?br> Device->Clear(0,0,D3DCLEAR_ZBUFFER,0,1.0f,0); //Z能达到物体在镜子中的效果,我们依然要用到ALPHA混合 Device->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR);//(Rd,Gd,Bd,Ad) Device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ZERO);//(0,0,0,0); //׃物体在镜面中的显CZؓ物体的像,于是我们要变攚w像绘制时的背面消隐模?br>Device->SetRenderState(D3DRS_CULLMODE,D3DCULL_CW);//时?br> 最后的工作是l制Z的物?然后关闭开启的功能,q恢复消隐模?br>Device->SetRenderState(D3DRS_ALPHABLEND,false); Device->SetRenderState(D3DRS_STENCILENABLE,false); Device->SetRenderState(D3DRS_CULLMODE,CCW);//恢复默认(逆时?
]]> 透明U理 http://www.shnenglu.com/Leaf/archive/2009/04/18/80322.html大渊?/dc:creator>大渊?/author>Sat, 18 Apr 2009 02:00:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/18/80322.html http://www.shnenglu.com/Leaf/comments/80322.html http://www.shnenglu.com/Leaf/archive/2009/04/18/80322.html#Feedback 0 http://www.shnenglu.com/Leaf/comments/commentRss/80322.html http://www.shnenglu.com/Leaf/services/trackbacks/80322.html 对于一些纹理,我们不要求全部显C出来,如用公告板显C的一|的纹理,此时p求让背景不显C出来,只显C树的部分?br>//首先囄的背景要处理成透明Q显然我们看到是透明的了Q但是对于计机来说Q同样会透明背景后的物品遮住?br>//此时p在渲染纹理前对其q行ALPHA混合 /*
alpha试Ҏ当前像素是否满alpha试条gQ即是否辑ֈ一定的透明度)来控制是否绘制该像素Q图形程序应用alpha试可以有效地屏蔽某些像素颜艌Ӏ与alpha混合相比Qalpha试不将当前像素的颜色与颜色~冲Z像素的颜色合,像素要么完全不透明Q要么完全透明。由于无需q行颜色~冲区的L作和颜色混合Q因此alpha试在速度上要优于alpha混合?br>
比如一|Q我们将它的背景ALPHAD|ؓ于1?Q那么,我们可以ALPHAREF 讄?? ?x000000ff 然后ALPHAFUNC 讄为GREATEREQUAL Q?gt;=Q?所以,只有当ALPHA值大于等?的部份被渲染Q这h的背景就不用MQ?br>*/ g_pMyd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );//开启ALPHA混合功能 g_pMyd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);//讄源合因子ؓQAs,As,As,As) g_pMyd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);//讄目标混合因子为(1-As,1-As,1-As,1-As);
g_pMyd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );//开启ALPHA试功能 g_pMyd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x0f );//讄ALPHA试参考?br> g_pMyd3dDevice->SetRenderState( D3DRS_ALPHAFUNC,D3DCMP_GREATEREQUAL );//讄APLHA试比较规则 //在此处加载纹理和渲染 在渲染完毕后Q不要忘了关闭开启的功能 g_pMyd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE ); g_pMyd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
]]> 公告?/title> http://www.shnenglu.com/Leaf/archive/2009/04/18/80321.html大渊?/dc:creator>大渊?/author>Sat, 18 Apr 2009 01:59:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/18/80321.html http://www.shnenglu.com/Leaf/comments/80321.html http://www.shnenglu.com/Leaf/archive/2009/04/18/80321.html#Feedback 1 http://www.shnenglu.com/Leaf/comments/commentRss/80321.html http://www.shnenglu.com/Leaf/services/trackbacks/80321.html 开始只是知道公告板是不管摄相机怎么转,对象L在摄相机前面。这是公告板中的一U,也是最常见的一U?br>如游戏中人物、NPC的名字等Q就是用贴图技术,然后再用公告板,q样不管玩家怎么转动视角QL能看见名字正对着自己Q?br>l于自己实现了一回公告板函数 void Billboard(IDirect3DDevice9* Device,D3DXMATRIX &matInput,D3DXMATRIX &matOutput) { //========================= //公告板技?br> //========================== D3DXMATRIX matBillboard,matView; D3DXMatrixIdentity(&matBillboard);//初始化ؓ单位矩阵 Device->GetTransform(D3DTS_VIEW,&matView);//取得观察矩阵 matBillboard._11 = matView._11;//赋?br> matBillboard._13 = matView._13; matBillboard._31 = matView._31; matBillboard._33 = matView._33;
D3DXMatrixInverse(&matBillboard,NULL,&matBillboard);//求其逆矩?br> matOutput = matBillboard * matInput; //公告板结?br>} 函数说明Q?br>q回|void Device 是一个IDirect3DDevice9* cd的参?br>&matInput 是一个D3DXMATRIX cd的参? &matOutput 是一个D3DXMATRIX cd的参?br> 功能Q将传入的matInput 矩阵Q与摄相机矩늚Look方向矩阵怹Q得到matOutput 用法 D3DXMATRIX matWorld; D3DXMatrixIdentity(&matWorld); D3DXMatrixTranslation(&matWorld,1,1,1); //对matWorld q行必要的变?如translation Qrotation 之类的?br> Billboard(g_pDevice,matWorld,matWorld); g_pDevice->SetTransform(D3DTS_WORLD,&matWorld); 接下来就可以q行材料Q纹理设|、绘制等工作了! 虽然是很单的技术,但却很实用?/p>
]]> D3D API调用消耗表 http://www.shnenglu.com/Leaf/archive/2009/04/17/80229.html大渊?/dc:creator>大渊?/author>Fri, 17 Apr 2009 05:21:00 GMT http://www.shnenglu.com/Leaf/archive/2009/04/17/80229.html http://www.shnenglu.com/Leaf/comments/80229.html http://www.shnenglu.com/Leaf/archive/2009/04/17/80229.html#Feedback 3 http://www.shnenglu.com/Leaf/comments/commentRss/80229.html http://www.shnenglu.com/Leaf/services/trackbacks/80229.html
API Call
Average number of Cycles
SetVertexDeclaration
6500 - 11250
SetFVF
6400 - 11200
SetVertexShader
3000 - 12100
SetPixelShader
6300 - 7000
SPECULARENABLE
1900 - 11200
SetRenderTarget
6000 - 6250
SetPixelShaderConstant (1 Constant)
1500 - 9000
NORMALIZENORMALS
2200 - 8100
LightEnable
1300 - 9000
SetStreamSource
3700 - 5800
LIGHTING
1700 - 7500
DIFFUSEMATERIALSOURCE
900 - 8300
AMBIENTMATERIALSOURCE
900 - 8200
COLORVERTEX
800 - 7800
SetLight
2200 - 5100
SetTransform
3200 - 3750
SetIndices
900 - 5600
AMBIENT
1150 - 4800
SetTexture
2500 - 3100
SPECULARMATERIALSOURCE
900 - 4600
EMISSIVEMATERIALSOURCE
900 - 4500
SetMaterial
1000 - 3700
ZENABLE
700 - 3900
WRAP0
1600 - 2700
MINFILTER
1700 - 2500
MAGFILTER
1700 - 2400
SetVertexShaderConstant (1 Constant)
1000 - 2700
COLOROP
1500 - 2100
COLORARG2
1300 - 2000
COLORARG1
1300 - 1980
CULLMODE
500 - 2570
CLIPPING
500 - 2550
DrawIndexedPrimitive
1200 - 1400
ADDRESSV
1090 - 1500
ADDRESSU
1070 - 1500
DrawPrimitive
1050 - 1150
SRGBTEXTURE
150 - 1500
STENCILMASK
570 - 700
STENCILZFAIL
500 - 800
STENCILREF
550 - 700
ALPHABLENDENABLE
550 - 700
STENCILFUNC
560 - 680
STENCILWRITEMASK
520 - 700
STENCILFAIL
500 - 750
ZFUNC
510 - 700
ZWRITEENABLE
520 - 680
STENCILENABLE
540 - 650
STENCILPASS
560 - 630
SRCBLEND
500 - 685
Two_Sided_StencilMODE
450 - 590
ALPHATESTENABLE
470 - 525
ALPHAREF
460 - 530
ALPHAFUNC
450 - 540
DESTBLEND
475 - 510
COLORWRITEENABLE
465 - 515
CCW_STENCILFAIL
340 - 560
CCW_STENCILPASS
340 - 545
CCW_STENCILZFAIL
330 - 495
SCISSORTESTENABLE
375 - 440
CCW_STENCILFUNC
250 - 480
SetScissorRect
150 - 340
使用D3DQ我们就得知道常用的API的消耗,才能够方便我们优化自q渲染器。这里给Z常用API的消耗表Q可以有一个直观的比较?br>q个表也可以在D3D SDK文?Accurately Profiling Direct3D API Calls (Direct3D 9) 一文中扑ֈ
]]>
99þ99þþƷƬ
|
99þ99þþþƷ |
ӰԺ˾þ |
þۺϺݺۺϾþ |
һɫþۺϺݺ |
ҹƷþþþþӰ777
|
þþþAVվ |
ݺɫþþһ |
㽶þҹɫƷС˵ |
þۺɫˮ99ž
|
ƷŷƬþùŷ... |
Ʒþþþþ |
þۺϾɫŷۺϺݺ |
˾Ʒþþùһ
|
þþþùպƷվ |
Ʒþþþһ
|
һɫþ88ձȡۺ |
þùAV䡪ٶ |
þ99Ʒþþþþ |
ھƷþþþþĻ |
պĻþ |
þþƷֻо99Ʒ |
TOKYOۺϾþþƷ |
88þþƷһëƬ |
þֻоƷ߹ۿ |
ݾƷŮ˾þþþþ |
AVþò |
þˬˬƬAV
|
˾þþƷ |
ݺݾþ
|
þ99Ʒ99þ6 |
ƷŮþþþþ2018 |
þˬ˰ |
þþۺ㽶ۺ |
91˾þþƷַ |
˸ŮѲžþþ |
Ʒþþþù |
Ʒ99þþþþ |
Ʒžžžþþž |
þùƷ-Ʒ |
þùƷ |
D3DUSAGE_RENDERTARGET 此纹理或表面作ؓ一个渲染目标被创徏Q只能分配在D3DPOOL_DEFAULT的显卡内存中
D3DUSAGE_AUTOGENMIPMAP 资源会自动生成多_ֺQ多层次l节Q纹?mipmap)(Direct3D 9). 不支持volume textures 和深度表?深度U理Q凹凸脓图). q个usage 不支持系l内存中的资?用D3DPOOL_SYSTEMMEM参数创徏的资?.
D3DUSAGE_DEPTHSTENCIL 此资源将会是一个深度缓Ԍ只能用D3DPOOL_DEFAULT分配.
D3DUSAGE_DMAP The resource will be a displacement map. Q?Q?
D3DUSAGE_DONOTCLIP 点~冲区内容不需要裁? 当被渲染的缓冲区讄此位?D3DRS_CLIPPING 渲染器状态必设|ؓfalse.
D3DUSAGE_DYNAMIC 讄此位表示点~冲需要动态的内存使用。这寚w动程序很有用因ؓ它得驱动程序可以决定把~冲区放在哪里。一般的Q静态顶端缓冲放|在昑֭儿动态缓冲防止在AGP内存中。注意如果你没有指定该标志位Q那么顶点缓冲默认就是静态的?
D3DUSAGE_DYNAMIC会被强制讄Q当D3DLOCK_DISCARD ?D3DLOCK_NOOVERWRITE 锁标志一起? 因此, D3DLOCK_DISCARD and D3DLOCK_NOOVERWRITE 只对使用 D3DUSAGE_DYNAMIC创徏的顶点缓冲有?更多参见Managing Resources (Direct3D 9).
更多关于动态顶点缓冲的信息Q参见Performance Optimizations (Direct3D 9).
D3DUSAGE_DYNAMIC ?D3DPOOL_MANAGED不兼? See D3DPOOL.
U理也可以用D3DUSAGE_DYNAMIC.当然, 托管的纹理不能?D3DUSAGE_DYNAMIC. 关于动态纹理的信息Q参?Using Dynamic Textures.
D3DUSAGE_WRITEONLY
用于点~冲和烦引缓?
通知pȝE序只想点和烦引缓冲中写入数据。用这个标记可以让驱动E序选择让写入和渲染操作效率最佳的内存分配方式。启用此Ҏ后试从内存缓冲中d数据的操作会p|。只对用D3DPOOL_DEFAULT分配在显存中的数据有效?
D3DUSAGE_RTPATCHES Set to indicate that the vertex buffer is to be used for drawing high-order primitives. Q?Q?
D3DUSAGE_NONSECURE 允许创徏的表面被另一个程序用一个无安全性的׃n句柄打开Q只在D3D9EX使用
D3DUSAGE_TEXTAPI D3D9EX专用 ?
用于Q?
IDirect3DDevice9::CreateCubeTexture
IDirect3DDevice9::CreateDepthStencilSurface
IDirect3DDevice9::CreateIndexBuffer
IDirect3DDevice9::CreateOffscreenPlainSurface
IDirect3DDevice9::CreateRenderTarget
IDirect3DDevice9::CreateTexture
IDirect3DDevice9::CreateVertexBuffer
IDirect3DDevice9::CreateVolumeTexture
D3DXCreatexxx texturing functions