谁知道3d max vc接口编程的教程在哪儿下

如题... 如题 展开
 我来答
信电感应
2007-11-09 · TA获得超过4687个赞
知道大有可为答主
回答量:2332
采纳率:33%
帮助的人:1694万
展开全部
先将3D studio文件转换为.x文件
1).X文件的读取
看过DXSDK文档的人都知道,微软提供的关于.X文件格式的信息少的可怜,如果对于.X文件什么都不懂的话简直是天书(本人不才,刚开始就是这么认为的)!幸好有一堆用来访问X文件的COM,要不然真的没辙了。听从鲁迅先生的教诲,我们把“拿来主义”发扬光大——有了就要用!再说了,用微软的COM读微软的文件,简直天造地设的一对儿啊!好了,废话少说,开始。

首先要建立一个IDirectXFile实例,这样:

LPDIRECTXFILE pxFile = NULL;
hr = DirectXFileCreate(&pxFile);

然后注册.X文件模板。模板(Template)规定了.X文件中数据对象的格式,所以要想访问.X文件,就必须先把文件中各种数据的格式说明白。这里使用标准模板:

hr = pxFile -> RegisterTemplates((LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES);

题外话:关于这两个D3DRM_XTEMPLATES和D3DRM_XTEMPLATE_BYTES可真是“来之不易”啊:你去文档里面搜索,连一个页面都找不到!也不知道微软为什么老是跟我们玩这种捉迷藏的游戏,他自己却在SkinnedMesh这个例子当中使用了。D3DRM_XTEMPLATES数组和D3DRM_XTEMPLATE_BYTES宏的定义在rmxftmpl.h中,用的时候别忘了include。

接下来要建立一个枚举对象,有了这个对象才可以遍历.X文件中所有的顶级对象:

LPDIRECTXFILEENUMOBJECT pEnumObject = NULL;
hr = pxFile -> CreateEnumObject("Modal.x", DXFILELOAD_FROMFILE, pEnumObject);

这个方法的说明文档里面有,我就不敷述了。需要说明的是,要从资源或者内存中装载.X文件,我发现的唯一途径就是在第二个参数中指明DXFILELOAD_FROMRESOURCE或者DXFILELOAD_FROMMEMORY,别的方法好像不行。

然后就可以开始遍历顶级对象了,这样做:

LPDIRECTXFILEDATA pData = NULL;
while(SUCCEEDED(pEnumObject -> GetNextDataObject(&pData)))
{
ParseData(pData);
pData -> Release();
}

这里的ParseData()马上说到,它负责解析.X文件的内容,根据要解析的信息可能会很复杂,而且因为.X文件的嵌套结构,所以ParseData()还将是一个递归函数。

2).X文件的解析

因为有太多的对象模板,.X文件的解析过程非常复杂,幸好我们只关心Mesh对象,而且有D3DXLoadMeshFromXof的帮助,使得过程简单了许多,先睹为快,看看这个解析函数:

void ParseData(LPDIRECTXFILEDATA pData)
{
LPDIRECTXFILEOBJECT pSubObj = NULL;
LPDIRECTXFILEDATA pSubData = NULL;
LPDIRECTXFILEDATAREFERENCE pDataRef = NULL;
const GUID *pType = NULL;
char *pName = NULL;
DWORD dwSize;

// 得到对象类型GUID
if(FAILED(pData->GetType(&pType)))
return;

// 得到对象名称
if(FAILED(pData->GetName(NULL, &dwSize)))
return;
if(dwSize) {
if((pName = new char[dwSize]) != NULL)
pData->GetName(pName, &dwSize);
}

// 如果对象没有名字,给它一个缺省的空字符串
if(pName == NULL) {
if((pName = new char[1]) == NULL)
return;
strcpy(pName, "");
}

// 根据对象GUID进行解析,这里我们只关心Mesh对象
if(*pType == TID_D3DRMMesh) {
D3DXLoadMeshFromXof(pData, D3DXMESH_SYSTEMMEM, g_pDevice, NULL, &g_pMtrlBuffer, &g_dwNumMaterials, &g_pMesh);
}

// 接着处理有可能嵌套在对象内部的对象
while(SUCCEEDED(pData->GetNextObject(&pSubObj))) {

// 试着导出一个引用对象
if(SUCCEEDED(pSubObj->QueryInterface(IID_IDirectXFileDataReference, (void**)&pDataRef))) {
// 将其解析为一个数据对象
if(SUCCEEDED(pDataRef->Resolve(&pSubData))) {
// 递归调用,继续解析子对象
ParseXFileData(pSubData);
pSubData -> Release();
}
pDataRef -> Release();
}

// 试着直接导出一个数据对象并解析
if(SUCCEEDED(pSubObj->QueryInterface(IID_IDirectXFileData, (void**)&pSubData))) {
ParseXFileData(pSubData);
pDataRef -> Release();
}
pSubObj -> Release();
}

delete[] pName;
}

需要说明一下,这里的模板GUID,TID_D3DRMMesh定义在文件rmxfguid.h中,要用的时候别忘了include。别的部分都好说,关键就在那个大的while循环,肯定有人要问为什么要调用两次QueryInterface,这点我也感到很奇怪。不过文档上说要决定子对象类型就必须以相应的GUID为参数调用QueryInterface,成功了就说明子对象就是这个类型的!我不禁暗地里为微软庆幸:幸好子对象类型只可能有三种(文档上说的:data, data reference or binary),要是有 n 种这个程序还不要慢死!

3)实用阶段

呵呵,最吸引人的部分来了:

#define RELEASENULL(p) { if(p) { (p) -> Release(); (p) = NULL; } }

