`
jgsj
  • 浏览: 964570 次
文章分类
社区版块
存档分类
最新评论

DirectX 操作.X格式文件总结

 
阅读更多

Loading an .X File导入.X格式的文件

这个是微软格式的模型文件。存储各种任务,树木,花草等模型信息的文件,可以导入并显示与程序屏幕中,导入函数:

HRESULT D3DXLoadMeshFromX(
      LPCSTR pFilename,
      DWORD Options,
      LPDIRECT3DDEVICE9 pDevice,
      LPD3DXBUFFER *ppAdjacency,
      LPD3DXBUFFER *ppMaterials,
      LPD3DXBUFFER* ppEffectInstances,
      PDWORD pNumMaterials,
      LPD3DXMESH *ppMesh
);
例子:
// Step 1: Load the .X file from file into a system memory mesh.

ID3DXMesh* meshSys      = 0;
ID3DXBuffer* adjBuffer  = 0;
ID3DXBuffer* mtrlBuffer = 0;
DWORD numMtrls          = 0;

HR(D3DXLoadMeshFromX(filename.c_str(), D3DXMESH_SYSTEMMEM,
      gd3dDevice, &adjBuffer, &mtrlBuffer, 0, &numMtrls, &meshSys));

测试顶点单位法向量 Vertex Normals

当一个.X 文件导入之后,ID3DXMesh的顶点属性一定有位置,但是不一定有单位向量,纹理坐标,我们可以手动地添加这些信息。可以colone到一个新的ID3DXMesh中,指定格式为我们想要的格式,就可以添加相应的属性了。

也可以把拥有不同属性的.x文件统一格式化成有相同格式属性的Mesh,然后统一渲染,可以加快渲染速度。

如下面代码检查是否有单位化向量,没有就才加,以免覆盖:

// Step 2: Find out if the mesh already has normal info.

D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE];
HR(meshSys->GetDeclaration(elems));

bool hasNormals = false;
for(int i = 0; i < MAX_FVF_DECL_SIZE; ++i)
{
      // Did we reach D3DDECL_END() {0xFF,0,D3DDECLTYPE_UNUSED, 0,0,0}?
      if(elems[i].Stream == 0xff)
            break;

      if( elems[i].Type == D3DDECLTYPE_FLOAT3 &&
            elems[i].Usage == D3DDECLUSAGE_NORMAL &&//如果我们找到一个3D顶点有normal usage
            elems[i].UsageIndex == 0 )//且其索引为0,那么就可以判定单位化向量存在。
 	{
            hasNormals = true;
            break;
      }
}

该表顶点格式

colone mesh,然后格式化为VertexPNT (position, normal, 2D texture coordinates) 格式,就可以采用我们自己写的shader来处理,当然这个shader是自己写的,格式也随自己需要而定。例如:

// Step 3: Change vertex format to VertexPNT.

D3DVERTEXELEMENT9 elements[64];
UINT numElements = 0;
VertexPNT::Decl->GetDeclaration(elements, &numElements);

ID3DXMesh* temp = 0;

HR(meshSys->CloneMesh(D3DXMESH_SYSTEMMEM,//这里一个函数就可以clone并格式化,非常方便,就是不太好理解。
       elements, gd3dDevice, &temp));
ReleaseCOM(meshSys);
meshSys = temp;

创造单位法向量信息Generating Normals

函数自动为新的增加的信息增加空间的,所以也不用我们自己管理其内存。:

// Step 4: If the mesh did not have normals, generate them.

if( hasNormals == false)
      HR(D3DXComputeNormals(meshSys, 0));//自动计算新的单位化信息
的函数 

第二个参数可以为零,是输入mesh的邻接矩阵的信息。

优化Optimizing

可以提高渲染速度.

// Step 5: Optimize the mesh.

HR(meshSys->Optimize(D3DXMESH_MANAGED | D3DXMESHOPT_COMPACT |//一个优化函数就搞定了
       D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE,
      (DWORD*)adjBuffer->GetBufferPointer(), 0, 0, 0, meshOut));
ReleaseCOM(meshSys);   // Done w/ system mesh.
ReleaseCOM(adjBuffer); // Done with buffer.

X 文件材质

D3DXLoadMeshFromX第七个参数是包含在mesh中的材质数量,第五个参数是一个D3DXMATERIAL数组:

typedef struct D3DXMATERIAL {
      D3DMATERIAL9 MatD3D;//各种材质,如下结构体
       LPSTR pTextureFilename;//自己指定的指向需要文件纹理图像
 } D3DXMATERIAL;

typedef struct _D3DMATERIAL9 {
      D3DCOLORVALUE Diffuse;
      D3DCOLORVALUE Ambient;
      D3DCOLORVALUE Specular;
      D3DCOLORVALUE Emissive;//自发射光
       float Power;
} D3DMATERIAL9;

.x文件的可以通过循环子网subset来渲染。

如下面例子:

void LoadXFile(
      const std::string& filename,
      ID3DXMesh** meshOut,
      std::vector<Mtrl>& mtrls,
      std::vector<IDirect3DTexture9*>& texs);

设置材质和纹理:

// Step 6: Extract the materials and load the textures.

if( mtrlBuffer != 0 && numMtrls != 0 )
{
      D3DXMATERIAL* d3dxmtrls =
            (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();

      for(DWORD i = 0; i < numMtrls; ++i)
      {
            // Save the ith material.  Note that the MatD3D property

            // does not have an ambient value set when it's loaded, so
            // just set it to the diffuse value.
            Mtrl m;
            m.ambient   = d3dxmtrls[i].MatD3D.Diffuse;
            m.diffuse   = d3dxmtrls[i].MatD3D.Diffuse;
            m.spec      = d3dxmtrls[i].MatD3D.Specular;
            m.specPower = d3dxmtrls[i].MatD3D.Power;
            mtrls.push_back( m );

            // Check if the ith material has an associative texture
            if( d3dxmtrls[i].pTextureFilename != 0 )
            {
                  // Yes, load the texture for the ith subset
                  IDirect3DTexture9* tex = 0;
                  char* texFN = d3dxmtrls[i].pTextureFilename;
                  HR(D3DXCreateTextureFromFile(gd3dDevice,
                                               texFN, &tex));

                  // Save the loaded texture
                  texs.push_back( tex );
            }
            else
            {
                  // No texture for the ith subset
                  texs.push_back( 0 );
            }
      }
}
ReleaseCOM(mtrlBuffer); // done w/ buffer

渲染:

// Application data members.
ID3DXMesh* mMesh;
std::vector<Mtrl> mMtrl;
std::vector<IDirect3DTexture9*> mTex;

// In application constructor:
LoadXFile("skullocc.x", &mMesh, mMtrl, mTex);

// Rendering code:

HR(mFX->BeginPass(0));

for(int j = 0; j < mMtrl.size(); ++j)
{
      HR(mFX->SetValue(mhMtrl, &mMtrl[j], sizeof(Mtrl)));

      // If there is a texture, then use.
      if(mTex[j] != 0)
      {

            HR(mFX->SetTexture(mhTex, mTex[j]));
      }

      // But if not, then set a pure white texture.
      else
      {
            HR(mFX->SetTexture(mhTex, mWhiteTex));
      }

      HR(mFX->CommitChanges());
      HR(mMesh->DrawSubset(j));
}
HR(mFX->EndPass());

清理代码:

ReleaseCOM(mMesh);
for(int i = 0; i < mTex.size(); ++i)
      ReleaseCOM(mTex[i]);


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics