你好,E.M-X游戏制作软件里怎么获取动画的如何设计像素角色点,就是当鼠标在角色透

Visual C++游戏开发(57)
最近几个星期,不停地收到大家的评论和邮件,大家都说希望浅墨早点讲骨骼动画。本来按浅墨拟定的写作计划是把骨骼动画放到很后面,因为骨骼动画知识需要前面的网格模型知识为基础,知识量本身有些大,很可能要占很多次更新的篇幅。
但是看到大家一致的评论,都说非常期待骨骼动画。那就好吧,我们就来开始慢慢讲。一路披荆斩棘,把网格模型相关知识讲完,然后消灭掉骨骼动画这个看似很难的大块头。
其实骨骼动画学起来并不难,而且掌握了非常好玩。一般的三维游戏中都要用到骨骼动画,没用到骨骼动画的三维游戏基本上都是那种什么小飞机啊,空战之类的小儿科游戏,弱爆了。
骨骼动画的前置知识是网格模型(把“前置”这两个字在word中打出来的时候怎么让我想起了DNF(毒奶粉)里面学技能时的“前置技能”- -)。而网格模型其实是Direct3D中非常重头的一部分内容,但是纵观已经与大家见面的十八篇Direct3D教程以来,只有《&
》是在纯粹讲解网格模型,所以想要掌握到骨骼动画,还得先把网格模型这部分再往后学一学,把基础部分补一补,这得花一些更新的次数。
这篇文章中我们来补的知识就是网格模型的优化以及克隆,然后把之前那篇网格模型文章中讲到的X文件的载入方法封装到了一个类中,以后就可以用几行代码,来载入多个3D模型到我们的游戏场景中了。首先放一张配套程序截图,这次我们载入了三个模型,分别是来自地狱代表队的地狱恶魔一头,来自人类代表队的人族骑士一个,来自天堂代表队的天堂雷龙一只。
一、网格模型的优化
文章开头就提到过了,我们之前讲过一次网格模型,大家如果不熟练,请移步到《&
》复习下吧。
无论是用手编(如果你真有这个毅力这么无聊的话)或者使用三维建模软件(3DS Max,Maya)所创建出的网格模型,都可能包含一些尸位素餐吃白饭的无用顶点和索引,况且网格中属性缓存中子集的顺序也不一定是有序的。所以,如果想要提高游戏程序的运行效率的话,网格模型的优化是可以做出卓越贡献的一块大头。
Direct3D的ID3DXMes接口为我们提供了ID3DXMesh::OptimizeInplace和ID3DXMesh::Optimize这两种方法来对网格进行优化。首先Optimize大家都知道,是优化的意思。两者的区别就在这个多出来的Inplace之上,in place,在原位的意思,那么OptimizeInplace函数就是在原来的位置上进行优化,直接对原网格进行优化,而不带Inplace的Optimize方法就生成一个优化后的新的网格对象。即调用OptimizeInplace函数进行优化,优化的是原网格,而调用Optimize函数进行优化,原网格不变,会返回一个优化后的新网格。
我们先来对OptimizeInplace方法进行剖析,MSDN中我们可以查到它的原型如下:
HRESULT&OptimizeInplace(&&&[in]&&&DWORD&Flags,&&&[in]&&&const&DWORD&*pAdjacencyIn,&&&[out]&&DWORD&*pAdjacencyOut,&&&[out]&&DWORD&*pFaceRemap,&&&[out]&&LPD3DXBUFFER&*ppVertexRemap&&);&&
■第一个参数,DWORD类型的Flags,表示执行什么类型的优化方法。它在D3DXMESHOPT枚举中取一个或者多个的值,常用的一些值如下:
网格优化标识
D3DXMESHOPT_COMPACT
从网格中移除没用的顶点和索引项。
D3DXMESHOPT_ATTRSORT
根据属性给三角形排序并调整属性表,这将使DrawSubset方法的绘制执行更有效率。
D3DXMESHOPT_VERTEXCACHE
增加顶点缓存的命中率
D3DXMESHOPT_STRIPREORDER
重组顶点索引,让三角带尽可能的长。
D3DXMESHOPT_IGNOREVERTS
只优化索引信息,忽略掉顶点信息。
另外需要注意的是:D3DXMESHOPT_VERTEXCACHE和D3DXMESHOPT_STRIPREORDER这两者的领域重合了,不能同时使用。
■第二个参数,const DWORD类型的*pAdjacencyIn ,指向优化前的邻接数组的指针,一般我们这样填(DWORD*)pAdjacencyBuffer-&GetBufferPointer(),其中的pAdjacencyBuffer我们在D3DXLoadMeshFromX中给它附上了被载入网格的邻接信息,然后GetBufferPointer一下就是指向待优化的邻接数组的指针了。
■第三个参数,DWORD类型的*pAdjacencyOut,指向优化后的邻接数组的指针。如果不需要优化后的邻接信息,设为NULL就好了。
■第四个参数,DWORD类型的*pFaceRemap,用来填充面重影射信息。该数组必须不小于ID3DXMesh::GetNumFaces()。当一个mesh被优化时,由索引缓存定义的面可能被移动;也就是说,在pFaceRemap中的第i项表示第i个原始面被移动后的新索引值。我们一般很少用,取0或者NULL就行了。
■第五个参数,LPD3DXBUFFER类型的*ppVertexRemap,用于保存网格顶点的重映射信息,一般设为0或者NULL就可以了。
讲起来好像每个参数都很复杂,其实用起来蛮简单的,因为不少参数设为0或者NULL就行了,就像这样:
&&&&&&&&&&&&&&&&&&m_pMesh-&OptimizeInplace(D3DXMESHOPT_COMPACT&|&D3DXMESHOPT_ATTRSORT&|&D3DXMESHOPT_STRIPREORDER,&&&&&&&&&&&&&&&&(DWORD*)pAdjacencyBuffer-&GetBufferPointer(),NULL,&NULL,&NULL&);&&
然后再讲一下Optimize方法,在MSDN中查到它的原型如下:
HRESULT&Optimize(&&&[in]&&&&&&&DWORD&Flags,&&&[in]&&&&&&&const&DWORD*pAdjacencyIn,&&&[in,&out]&&DWORD&*pAdjacencyOut,&&&[in,&out]&&DWORD&*pFaceRemap,&&&[out]&&&&&&LPD3DXBUFFER*ppVertexRemap,&&&[out]&&&&&&LPD3DXMESH&*ppOptMesh&&);&&
这个方法的前五个参数和OptimizeInplace方法的的完全一模一样,大家照着OptimizeInplace看就得了。因为Optimize方法不修改原网格,所以需要额外准备一个参数来存放指向新网格的指针,这就有了它的第六个参数,LPD3DXMESH类型的*ppOptMesh。
另外,关于模型的优化问题。有些模型在制作过程中已经做了优化,所以有可能再优化也优化不出什么内容了。如果是载入一些没有经过优化或者是粗制滥造的3D模型,优化的效果就体现出来了,可以大大增加每秒渲染的帧数。
二、网格模型的克隆
另外,我们也可能要用到网格的克隆技术。网格的克隆是重新生成网格数据的一种方式。通过这种方式,我们可以创建出一个与原网格相同的网格模型,而且还能通过克隆选项重新指定网格数据的某些特殊的特性。网格的克隆是三维模型常用的一个概念,3DS Max与Maya中就有专门的功能,而在我们Direct3D中,也有专门的函数来应对,他就是ID3DXBaseMesh::CloneMeshFVF方法,我们来讲一下:
HRESULT&CloneMeshFVF(&&&[in]&&&&&&&&&&&DWORD&Options,&&&[in]&&&&&&&&&&&DWORD&FVF,&&&[in]&&&&&&&&&&&LPDIRECT3DDEVICE9pDevice,&&&[out,&retval]&&LPD3DXMESH*ppCloneMesh&&);&&
■第一个参数,DWORD类型的Options,表示创建克隆网格时的一些选项,在一个庞大的D3DXMESH枚举体中取值,完整的介绍在这里就免了,没意义。我们介绍几个常用的就行了,其他的很少用到,就算用到了,我们可以查阅MSDN:&&&&&&
克隆网格标识
D3DXMESH_32BIT
克隆的网格使用32位索引
D3DXMESH_MANAGED
克隆出的网格的数据的索引缓存用D3DPOOL_MANAGED标识
D3DXMESH_WRITEONLY
克隆出的网格数据只能执行写操作,不能执行读操作
D3DXMESH_DYNAMIC
克隆出的网格缓存为动态的
■第二个参数,DWORD类型的FVF,很好理解,就是为克隆出的新网格指定FVF灵活顶点格式,这就说明了克隆出的新网格是完全可以和原网格有不同的FVF灵活顶点格式的。
■第三个参数,LPDIRECT3DDEVICE9类型的pDevice,老朋友了,我们的金钥匙Direct3D设备指针。
■第四个参数,LPD3DXMESH类型的*ppCloneMesh,指向克隆出的网格模型的指针。我们事先新建一个网格模型指针,然后调用CloneMeshFVF函数的时候填在这里,调用完之后,这个指针就指向新克隆好的网格模型了。
如果大家看起来不太懂,没关系,我们来看一个调用实例:
&&LPD3DXMESH&&pNewM&&m_pMesh-&CloneMeshFVF(D3DXMESH_MANAGED,m_pMesh-&GetFVF()&|&D3DFVF_NORMAL,&g_pd3dDevice,&&pNewMesh);&&
三、X文件模型载入类的设计
上面的这些知识学起来有点闷有木有,下面我们来动手写点东西吧,然后给我们经过几次文章的更新构建起来的初具规模的游戏场景demo进一步完善,加入更多功能。这周的任务是把之前的X文件的载入与绘制功能封装在一个类中,这样我们就可以在游戏程序中使用这个类,随便几行代码就可以载入并绘制多个好看的3D模型来。
从某种意义上来说,类的出现就是为了避免重复的劳动。在游戏程序的编写过程中,多个3D模型的载入必然是需要一个或者多个专门来类的管理的,如果像我们之前的那样,每载入一个3D模型就要定义一堆全局变量,然后重复写一堆代码,完全就是乱来了。等到后面需要绘制的东西越来越多。到最后也许我们自己写出来的程序源码,都不忍直视了。。。
我们在上一节中的工程中新建一个C++类,命名为XFileModelClass。依然是老规矩,看看有哪些成员变量。
首先呢,理一理思路,我们注意到之前的示例程序中与X模型载入有关的全局变量有这些:
LPD3DXMESH&&&&&&&&&&&&&&&&&&g_pMesh&=&NULL;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&D3DMATERIAL9*&&&&&&&&&&&&&&g_pMaterials=&NULL;&&&&&&&&&&&&&&&&&&&&&&&LPDIRECT3DTEXTURE9*&&&g_pTextures&=&NULL;&&&&&&&&&&&&&&&&&DWORD&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_dwNumMtrls=&0;&&&&&&&&&&&&&&&&&&
那么我们类成员变量的书写思路就出来了。
首当其冲的是D3D设备对象m_pd3dDevice,然后网格模型的指针LPD3DXMESH类型的m_pMesh自然要有,接着表示材质数量的m_dwNumMaterials要有,模型材质的结构体实例m_pMaterials要有,最后,自然就是模型纹理的结构体的实例m_pTextures了。
然后成员函数方面,构造函数析构函数依旧显式地写出来,然后就是接下来比较关键的成员函数了。不过这次的成员函数就两个就可以了,一个用于载入,一个用于绘制。模型的载入函数我们取名为LoadModelFromXFile,模型的绘制函数我们取名为RenderModel,好了,类轮廓就被我们勾勒出来了。就是如下,即我们贴出XFileModelClass.h的全部代码:
&&&&&&&&&&&&#pragma&once&&#include&&D3DUtil.h&&&&&&&class&XFileModelClass&&{&&private:&&&&&&LPDIRECT3DDEVICE9&&&&&&&m_pd3dD&&&&&&&&&&&LPD3DXMESH&&&&&&&&&&m_pM&&&&&&&&span&style=&white-space:pre&&&&&&/span&&&&&&&&&DWORD&&&&&&&&&&&&&&&m_dwNumM&&&&&&&D3DMATERIAL9*&&&&&&&&&&&m_pM&&&&&&&&&&&LPDIRECT3DTEXTURE9&*&&&&&&&&m_pT&&&&&&&&&&public:&&&&&&XFileModelClass(IDirect3DDevice9&*pd3dDevice);&&&&&&&~XFileModelClass(void);&&&&&&&&&public:&&&&&&HRESULT&&&&&LoadModelFromXFile(WCHAR*&strFilename&);&&&&&&&HRESULT&&&&&RenderModel(&);&&&&&&&&&&};&&
四、X文件模型载入类的实现
类轮廓的框架打好了,实现这个类还不是手到擒来的事。X文件模型的载入核心方法当然是已经被我们用了无数次的D3DXLoadMeshFromX方法。依旧是先复习一下我们在之前的示例程序中是如何载入X文件的,那个时候,我们总结了一个模型载入三步曲:
X文件模型载入三步曲之一,加载网格
X文件模型载入三步曲之二,加载材质纹理,
X文件模型载入三步曲之三,绘制
X文件模型载入三步曲的核心代码如下:
&&&&&&&&&LPD3DXBUFFERpAdjBuffer&&=&NULL;&&&&&&&&&&LPD3DXBUFFERpMtrlBuffer&=&NULL;&&&&&&&&&&&&D3DXLoadMeshFromX(L&miki.X&,D3DXMESH_MANAGED,g_pd3dDevice,&&&&&&&&&&&&&&pAdjBuffer,&pMtrlBuffer,&NULL,&&g_dwNumMtrls,&g_pMesh);&&&&&&&&&&&&&&&&&&&&&&&D3DXMATERIAL*pMtrls&=&(D3DXMATERIAL*)pMtrlBuffer-&GetBufferPointer();&&&&&&&g_pMaterials=&new&D3DMATERIAL9[g_dwNumMtrls];&&&&&&&&g_pTextures&&=&newLPDIRECT3DTEXTURE9[g_dwNumMtrls];&&&&&&&&&&&&for(DWORD&i=0;&i&g_dwNumM&i++)&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&g_pMaterials[i]=&pMtrls[i].MatD3D;&&&&&&&&&&&&&g_pMaterials[i].Ambient=&g_pMaterials[i].D&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pTextures[i]&&=&NULL;&&&&&&&&&&&&&D3DXCreateTextureFromFileA(g_pd3dDevice,pMtrls[i].pTextureFilename,&g_pTextures[i]);&&&&&&&&}&&&&&&&&&&&&SAFE_RELEASE(pAdjBuffer)&&&&&&&&SAFE_RELEASE(pMtrlBuffer)&&&&&&&void&Direct3D_Render(HWND&hwnd)&&&{&&&&&&&&&&&&g_pd3dDevice-&Clear(0,NULL,&D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(100,&100,&100),&1.0f,&0);&&&&&g_pd3dDevice-&BeginScene();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&for(DWORD&i&=&0;&i&&&g_dwNumM&i++)&&&&&&&&{&&&&&&&&&&&&&g_pd3dDevice-&SetMaterial(&g_pMaterials[i]);&&&&&&&&&&&&&g_pd3dDevice-&SetTexture(0,g_pTextures[i]);&&&&&&&&&&&&&g_pMesh-&DrawSubset(i);&&&&&&&&}&&&g_pd3dDevice-&EndScene();&&&&&&&&&&&&&&&&&&&&&&&&&g_pd3dDevice-&Present(NULL,&NULL,&NULL,NULL);&&&&&&&&&&&&&&}&&&
既然核心代码就是如上的这些,之前的四个全局变量我们已经定义为了类成员变量,那么剩下的封装起来还不简单。说白了就是把X文件模型载入三步曲的前两步的代码copy到我们自定义的X文件模型载入函数LoadModelFromXFile的函数体中,把文件路径,即D3DXLoadMeshFromX函数的第一个参数用一个参数来表示,并且把全局的变量名改成类中定义的对应的成员变量名就好了。最后再用一下我们今天所学的网格优化知识,调用一下OptimizeInplace函数,于是LoadModelFromXFile函数的实现就是这样:
&&&&&&&&HRESULTXFileModelClass::LoadModelFromXFile(&WCHAR*&strFilename&)&&{&&&&&&&&&&&&LPD3DXBUFFERpAdjacencyBuffer&=&NULL;&&&&&&&&&&&LPD3DXBUFFERpD3DXMtrlBuffer&=&NULL;&&&&&&&&&&&&&&&&&&&&&&&&D3DXLoadMeshFromX(strFilename,&D3DXMESH_MANAGED,&m_pd3dDevice,&&pAdjacencyBuffer,&&&&&&&&&&&&&&&&&pD3DXMtrlBuffer,NULL,&&m_dwNumMaterials,&&m_pMesh&);&&&&&&&&&&&&&&&&&&&&&D3DXMATERIAL*d3dxMaterials&=&(D3DXMATERIAL*)pD3DXMtrlBuffer-&GetBufferPointer();&&&&&&&&&m_pMaterials=&new&D3DMATERIAL9[m_dwNumMaterials];&&&&&&&&&m_pTextures&&=&new&LPDIRECT3DTEXTURE9[m_dwNumMaterials];&&&&&&&&&&&&&&&&&&&&&for(DWORD&i=0;&i&m_dwNumM&i++&)&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&m_pMaterials[i]=&d3dxMaterials[i].MatD3D;&&&&&&&&&&&&&&&&m_pMaterials[i].Ambient=&m_pMaterials[i].D&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&m_pTextures[i]=&NULL;&&&&&&&&&&&&&&&&if(d3dxMaterials[i].pTextureFilename&!=&NULL&&&&&&&&&&&&&&&&&&&&&&&&&&strlen(d3dxMaterials[i].pTextureFilename)&&0&)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(FAILED(&D3DXCreateTextureFromFileA(m_pd3dDevice,d3dxMaterials[i].pTextureFilename,&&m_pTextures[i]&)&)&)&&&&&&&&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&MessageBox(NULL,L&SORRY~!没有找到纹理文件!&,&L&XFileModelClass类读取文件错误&,&MB_OK);&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&}&&&&&&&&&}&&&&&&&&&&&&&&&&&&m_pMesh-&OptimizeInplace(D3DXMESHOPT_COMPACT&|&D3DXMESHOPT_ATTRSORT&|&D3DXMESHOPT_STRIPREORDER,&&&&&&&&&&&&&&&&(DWORD*)pAdjacencyBuffer-&GetBufferPointer(),NULL,&NULL,&NULL&);&&&&&&&&&&&&returnS_OK;&&}&&
接着,网格模型的绘制函数RenderModel的书写,参照着“X文件模型载入三步曲之三,绘制”,也就是一个for循环,无脑把代码拷过来,改一下变量名,于是,RenderModel函数就这样被我们瞬间无耻地写完了:
&&&&&&&&HRESULT&XFileModelClass::RenderModel(&)&&{&&&&&&&&&for(DWORD&i=0;&i&m_dwNumM&i++&)&&&&&&&&&{&&&&&&&&&&&&&&&&&&&m_pd3dDevice-&SetMaterial(&m_pMaterials[i]&);&&&&&&&&&&&&&&&&m_pd3dDevice-&SetTexture(0,&m_pTextures[i]&);&&&&&&&&&&&&&&&&m_pMesh-&DrawSubset(i&);&&&&&&&&&}&&&&&&&&&returnS_OK;&&}&&
构造函数和析构函数也没什么技术含量,构造函数就把D3D设备赋值了进来,析构函数就是在释放一些对象,实现代码如下:
&&&&&&XFileModelClass::XFileModelClass(IDirect3DDevice9*pd3dDevice)&&{&&&&&&&&&&&&&&&&&&&&&&&m_pd3dDevice=&pd3dD&&}&&&&&&&&&&&&&&XFileModelClass::~XFileModelClass(void)&&{&&&&&&&&&&&&&&&&&&SAFE_DELETE_ARRAY(m_pMaterials);&&&&&&&&&&&&&&&&&&&&&if(m_pTextures&)&&&&&&&&&{&&&&&&&&&&&&&&&&for(DWORD&i&=&0;&i&&&m_dwNumM&i++&)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&SAFE_RELEASE(m_pTextures[i]);&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&SAFE_DELETE_ARRAY(m_pTextures);&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&SAFE_RELEASE(m_pMesh);&&}&&
浅墨觉得我们这次的封装有够无耻的,就是在“炒现饭”,把之前用过的东西稍微改一下,用一个类把它们“盛”起来,然后就可以利用这个类,无限度地用相同的伎俩,淡淡地写几句代码,来载入无数的X文件模型了。这有点工厂中的加工车间的意思,把经得起推敲的技术弄成一套生产流水线,来批量生产。
五、X文件模型载入类的使用
这个类中,我们简化到只用四句代码就能载入并绘制出一个模型来,不过我们演示的是多个X文件模型的载入,所以就不止4行代码了,而是有几个模型就乘以4的代码量,另外我们还要给每个模型设置不同的世界矩阵,不然一会儿我们绘制的模型就挤到一块儿去了,所以代码量又稍微加了一点。
Ⅰ.首先,定义一个XFileModelClass类的全局指针实例:
XFileModelClass*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pXFileModel1&&=&NULL;&&&&&XFileModelClass*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pXFileModel2&&=&NULL;&&&&&&&&&&XFileModelClass*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pXFileModel3&&=&NULL;&&&&&&&&&&
Ⅱ.然后,在初始化阶段拿着类指针对象pXFileModel到处“指”,从X文件载入模型:
HRESULT&&&&&g_pXFileModel1&=&new&XFileModelClass(g_pd3dDevice);&&HR(&g_pXFileModel1-&LoadModelFromXFile(L&knight.X&&));&&&&g_pXFileModel2&=&new&XFileModelClass(g_pd3dDevice);&&HR(&g_pXFileModel2-&LoadModelFromXFile(L&dragon.X&&));&&&&g_pXFileModel3&=&new&XFileModelClass(g_pd3dDevice);&&HR(&g_pXFileModel3-&LoadModelFromXFile(L&Demon.X&&));&&
Ⅲ.最后,就是在Render函数中给他们构建不同的世界矩阵,设置一个世界矩阵绘制一次,这样有顺序地做三次,分别绘制出三个模型来:
&&&&&&D3DXMATRIXmScal,mTrans1,mTrans2,mTrans3,mFinal1,mFinal2,mFinal3;&&&&&&&&&&&&&&&&&D3DXMatrixTranslation(&mTrans1,50.0f,.0f);&&&&&&D3DXMatrixScaling(&mScal,3.0f,3.0f,3.0f);&&&&&&mFinal1=mScal*mTrans1*g_matW&&&&&&g_pd3dDevice-&SetTransform(D3DTS_WORLD,&mFinal1);&&&&&&g_pXFileModel1-&RenderModel();&&&&&&&&&&&&&&D3DXMatrixTranslation(&mTrans2,200.0f,&0.0f,&0.0f);&&&&&&mFinal2=mTrans2*mFinal1;&&&&&&g_pd3dDevice-&SetTransform(D3DTS_WORLD,&mFinal2);&&&&&&g_pXFileModel2-&RenderModel();&&&&&&&&&&&&&&D3DXMatrixTranslation(&mTrans3,-200.0f,&0.0f,&0.0f);&&&&&&mFinal3=mTrans3*mFinal1;&&&&&&g_pd3dDevice-&SetTransform(D3DTS_WORLD,&mFinal3);&&&&&&g_pXFileModel3-&RenderModel();&&
通过类的封装,其实一个模型的载入与绘制最简化可以到两句代码,把LoadModelFromXFile函数中的内容直接放在构造函数中,然后在定义类对象的同时用构造函数初始化,然后世界矩阵也不设置直接裸奔绘制,不过这样的话,这个类就太怪异了- -。
六、详细注释的源代码欣赏
本篇文章配套的源代码在之前的基础上又增加了两个文件,也就是封装了X文件模型载入类的源文件和头文件。全部文件数量增加到了14个,它们的列表如下:
我们依旧只贴出核心代码main.cpp,其他的众多文件大家下源代码回去看就好了。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#define&SCREEN_WIDTH&&&&932&&&&&&&&&&&&&&&&&&&&&//为窗口宽度定义的宏,以方便在此处修改窗口宽度&&#define&SCREEN_HEIGHT&&&700&&&&&&&&&&&&&&&&&&&&&&&&&//为窗口高度定义的宏,以方便在此处修改窗口高度&&#define&WINDOW_TITLE&&&&_T(&【Visual&C++】游戏开发笔记系列配套示例程序五十一&&浅墨DirectX教程十九&网格模型进阶之路&&)&//为窗口标题定义的宏&&&&&&&&&&&&&&#include&&d3d9.h&&&#include&&d3dx9.h&&&#include&&tchar.h&&&#include&&time.h&&&&#include&&DirectInputClass.h&&&#include&&CameraClass.h&&&#include&&TerrainClass.h&&&#include&&SkyBoxClass.h&&&#include&&SnowParticleClass.h&&&#include&&XFileModelClass.h&&&&&&&&&&&&&#pragma&comment(lib,&d3d9.lib&)&&#pragma&comment(lib,&d3dx9.lib&)&&#pragma&comment(lib,&&dinput8.lib&)&&&&&//&使用DirectInput必须包含的库文件,注意这里有8&&#pragma&comment(lib,&dxguid.lib&)&&#pragma&comment(lib,&&winmm.lib&)&&&&&&&&&&&&&&&LPDIRECT3DDEVICE9&&&&&&&&&&&&&&&&&&&g_pd3dDevice&=&NULL;&&&&&&&&&&&&&&&&&&LPD3DXFONT&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pTextFPS&=NULL;&&&&&&LPD3DXFONT&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pTextAdaperName&=&NULL;&&&&LPD3DXFONT&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pTextHelper&=&NULL;&&&&LPD3DXFONT&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pTextInfor=&NULL;&&&&float&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_FPS=&0.0f;&&&&&&&&&wchar_t&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_strFPS[50]&={0};&&&&&&wchar_t&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_strAdapterName[60]&={0};&&&&&D3DXMATRIX&&&&&&&&&&&&&&&&&&&&&&&&&&g_matW&&&&&&&&&&&&&&&&&&&&&&&&&&&D3DLIGHT9&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_L&&&&&DInputClass*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pDInput&=&NULL;&&&&&&&&&&&&&&&&&CameraClass*&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pCamera&=&NULL;&&&&&&&&&&&&&&&&&TerrainClass*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pTerrain&=&NULL;&&&&&&&&&&&&&&&&SkyBoxClass*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pSkyBox=NULL;&&&&&&&&&&&&&&&&&&&SnowParticleClass*&&&&&&&&&&&&&&&&&&&&&&g_pSnowParticles&=&NULL;&&&&&&&&&&XFileModelClass*&&&&&&&&&&&&&&&&&&&&&&&&g_pXFileModel1&&=&NULL;&&&&&&XFileModelClass*&&&&&&&&&&&&&&&&&&&&&&&&g_pXFileModel2&&=&NULL;&&&&&XFileModelClass*&&&&&&&&&&&&&&&&&&&&&&&&g_pXFileModel3&&=&NULL;&&&&&&&&&&&&&&&&&&&&&&&&LRESULT&CALLBACK&&&&&&&&WndProc(&HWND&hwnd,&UINT&message,&WPARAM&wParam,&LPARAM&lParam&);&&HRESULT&&&&&&&&&&&&&&&&&&&&&Direct3D_Init(HWND&hwnd,HINSTANCE&hInstance);&&HRESULT&&&&&&&&&&&&&&&&&&&&&Objects_Init();&&void&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Direct3D_Render(&HWND&hwnd,FLOAT&fTimeDelta);&&void&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Direct3D_Update(&HWND&hwnd,FLOAT&fTimeDelta);&&void&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Direct3D_CleanUp(&);&&float&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Get_FPS();&&void&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&HelpText_Render(HWND&hwnd);&&&&&&&&&&&&int&WINAPI&WinMain(HINSTANCE&hInstance,&HINSTANCE&hPrevInstance,LPSTR&lpCmdLine,&int&nShowCmd)&&{&&&&&&&&&&&&&&WNDCLASSEX&wndClass={0}&;&&&&&&&&&&&&&&&&&&&&&wndClass.cbSize&=&sizeof(&WNDCLASSEX&)&;&&&&&&&&&&wndClass.style&=&CS_HREDRAW&|&CS_VREDRAW;&&&&&&&&&wndClass.lpfnWndProc&=&WndP&&&&&&&&&&&&&&&&&&&wndClass.cbClsExtra&&&&&=&0;&&&&&&wndClass.cbWndExtra&&&&&=&0;&&&&&&wndClass.hInstance&=&hI&&&&&&&&&&&&&&&&&&&wndClass.hIcon=(HICON)::LoadImage(NULL,_T(&GameMedia\\icon.ico&),IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);&&&&&&&wndClass.hCursor&=&LoadCursor(&NULL,&IDC_ARROW&);&&&&&&&&&&wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);&&&&&&&&wndClass.lpszMenuName&=&NULL;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&wndClass.lpszClassName&=&_T(&ForTheDreamOfGameDevelop&);&&&&&&&&&&&&&&&&if(&!RegisterClassEx(&&wndClass&)&)&&&&&&&&&&&&&&&&&&&&&&&return&-1;&&&&&&&&&&&&&&HWND&hwnd&=&CreateWindow(&_T(&ForTheDreamOfGameDevelop&),WINDOW_TITLE,&&&&&&&&&&&&&&&&&&&&WS_OVERLAPPEDWINDOW,&CW_USEDEFAULT,&CW_USEDEFAULT,&SCREEN_WIDTH,&&&&&&&&&&SCREEN_HEIGHT,&NULL,&NULL,&hInstance,&NULL&);&&&&&&&&&&&&&&&&if&(!(S_OK==Direct3D_Init&(hwnd,hInstance)))&&&&&&{&&&&&&&&&&MessageBox(hwnd,&_T(&Direct3D初始化失败~!&),&_T(&浅墨的消息窗口&),&0);&&&&&&&}&&&&&&PlaySound(L&GameMedia\\NightElf1.wav&,&NULL,&SND_FILENAME&|&SND_ASYNC|SND_LOOP);&&&&&&&&&&&&&&&&&&&MoveWindow(hwnd,200,10,SCREEN_WIDTH,SCREEN_HEIGHT,true);&&&&&&&&&ShowWindow(&hwnd,&nShowCmd&);&&&&&&&&&&UpdateWindow(hwnd);&&&&&&&&&&&&&&&&g_pDInput&=&new&DInputClass();&&&&&&g_pDInput-&Init(hwnd,hInstance,DISCL_FOREGROUND&|&DISCL_NONEXCLUSIVE,DISCL_FOREGROUND&|&DISCL_NONEXCLUSIVE);&&&&&&&&&&&&&&MSG&msg&=&{&0&};&&&&&&&&while(&msg.message&!=&WM_QUIT&)&&&&&&&&&&&&&&&{&&&&&&&&&&static&FLOAT&fLastTime&&=&(float)::timeGetTime();&&&&&&&&&&static&FLOAT&fCurrTime&&=&(float)::timeGetTime();&&&&&&&&&&static&FLOAT&fTimeDelta&=&0.0f;&&&&&&&&&&fCurrTime&&=&(float)::timeGetTime();&&&&&&&&&&fTimeDelta&=&(fCurrTime&-&fLastTime)&/&1000.0f;&&&&&&&&&&fLastTime&&=&fCurrT&&&&&&&&&&&&if(&PeekMessage(&&msg,&0,&0,&0,&PM_REMOVE&)&)&&&&&&&&&&&&&{&&&&&&&&&&&&&&TranslateMessage(&&msg&);&&&&&&&&&&&&&&&&&&&&&DispatchMessage(&&msg&);&&&&&&&&&&&&&&&&&&}&&&&&&&&&&else&&&&&&&&&&{&&&&&&&&&&&&&&Direct3D_Update(hwnd,fTimeDelta);&&&&&&&&&&&&&&&&&&&&&&&Direct3D_Render(hwnd,fTimeDelta);&&&&&&&&&&&&&&&&&&&&&}&&&&&&}&&&&&&&&UnregisterClass(_T(&ForTheDreamOfGameDevelop&),&wndClass.hInstance);&&&&&&return&0;&&&&}&&&&&&&&&&&&&&&&LRESULT&CALLBACK&WndProc(&HWND&hwnd,&UINT&message,&WPARAM&wParam,&LPARAM&lParam&)&&&&&{&&&&&&switch(&message&)&&&&&&&&&&&&&&&&&&&&&{&&&&&&case&WM_PAINT:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Direct3D_Render(hwnd,0.0f);&&&&&&&&&&&&&&&&&&&&ValidateRect(hwnd,&NULL);&&&&&&&&&&&&&break;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&case&WM_KEYDOWN:&&&&&&&&&&&&&&&&&&&&&&&&&&if&(wParam&==&VK_ESCAPE)&&&&&&&&&&&&&&&&&&DestroyWindow(hwnd);&&&&&&&&&&&&&&break;&&&&&&case&WM_DESTROY:&&&&&&&&&&&&&&&&&&&&&&&&&&Direct3D_CleanUp();&&&&&&&&&&&&&&&PostQuitMessage(&0&);&&&&&&&&&&&&&&&&&break;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&default:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&return&DefWindowProc(&hwnd,&message,&wParam,&lParam&);&&&&&&&&&&&&}&&&&&&&&return&0;&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&HRESULT&Direct3D_Init(HWND&hwnd,HINSTANCE&hInstance)&&{&&&&&&&&&&&&&&&&&&&&&&&&&&LPDIRECT3D9&&pD3D&=&NULL;&&&&&&&if(&NULL&==&(&pD3D&=&Direct3DCreate9(&D3D_SDK_VERSION&)&)&)&&&&&&&&&&&&&&&return&E_FAIL;&&&&&&&&&&&&&&&&&&&&&&&&&&D3DCAPS9&&int&vp&=&0;&&&&&&if(&FAILED(&pD3D-&GetDeviceCaps(&D3DADAPTER_DEFAULT,&D3DDEVTYPE_HAL,&&caps&)&)&)&&&&&&&&&&{&&&&&&&&&&&&&&return&E_FAIL;&&&&&&&&&&}&&&&&&if(&caps.DevCaps&&&D3DDEVCAPS_HWTRANSFORMANDLIGHT&)&&&&&&&&&&vp&=&D3DCREATE_HARDWARE_VERTEXPROCESSING;&&&&&&&&&else&&&&&&&&&&vp&=&D3DCREATE_SOFTWARE_VERTEXPROCESSING;&&&&&&&&&&&&&&&&&&&&&&&&&&&D3DPRESENT_PARAMETERS&d3&&&&&&&ZeroMemory(&d3dpp,&sizeof(d3dpp));&&&&&&d3dpp.BackBufferWidth&&&&&&&&&&&&=&SCREEN_WIDTH;&&&&&&d3dpp.BackBufferHeight&&&&&&&&&&&=&SCREEN_HEIGHT;&&&&&&d3dpp.BackBufferFormat&&&&&&&&&&&=&D3DFMT_A8R8G8B8;&&&&&&d3dpp.BackBufferCount&&&&&&&&&&&&=&2;&&&&&&d3dpp.MultiSampleType&&&&&&&&&&&&=&D3DMULTISAMPLE_NONE;&&&&&&d3dpp.MultiSampleQuality&&&&&&&&&=&0;&&&&&&d3dpp.SwapEffect&&&&&&&&&&&&&&&&&=&D3DSWAPEFFECT_DISCARD;&&&&&&&d3dpp.hDeviceWindow&&&&&&&&&&&&&&=&&&&&&&d3dpp.Windowed&&&&&&&&&&&&&&&&&&&=&true;&&&&&&d3dpp.EnableAutoDepthStencil&&&&&=&true;&&&&&&&d3dpp.AutoDepthStencilFormat&&&&&=&D3DFMT_D24S8;&&&&&&d3dpp.Flags&&&&&&&&&&&&&&&&&&&&&&=&0;&&&&&&d3dpp.FullScreen_RefreshRateInHz&=&0;&&&&&&d3dpp.PresentationInterval&&&&&&&=&D3DPRESENT_INTERVAL_IMMEDIATE;&&&&&&&&&&&&&&&&&&&&&&&&&&if(FAILED(pD3D-&CreateDevice(D3DADAPTER_DEFAULT,&D3DDEVTYPE_HAL,&&&&&&&&&&&hwnd,&vp,&&d3dpp,&&g_pd3dDevice)))&&&&&&&&&&return&E_FAIL;&&&&&&&&&&&&&&&&&wchar_t&TempName[60]=L&当前显卡型号:&;&&&&&&&&&&D3DADAPTER_IDENTIFIER9&A&&&&&&&&&pD3D-&GetAdapterIdentifier(0,0,&Adapter);&&&&&&&int&len&=&MultiByteToWideChar(CP_ACP,0,&Adapter.Description,&-1,&NULL,&0);&&&&&&&MultiByteToWideChar(CP_ACP,&0,&Adapter.Description,&-1,&g_strAdapterName,&len);&&&&&&&wcscat_s(TempName,g_strAdapterName);&&&&&&&wcscpy_s(g_strAdapterName,TempName);&&&&&&&&if(!(S_OK==Objects_Init()))&return&E_FAIL;&&&&&&&&SAFE_RELEASE(pD3D)&&&&&&&&&&&&&return&S_OK;&&}&&&&&&HRESULT&Objects_Init()&&{&&&&&&&&&&&&D3DXCreateFont(g_pd3dDevice,&36,&0,&0,&1000,&false,&DEFAULT_CHARSET,&&&&&&&&&&&OUT_DEFAULT_PRECIS,&DEFAULT_QUALITY,&0,&_T(&Calibri&),&&g_pTextFPS);&&&&&&D3DXCreateFont(g_pd3dDevice,&20,&0,&1000,&0,&false,&DEFAULT_CHARSET,&&&&&&&&&&&OUT_DEFAULT_PRECIS,&DEFAULT_QUALITY,&0,&L&华文中宋&,&&g_pTextAdaperName);&&&&&&&D3DXCreateFont(g_pd3dDevice,&23,&0,&1000,&0,&false,&DEFAULT_CHARSET,&&&&&&&&&&&OUT_DEFAULT_PRECIS,&DEFAULT_QUALITY,&0,&L&微软雅黑&,&&g_pTextHelper);&&&&&&&D3DXCreateFont(g_pd3dDevice,&26,&0,&1000,&0,&false,&DEFAULT_CHARSET,&&&&&&&&&&&OUT_DEFAULT_PRECIS,&DEFAULT_QUALITY,&0,&L&黑体&,&&g_pTextInfor);&&&&&&&&&&&&&&&&&&&::ZeroMemory(&g_Light,&sizeof(g_Light));&&&&&&&&g_Light.Type&&&&&&&&&&=&D3DLIGHT_DIRECTIONAL;&&&&&&&&g_Light.Ambient&&&&&&&=&D3DXCOLOR(0.7f,&0.7f,&0.7f,&1.0f);&&&&&&&&g_Light.Diffuse&&&&&&&=&D3DXCOLOR(1.0f,&1.0f,&1.0f,&1.0f);&&&&&&&&g_Light.Specular&&&&&&=&D3DXCOLOR(0.9f,&0.9f,&0.9f,&1.0f);&&&&&&&&g_Light.Direction&&&&&=&D3DXVECTOR3(1.0f,&1.0f,&1.0f);&&&&&&&&g_pd3dDevice-&SetLight(0,&&g_Light);&&&&&&&&g_pd3dDevice-&LightEnable(0,&true);&&&&&&&&g_pd3dDevice-&SetRenderState(D3DRS_NORMALIZENORMALS,&true);&&&&&&&&g_pd3dDevice-&SetRenderState(D3DRS_SPECULARENABLE,&true);&&&&&&&&&&&&&&g_pCamera&=&new&CameraClass(g_pd3dDevice);&&&&&&g_pCamera-&SetCameraPosition(&D3DXVECTOR3(0.0f,&1400.0f,&-1800.0f));&&&&&&&&g_pCamera-&SetTargetPosition(&D3DXVECTOR3(0.0f,&1500.0f,&0.0f));&&&&&&&&g_pCamera-&SetViewMatrix();&&&&&&&&g_pCamera-&SetProjMatrix();&&&&&&&&&&&&&&&&g_pTerrain&=&new&TerrainClass(g_pd3dDevice);&&&&&&&&&g_pTerrain-&LoadTerrainFromFile(L&GameMedia\\heighmap.raw&,&L&GameMedia\\terrainstone.jpg&);&&&&&&&&&&&g_pTerrain-&InitTerrain(200,&200,&60.0f,&8.0f);&&&&&&&&&&&&&&&&g_pSkyBox&=&new&SkyBoxClass(&g_pd3dDevice&);&&&&&&g_pSkyBox-&LoadSkyTextureFromFile(L&GameMedia\\SunSetFront2048.png&,L&GameMedia\\SunSetBack2048.png&,L&GameMedia\\SunSetRight2048.png&,L&GameMedia\\SunSetLeft2048.png&,&L&GameMedia\\SunSetUp2048.png&);&&&&&&g_pSkyBox-&InitSkyBox(50000);&&&&&&&&&&&&&&&&g_pSnowParticles&=&new&SnowParticleClass(g_pd3dDevice);&&&&&&g_pSnowParticles-&InitSnowParticle();&&&&&&&&HRESULT&&&&&&&&&&&&&g_pXFileModel1&=&new&XFileModelClass(g_pd3dDevice);&&&&&&HR(&g_pXFileModel1-&LoadModelFromXFile(L&knight.X&&));&&&&&&&&&&&&g_pXFileModel2&=&new&XFileModelClass(g_pd3dDevice);&&&&&&HR(&g_pXFileModel2-&LoadModelFromXFile(L&dragon.X&&));&&&&&&&&&&&&g_pXFileModel3&=&new&XFileModelClass(g_pd3dDevice);&&&&&&HR(&g_pXFileModel3-&LoadModelFromXFile(L&Demon.X&&));&&&&&&&&return&S_OK;&&}&&&&void&&&&&&&&&&&&&&&&Direct3D_Update(&HWND&hwnd,FLOAT&fTimeDelta)&&{&&&&&&&&&&&&g_pDInput-&GetInput();&&&&&&&&&&&&&&if&(g_pDInput-&IsKeyDown(DIK_A))&&g_pCamera-&MoveAlongRightVec(-1.0f);&&&&&&if&(g_pDInput-&IsKeyDown(DIK_D))&&g_pCamera-&MoveAlongRightVec(&1.0f);&&&&&&if&(g_pDInput-&IsKeyDown(DIK_W))&g_pCamera-&MoveAlongLookVec(&1.0f);&&&&&&if&(g_pDInput-&IsKeyDown(DIK_S))&&g_pCamera-&MoveAlongLookVec(-1.0f);&&&&&&if&(g_pDInput-&IsKeyDown(DIK_R))&&g_pCamera-&MoveAlongUpVec(&1.0f);&&&&&&if&(g_pDInput-&IsKeyDown(DIK_F))&&g_pCamera-&MoveAlongUpVec(-1.0f);&&&&&&&&&&&&&&if&(g_pDInput-&IsKeyDown(DIK_LEFT))&&g_pCamera-&RotationUpVec(-0.003f);&&&&&&if&(g_pDInput-&IsKeyDown(DIK_RIGHT))&&g_pCamera-&RotationUpVec(&0.003f);&&&&&&if&(g_pDInput-&IsKeyDown(DIK_UP))&&g_pCamera-&RotationRightVec(-0.003f);&&&&&&if&(g_pDInput-&IsKeyDown(DIK_DOWN))&&g_pCamera-&RotationRightVec(&0.003f);&&&&&&if&(g_pDInput-&IsKeyDown(DIK_Q))&g_pCamera-&RotationLookVec(0.001f);&&&&&&if&(g_pDInput-&IsKeyDown(DIK_E))&g_pCamera-&RotationLookVec(&-0.001f);&&&&&&&&&&&&&&g_pCamera-&RotationUpVec(g_pDInput-&MouseDX()*&0.0006f);&&&&&&g_pCamera-&RotationRightVec(g_pDInput-&MouseDY()&*&0.0006f);&&&&&&&&&&&&&&static&FLOAT&fPosZ=0.0f;&&&&&&fPosZ&+=&g_pDInput-&MouseDZ()*0.03f;&&&&&&&&&&&&&&D3DXMATRIX&matV&&&&&&g_pCamera-&CalculateViewMatrix(&matView);&&&&&&g_pd3dDevice-&SetTransform(D3DTS_VIEW,&&matView);&&&&&&&&&&&&&&D3DXMatrixTranslation(&g_matWorld,&0.0f,&0.0f,&fPosZ);&&&&&&&&&&&&&&&&POINT&lt,&&&&&&RECT&&&&&&&GetClientRect(hwnd,&rect);&&&&&&&&&&&&&&lt.x&=&rect.&&&&&&lt.y&=&rect.&&&&&&&&&&&&rb.x&=&rect.&&&&&&rb.y&=&rect.&&&&&&&&&&&&ClientToScreen(hwnd,&);&&&&&&ClientToScreen(hwnd,&rb);&&&&&&&&&&&&rect.left&=&lt.x;&&&&&&rect.top&=&lt.y;&&&&&&rect.right&=&rb.x;&&&&&&rect.bottom&=&rb.y;&&&&&&&&&&&&ClipCursor(&rect);&&&&&&&&ShowCursor(false);&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&void&Direct3D_Render(HWND&hwnd,FLOAT&fTimeDelta)&&{&&&&&&&&&&&&&&&&&&&&&&&&g_pd3dDevice-&Clear(0,&NULL,&D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,&D3DCOLOR_XRGB(100,&255,&255),&1.0f,&0);&&&&&&&&&&&&&&&&&&&&&&&&&&g_pd3dDevice-&BeginScene();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&D3DXMATRIX&mScal,mTrans1,mTrans2,mTrans3,mFinal1,mFinal2,mFinal3;&&&&&&&&&&&&&&&&&D3DXMatrixTranslation(&mTrans1,50.0f,.0f);&&&&&&D3DXMatrixScaling(&mScal,3.0f,3.0f,3.0f);&&&&&&mFinal1=mScal*mTrans1*g_matW&&&&&&g_pd3dDevice-&SetTransform(D3DTS_WORLD,&&mFinal1);&&&&&&g_pXFileModel1-&RenderModel(&);&&&&&&&&&&&&&&D3DXMatrixTranslation(&mTrans2,&200.0f,&0.0f,&0.0f);&&&&&&mFinal2=mTrans2*mFinal1;&&&&&&g_pd3dDevice-&SetTransform(D3DTS_WORLD,&&mFinal2);&&&&&&g_pXFileModel2-&RenderModel(&);&&&&&&&&&&&&&&D3DXMatrixTranslation(&mTrans3,&-200.0f,&0.0f,&0.0f);&&&&&&mFinal3=mTrans3*mFinal1;&&&&&&g_pd3dDevice-&SetTransform(D3DTS_WORLD,&&mFinal3);&&&&&&g_pXFileModel3-&RenderModel(&);&&&&&&&&&&&&&&&&&&g_pTerrain-&RenderTerrain(&g_matWorld,&false);&&&&&&&&&&&&&&&&D3DXMATRIX&matSky,matTransSky,matRotS&&&&&&D3DXMatrixTranslation(&matTransSky,0.0f,-.0f);&&&&&&D3DXMatrixRotationY(&matRotSky,&-0.00005f*timeGetTime());&&&&&&&&&matSky=matTransSky*matRotS&&&&&&g_pSkyBox-&RenderSkyBox(&matSky,&false);&&&&&&&&&&&&&&g_pSnowParticles-&UpdateSnowParticle(fTimeDelta);&&&&&&g_pSnowParticles-&RenderSnowParticle();&&&&&&&&&&&&&&HelpText_Render(hwnd);&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pd3dDevice-&EndScene();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&g_pd3dDevice-&Present(NULL,&NULL,&NULL,&NULL);&&&&&&&&&&&}&&&&&&void&HelpText_Render(HWND&hwnd)&&{&&&&&&&&&&&&RECT&formatR&&&&&&GetClientRect(hwnd,&&formatRect);&&&&&&&&&&&&&&formatRect.top&=&5;&&&&&&int&charCount&=&swprintf_s(g_strFPS,&20,&_T(&FPS:%0.3f&),&Get_FPS()&);&&&&&&g_pTextFPS-&DrawText(NULL,&g_strFPS,&charCount&,&&formatRect,&DT_TOP&|&DT_RIGHT,&D3DCOLOR_RGBA(0,239,136,255));&&&&&&&&&&&&&&g_pTextAdaperName-&DrawText(NULL,g_strAdapterName,&-1,&&formatRect,&&&&&&&&&&&DT_TOP&|&DT_LEFT,&D3DXCOLOR(1.0f,&0.5f,&0.0f,&1.0f));&&&&&&&&&&&&&&formatRect.left&=&0,formatRect.top&=&380;&&&&&&g_pTextInfor-&DrawText(NULL,&L&控制说明:&,&-1,&&formatRect,&&&&&&&&&&&DT_SINGLELINE&|&DT_NOCLIP&|&DT_LEFT,&D3DCOLOR_RGBA(235,123,230,255));&&&&&&formatRect.top&+=&35;&&&&&&g_pTextHelper-&DrawText(NULL,&L&&&&&W:向前飞翔&&&&&S:向后飞翔&&,&-1,&&formatRect,&&&&&&&&&&&DT_SINGLELINE&|&DT_NOCLIP&|&DT_LEFT,&D3DCOLOR_RGBA(255,200,0,255));&&&&&&formatRect.top&+=&25;&&&&&&g_pTextHelper-&DrawText(NULL,&L&&&&&A:向左飞翔&&&&&D:向右飞翔&,&-1,&&formatRect,&&&&&&&&&&&DT_SINGLELINE&|&DT_NOCLIP&|&DT_LEFT,&D3DCOLOR_RGBA(255,200,0,255));&&&&&&formatRect.top&+=&25;&&&&&&g_pTextHelper-&DrawText(NULL,&L&&&&&R:垂直向上飞翔&&&&&F:垂直向下飞翔&,&-1,&&formatRect,&&&&&&&&&&&DT_SINGLELINE&|&DT_NOCLIP&|&DT_LEFT,&D3DCOLOR_RGBA(255,200,0,255));&&&&&&formatRect.top&+=&25;&&&&&&g_pTextHelper-&DrawText(NULL,&L&&&&&Q:向左倾斜&&&&&&&E:向右倾斜&,&-1,&&formatRect,&&&&&&&&&&&DT_SINGLELINE&|&DT_NOCLIP&|&DT_LEFT,&D3DCOLOR_RGBA(255,200,0,255));&&&&&&formatRect.top&+=&25;&&&&&&g_pTextHelper-&DrawText(NULL,&L&&&&&上、下、左、右方向键、鼠标移动:视角变化&&,&-1,&&formatRect,&&&&&&&&&&&DT_SINGLELINE&|&DT_NOCLIP&|&DT_LEFT,&D3DCOLOR_RGBA(255,200,0,255));&&&&&&formatRect.top&+=&25;&&&&&&g_pTextHelper-&DrawText(NULL,&L&&&&&&鼠标滚轮:人物模型Y轴方向移动&,&-1,&&formatRect,&&&&&&&&&&&DT_SINGLELINE&|&DT_NOCLIP&|&DT_LEFT,&D3DCOLOR_RGBA(255,200,0,255));&&&&&&formatRect.top&+=&25;&&&&&&g_pTextHelper-&DrawText(NULL,&L&&&&&ESC键&:&退出程序&,&-1,&&formatRect,&&&&&&&&&&&DT_SINGLELINE&|&DT_NOCLIP&|&DT_LEFT,&D3DCOLOR_RGBA(255,200,0,255));&&}&&&&&&&&&&&&float&Get_FPS()&&{&&&&&&&&&&&&&&static&float&&fps&=&0;&&&&&&&static&int&&&&frameCount&=&0;&&&&&&static&float&&currentTime&=0.0f;&&&&&&static&float&&lastTime&=&0.0f;&&&&&&&&frameCount++;&&&&&&currentTime&=&timeGetTime()*0.001f;&&&&&&&&&&&&&&if(currentTime&-&lastTime&&&1.0f)&&&&&&&{&&&&&&&&&&fps&=&(float)frameCount&/(currentTime&-&lastTime);&&&&&&&&&&lastTime&=&currentT&&&&&&&&&&&frameCount&&&&=&0;&&&&&&}&&&&&&&&return&&&}&&&&&&&&&&&&&&&&void&Direct3D_CleanUp()&&{&&&&&&&&&&&&&&SAFE_DELETE(g_pDInput);&&&&&&SAFE_RELEASE(g_pd3dDevice);&&&&&&SAFE_RELEASE(g_pTextAdaperName)&&&&&&SAFE_RELEASE(g_pTextHelper)&&&&&&SAFE_RELEASE(g_pTextInfor)&&&&&&SAFE_RELEASE(g_pTextFPS)&&&&&&SAFE_RELEASE(g_pd3dDevice)&&}&&
这次的游戏场景有些西方风格的“暗黑”化,天空盒的纹理素材选择的是深色的傍晚,然后3个模型的选择之前已经说了,非常有代表性,来自地狱代表队的地狱恶魔一头,来自人类代表队的人族骑士一个,来自天堂代表队的天堂雷龙一只。
我们来看一下运行截图:
首先是纵览图一张:
然后三张模型的正面图:
然后三张侧面图:
再来一张纵览:
特写镜头一张:划破天际的锋利刀刃
文章最后,依旧是放出本篇文章配套源代码的下载:
本节笔记配套源代码请点击这里下载:
以上就是本节笔记的全部内容,更多精彩内容,且听下回分解。
浅墨在这里,希望喜欢游戏开发系列文章的朋友们能留下你们的评论,每次浅墨登陆博客看到大家的留言的时候都会非常开心,感觉自己正在传递一种信仰,一种精神。
文章最后,依然是【每文一语】栏目,今天的句子是:&
成功的人都是从逆境中坚持下来的,我们应感谢生命赐予的不幸和挫折,让我们证明我们的坚强和勇敢。
下周一,让我们离游戏开发的梦想更近一步。
下周一,游戏开发笔记,我们,不见不散。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:18113次
排名:千里之外
转载:100篇}

我要回帖

更多关于 角色扮演鼠标 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信