// 这个是解析函数,不用直接调用
HRESULT d3dhLoadMeshFromXof(
LPDIRECTXFILEDATA pxFileData,
LPSTR pMeshName,
DWORD dwMeshOptions,
LPDIRECT3DDEVICE8 pDevice,
LPD3DXBUFFER* ppAdjacency,
LPD3DXBUFFER* ppMaterials,
PDWORD pNumMaterials,
LPD3DXMESH *ppMesh
)
{
LPDIRECTXFILEOBJECT pxFileObject = NULL;
LPDIRECTXFILEDATAREFERENCE pxFileReference = NULL;
LPDIRECTXFILEDATA pxFileSubData = NULL;
const GUID* pDataType;
HRESULT hr;
LPSTR pName;
DWORD dwSize;

// Get object type and space to store the name
if ( FAILED(hr = pxFileData -> GetType(&pDataType)) ||
FAILED(hr = pxFileData -> GetName(NULL, &dwSize)) )
return hr;

// Get object name
if ( dwSize == 0 ) dwSize = 1;
if ( ( pName = new char[dwSize] ) == NULL )
return E_OUTOFMEMORY;
strcpy(pName, "");
pxFileData -> GetName(pName, &dwSize);

// We only care about mesh object
if ( *pDataType == TID_D3DRMMesh && !strcmp(pMeshName, pName) )
{
hr = D3DXLoadMeshFromXof(pxFileData, dwMeshOptions, pDevice, ppAdjacency, ppMaterials, pNumMaterials, ppMesh);
goto EXIT;
}

// Parse sub-objects in this file data
while(SUCCEEDED(hr = pxFileData -> GetNextObject(&pxFileObject)))
{
// Scan for data reference object
if ( SUCCEEDED(pxFileObject -> QueryInterface(IID_IDirectXFileDataReference, (LPVOID*)&pxFileReference)) )
{
if ( SUCCEEDED(pxFileReference -> Resolve(&pxFileSubData)) )
{
if ( SUCCEEDED(hr = d3dhLoadMeshFromXof(pxFileSubData, pMeshName, dwMeshOptions, pDevice, ppAdjacency, ppMaterials, pNumMaterials, ppMesh)) )
// Mesh found and loaded, exit
goto EXIT;
else if ( hr != DXFILEERR_NOMOREOBJECTS )
goto EXIT;
RELEASENULL(pxFileSubData);
}
RELEASENULL(pxFileReference);
}
if ( SUCCEEDED(pxFileObject -> QueryInterface(IID_IDirectXFileData, (LPVOID*)&pxFileSubData)) )
{
if ( SUCCEEDED(hr = d3dhLoadMeshFromXof(pxFileSubData, pMeshName, dwMeshOptions, pDevice, ppAdjacency, ppMaterials, pNumMaterials, ppMesh)) )
goto EXIT;
else if ( hr != DXFILEERR_NOMOREOBJECTS )
goto EXIT;
RELEASENULL(pxFileSubData);
}
RELEASENULL(pxFileReference);
}

EXIT:
RELEASENULL(pxFileSubData);
RELEASENULL(pxFileReference);
RELEASENULL(pxFileObject);
delete[] pName;

return hr;
}

// 这个是接口函数
HRESULT d3dhLoadMeshFromX(
LPSTR pSource, // Pointer to source data, depend on load options
DWORD dwLoadOptions, // Reference to IDirectXFile::CreateEnumObject
LPSTR pMeshName, // Name of the mesh to load
DWORD dwMeshOptions, // Reference to D3DXLoadMeshFromX
LPDIRECT3DDEVICE8 pDevice, // Reference to D3DXLoadMeshFromX
LPD3DXBUFFER* ppAdjacency, // Reference to D3DXLoadMeshFromX
LPD3DXBUFFER* ppMaterials, // Reference to D3DXLoadMeshFromX
PDWORD pNumMaterials, // Reference to D3DXLoadMeshFromX
LPD3DXMESH *ppMesh // Reference to D3DXLoadMeshFromX
)
{
LPDIRECTXFILE pxFile = NULL;
LPDIRECTXFILEDATA pxFileData = NULL;
LPDIRECTXFILEENUMOBJECT pxFileEnumObject = NULL;
HRESULT hr;

// Parameter validation
if ( pSource == NULL || pMeshName == NULL )
return D3DERR_INVALIDCALL;

// Create DirectX file objects
if ( FAILED(hr = DirectXFileCreate(&pxFile)) ||
FAILED(hr = pxFile -> RegisterTemplates((LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)) ||
FAILED(hr = pxFile -> CreateEnumObject(pSource, dwLoadOptions, &pxFileEnumObject)) )
goto EXIT;

// Enumerate all top-level objects
while(SUCCEEDED(hr = pxFileEnumObject -> GetNextDataObject(&pxFileData)))
{
if ( SUCCEEDED(hr = d3dhLoadMeshFromXof(pxFileData, pMeshName, dwMeshOptions, pDevice, ppAdjacency, ppMaterials, pNumMaterials, ppMesh)) )
// Mesh found and loaded successfully, exit
goto EXIT;
else if ( hr != DXFILEERR_NOMOREOBJECTS )
// Unexpected error, abort
goto EXIT;
RELEASENULL(pxFileData);
}

EXIT:
// Clean up
RELEASENULL(pxFileEnumObject);
RELEASENULL(pxFileData);
RELEASENULL(pxFile);

return hr;
}

说明一下:这两个函数完全仿照D3DXLoadMeshFromX()和D3DXLoadMeshFromXof()的模式编写,一般情况下只使用d3dhLoadMeshFromX()就够了。用过D3DXLoadMeshFromX()的朋友一定看出来了,d3dhLoadMeshFromX()多了两个参数,对了!就是我们最需要的那两个参数,一个是装载.X文件的位置,另一个是想要装载的多边形的名称。
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式