本系列文章由zhmxy555(毛星云)编写,转载请注明出处。  

文章链接: http://blog.csdn.net/zhmxy555/article/details/8770426

作者:毛星云(浅墨)    邮箱: happylifemxy@163.com  




最近几个星期,不停地收到大家的评论和邮件,大家都说希望浅墨早点讲骨骼动画。本来按浅墨拟定的写作计划是把骨骼动画放到很后面,因为骨骼动画知识需要前面的网格模型知识为基础,知识量本身有些大,很可能要占很多次更新的篇幅。

但是看到大家一致的评论,都说非常期待骨骼动画。那就好吧,我们就来开始慢慢讲。一路披荆斩棘,把网格模型相关知识讲完,然后消灭掉骨骼动画这个看似很难的大块头。

其实骨骼动画学起来并不难,而且掌握了非常好玩。一般的三维游戏中都要用到骨骼动画,没用到骨骼动画的三维游戏基本上都是那种什么小飞机啊,空战之类的小儿科游戏,弱爆了。

骨骼动画的前置知识是网格模型(把“前置”这两个字在word中打出来的时候怎么让我想起了DNF(毒奶粉)里面学技能时的“前置技能”- -)。而网格模型其实是Direct3D中非常重头的一部分内容,但是纵观已经与大家见面的十八篇Direct3D教程以来,只有《 

【Visual C++】游戏开发笔记四十四 浅墨DirectX教程十二 网格模型和X文件使用面面观

是在纯粹讲解网格模型,所以想要掌握到骨骼动画,还得先把网格模型这部分再往后学一学,把基础部分补一补,这得花一些更新的次数。

这篇文章中我们来补的知识就是网格模型的优化以及克隆,然后把之前那篇网格模型文章中讲到的X文件的载入方法封装到了一个类中,以后就可以用几行代码,来载入多个3D模型到我们的游戏场景中了。首先放一张配套程序截图,这次我们载入了三个模型,分别是来自地狱代表队的地狱恶魔一头,来自人类代表队的人族骑士一个,来自天堂代表队的天堂雷龙一只。

 


 




一、网格模型的优化



文章开头就提到过了,我们之前讲过一次网格模型,大家如果不熟练,请移步到《 

【Visual C++】游戏开发笔记四十四 浅墨DirectX教程十二 网格模型和X文件使用面面观

》复习下吧。

无论是用手编(如果你真有这个毅力这么无聊的话)或者使用三维建模软件(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就行了,就像这样:

 

//其中pAdjacencyBuffer中存放了要被优化的网格的邻接信息//优化网格模型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函数的时候填在这里,调用完之后,这个指针就指向新克隆好的网格模型了。

 

如果大家看起来不太懂,没关系,我们来看一个调用实例:

//其中的m_pMesh为需要被克隆的原模型指针,为LPD3DXMESH类型
LPD3DXMESH  pNewMesh;
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的全部代码:

 

//=============================================================================
// Name: XFileModelClass.h
// Des: 一个封装了X文件载入与渲染功能的类头文件
// 2013年 4月7日  Create by 浅墨 
//=============================================================================#pragma once
#include "D3DUtil.h"class XFileModelClass
{
private:LPDIRECT3DDEVICE9		m_pd3dDevice;	  //D3D设备对象LPD3DXMESH			m_pMesh;       	  //网格模型对象DWORD				m_dwNumMaterials; //材质的数量D3DMATERIAL9*			m_pMaterials;     //模型材质结构体的实例LPDIRECT3DTEXTURE9 *		m_pTextures;      //模型纹理结构体的实例public:XFileModelClass(IDirect3DDevice9 *pd3dDevice); //构造函数~XFileModelClass(void);     //析构函数   public:HRESULT		LoadModelFromXFile(WCHAR* strFilename ); //从.X文件读取三维模型到内存中HRESULT		RenderModel( );  //渲染三维网格模型};






四、X文件模型载入类的实现




类轮廓的框架打好了,实现这个类还不是手到擒来的事。X文件模型的载入核心方法当然是已经被我们用了无数次的D3DXLoadMeshFromX方法。依旧是先复习一下我们在之前的示例程序中是如何载入X文件的,那个时候,我们总结了一个模型载入三步曲:

 

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();//创建一个D3DXMATERIAL结构体用于读取材质和纹理信息 g_pMaterials= new D3DMATERIAL9[g_dwNumMtrls]; g_pTextures  = newLPDIRECT3DTEXTURE9[g_dwNumMtrls]; for(DWORD i=0; i<g_dwNumMtrls; i++) { //获取材质,并设置一下环境光的颜色值 g_pMaterials[i]= pMtrls[i].MatD3D; g_pMaterials[i].Ambient= g_pMaterials[i].Diffuse; //创建一下纹理对象 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循环,进行网格各个部分的绘制 for(DWORD i = 0; i < g_dwNumMtrls; 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函数的实现就是这样:

 

//--------------------------------------------------------------------------------------
// Name:XFileModelClass::LoadModelFromXFile()
// Desc: 从.X文件读取三维模型到内存中
//--------------------------------------------------------------------------------------
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_dwNumMaterials; i++ ){//获取材质,并设置一下环境光的颜色值m_pMaterials[i]= d3dxMaterials[i].MatD3D;m_pMaterials[i].Ambient= m_pMaterials[i].Diffuse;//创建一下纹理对象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函数就这样被我们瞬间无耻地写完了:

//--------------------------------------------------------------------------------------
// Name: XFileModelClass::RenderModel()
// Desc: 渲染三维网格模型
//--------------------------------------------------------------------------------------
HRESULT XFileModelClass::RenderModel( )
{for(DWORD i=0; i<m_dwNumMaterials; i++ ){m_pd3dDevice->SetMaterial(&m_pMaterials[i] );m_pd3dDevice->SetTexture(0, m_pTextures[i] );m_pMesh->DrawSubset(i );}returnS_OK;
}


构造函数和析构函数也没什么技术含量,构造函数就把D3D设备赋值了进来,析构函数就是在释放一些对象,实现代码如下:

//-----------------------------------------------------------------------------
// Desc: 构造函数
//-----------------------------------------------------------------------------
XFileModelClass::XFileModelClass(IDirect3DDevice9*pd3dDevice)
{     //给各个成员变量赋初值m_pd3dDevice= pd3dDevice;
}//-----------------------------------------------------------------------------
// Desc: 析构函数
//-----------------------------------------------------------------------------
XFileModelClass::~XFileModelClass(void)
{//释放网格模型材质SAFE_DELETE_ARRAY(m_pMaterials);//释放网格模型纹理if(m_pTextures ){for(DWORD i = 0; i < m_dwNumMaterials; 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 hr;//载入第一个模型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,1200.0f,0.0f);D3DXMatrixScaling(&mScal,3.0f,3.0f,3.0f);mFinal1=mScal*mTrans1*g_matWorld;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,其他的众多文件大家下源代码回去看就好了。


//*****************************************************************************************
//
//【Visual C++】游戏开发笔记系列配套源码五十一  浅墨DirectX教程十九 网格模型进阶之路  
//		 VS2010版
// 2013年 4月6日  Create by 浅墨 
//图标素材出处: VAMPIRE_SWEETIE
//背景音乐素材出处:魔兽争霸3 暗夜精灵战斗曲
//人物模型素材出处:英雄无敌6
//
//***************************************************************************************** //*****************************************************************************************
// Desc: 宏定义部分   
//*****************************************************************************************
#define SCREEN_WIDTH	932						//为窗口宽度定义的宏,以方便在此处修改窗口宽度
#define SCREEN_HEIGHT	700							//为窗口高度定义的宏,以方便在此处修改窗口高度
#define WINDOW_TITLE	_T("【Visual C++】游戏开发笔记系列配套示例程序五十一  浅墨DirectX教程十九 网格模型进阶之路 ") //为窗口标题定义的宏//*****************************************************************************************
// Desc: 头文件定义部分  
//*****************************************************************************************                                                                                       
#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"//*****************************************************************************************
// Desc: 库文件定义部分  
//***************************************************************************************** 
#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") //*****************************************************************************************
// Desc: 全局变量声明部分  
//*****************************************************************************************
LPDIRECT3DDEVICE9					g_pd3dDevice = NULL;				//Direct3D设备对象
LPD3DXFONT								g_pTextFPS =NULL;    //字体COM接口
LPD3DXFONT								g_pTextAdaperName = NULL;  // 显卡信息的2D文本
LPD3DXFONT								g_pTextHelper = NULL;  // 帮助信息的2D文本
LPD3DXFONT								g_pTextInfor= NULL;  // 绘制信息的2D文本
float											g_FPS= 0.0f;       //一个浮点型的变量,代表帧速率
wchar_t										g_strFPS[50] ={0};    //包含帧速率的字符数组
wchar_t										g_strAdapterName[60] ={0};   //包含显卡名称的字符数组
D3DXMATRIX							g_matWorld;							//世界矩阵
D3DLIGHT9								g_Light;   //全局光照
DInputClass*								g_pDInput = NULL;				//DInputClass类的指针实例
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;	  //模型类的第三个对象//*****************************************************************************************
// Desc: 全局函数声明部分 
//***************************************************************************************** 
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);//*****************************************************************************************
// Name: WinMain( )
// Desc: Windows应用程序入口函数
//*****************************************************************************************
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd)
{//开始设计一个完整的窗口类WNDCLASSEX wndClass={0} ;				//用WINDCLASSEX定义了一个窗口类,即用wndClass实例化了WINDCLASSEX,用于之后窗口的各项初始化    wndClass.cbSize = sizeof( WNDCLASSEX ) ;	//设置结构体的字节数大小wndClass.style = CS_HREDRAW | CS_VREDRAW;	//设置窗口的样式wndClass.lpfnWndProc = WndProc;				//设置指向窗口过程函数的指针wndClass.cbClsExtra		= 0;wndClass.cbWndExtra		= 0;wndClass.hInstance = hInstance;				//指定包含窗口过程的程序的实例句柄。wndClass.hIcon=(HICON)::LoadImage(NULL,_T("GameMedia\\icon.ico"),IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE); //从全局的::LoadImage函数从本地加载自定义ico图标wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );    //指定窗口类的光标句柄。wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);  //为hbrBackground成员指定一个灰色画刷句柄wndClass.lpszMenuName = NULL;						//用一个以空终止的字符串,指定菜单资源的名字。wndClass.lpszClassName = _T("ForTheDreamOfGameDevelop");		//用一个以空终止的字符串,指定窗口类的名字。if( !RegisterClassEx( &wndClass ) )				//设计完窗口后,需要对窗口类进行注册,这样才能创建该类型的窗口return -1;		HWND hwnd = CreateWindow( _T("ForTheDreamOfGameDevelop"),WINDOW_TITLE,			//喜闻乐见的创建窗口函数CreateWindowWS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, SCREEN_WIDTH,SCREEN_HEIGHT, NULL, NULL, hInstance, NULL );//Direct3D资源的初始化,调用失败用messagebox予以显示if (!(S_OK==Direct3D_Init (hwnd,hInstance))){MessageBox(hwnd, _T("Direct3D初始化失败~!"), _T("浅墨的消息窗口"), 0); //使用MessageBox函数,创建一个消息窗口 }PlaySound(L"GameMedia\\NightElf1.wav", NULL, SND_FILENAME | SND_ASYNC|SND_LOOP);   //循环播放背景音乐MoveWindow(hwnd,200,10,SCREEN_WIDTH,SCREEN_HEIGHT,true);   //调整窗口显示时的位置,窗口左上角位于屏幕坐标(200,0)处ShowWindow( hwnd, nShowCmd );    //调用Win32函数ShowWindow来显示窗口UpdateWindow(hwnd);  //对窗口进行更新,就像我们买了新房子要装修一样//进行DirectInput类的初始化g_pDInput = new DInputClass();g_pDInput->Init(hwnd,hInstance,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);//消息循环过程MSG msg = { 0 };  //初始化msgwhile( msg.message != WM_QUIT )			//使用while循环{static FLOAT fLastTime  = (float)::timeGetTime();static FLOAT fCurrTime  = (float)::timeGetTime();static FLOAT fTimeDelta = 0.0f;fCurrTime  = (float)::timeGetTime();fTimeDelta = (fCurrTime - fLastTime) / 1000.0f;fLastTime  = fCurrTime;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;  
}//*****************************************************************************************
// Name: WndProc()
// Desc: 对窗口消息进行处理
//*****************************************************************************************
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )   //窗口过程函数WndProc
{switch( message )				//switch语句开始{case WM_PAINT:					 // 客户区重绘消息Direct3D_Render(hwnd,0.0f);          //调用Direct3D_Render函数,进行画面的绘制ValidateRect(hwnd, NULL);   // 更新客户区的显示break;									//跳出该switch语句case WM_KEYDOWN:                // 键盘按下消息if (wParam == VK_ESCAPE)    // ESC键DestroyWindow(hwnd);    // 销毁窗口, 并发送一条WM_DESTROY消息break;case WM_DESTROY:				//窗口销毁消息Direct3D_CleanUp();     //调用Direct3D_CleanUp函数,清理COM接口对象PostQuitMessage( 0 );		//向系统表明有个线程有终止请求。用来响应WM_DESTROY消息break;						//跳出该switch语句default:						//若上述case条件都不符合,则执行该default语句return DefWindowProc( hwnd, message, wParam, lParam );		//调用缺省的窗口过程来为应用程序没有处理的窗口消息提供缺省的处理。}return 0;					//正常退出
}//*****************************************************************************************
// Name: Direct3D_Init( )
// Desc: 初始化Direct3D
// Point:【Direct3D初始化四步曲】
//		1.初始化四步曲之一,创建Direct3D接口对象
//		2.初始化四步曲之二,获取硬件设备信息
//		3.初始化四步曲之三,填充结构体
//		4.初始化四步曲之四,创建Direct3D设备接口
//*****************************************************************************************HRESULT Direct3D_Init(HWND hwnd,HINSTANCE hInstance)
{//--------------------------------------------------------------------------------------// 【Direct3D初始化四步曲之一,创接口】:创建Direct3D接口对象, 以便用该Direct3D对象创建Direct3D设备对象//--------------------------------------------------------------------------------------LPDIRECT3D9  pD3D = NULL; //Direct3D接口对象的创建if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) //初始化Direct3D接口对象,并进行DirectX版本协商return E_FAIL;//--------------------------------------------------------------------------------------// 【Direct3D初始化四步曲之二,取信息】:获取硬件设备信息//--------------------------------------------------------------------------------------D3DCAPS9 caps; int vp = 0;if( FAILED( pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps ) ) ){return E_FAIL;}if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;   //支持硬件顶点运算,我们就采用硬件顶点运算,妥妥的elsevp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //不支持硬件顶点运算,无奈只好采用软件顶点运算//--------------------------------------------------------------------------------------// 【Direct3D初始化四步曲之三,填内容】:填充D3DPRESENT_PARAMETERS结构体//--------------------------------------------------------------------------------------D3DPRESENT_PARAMETERS d3dpp; 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              = hwnd;d3dpp.Windowed                   = true;d3dpp.EnableAutoDepthStencil     = true; d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;d3dpp.Flags                      = 0;d3dpp.FullScreen_RefreshRateInHz = 0;d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;//--------------------------------------------------------------------------------------// 【Direct3D初始化四步曲之四,创设备】:创建Direct3D设备接口//--------------------------------------------------------------------------------------if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, vp, &d3dpp, &g_pd3dDevice)))return E_FAIL;//获取显卡信息到g_strAdapterName中,并在显卡名称之前加上“当前显卡型号:”字符串wchar_t TempName[60]=L"当前显卡型号:";   //定义一个临时字符串,且方便了把"当前显卡型号:"字符串引入我们的目的字符串中D3DADAPTER_IDENTIFIER9 Adapter;  //定义一个D3DADAPTER_IDENTIFIER9结构体,用于存储显卡信息pD3D->GetAdapterIdentifier(0,0,&Adapter);//调用GetAdapterIdentifier,获取显卡信息int len = MultiByteToWideChar(CP_ACP,0, Adapter.Description, -1, NULL, 0);//显卡名称现在已经在Adapter.Description中了,但是其为char类型,我们要将其转为wchar_t类型MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, g_strAdapterName, len);//这步操作完成后,g_strAdapterName中就为当前我们的显卡类型名的wchar_t型字符串了wcscat_s(TempName,g_strAdapterName);//把当前我们的显卡名加到“当前显卡型号:”字符串后面,结果存在TempName中wcscpy_s(g_strAdapterName,TempName);//把TempName中的结果拷贝到全局变量g_strAdapterName中,大功告成~if(!(S_OK==Objects_Init())) return E_FAIL;SAFE_RELEASE(pD3D) //LPDIRECT3D9接口对象的使命完成,我们将其释放掉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");//从文件加载前、后、左、右、顶面5个面的纹理图g_pSkyBox->InitSkyBox(50000);  //设置天空盒的边长//创建并初始化雪花粒子系统g_pSnowParticles = new SnowParticleClass(g_pd3dDevice);g_pSnowParticles->InitSnowParticle();HRESULT hr;//载入第一个模型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)
{//使用DirectInput类读取数据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 matView;g_pCamera->CalculateViewMatrix(&matView);g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);//把正确的世界变换矩阵存到g_matWorld中D3DXMatrixTranslation(&g_matWorld, 0.0f, 0.0f, fPosZ);//以下这段代码用于限制鼠标光标移动区域POINT lt,rb;RECT rect;GetClientRect(hwnd,&rect);  //取得窗口内部矩形//将矩形左上点坐标存入lt中lt.x = rect.left;lt.y = rect.top;//将矩形右下坐标存入rb中rb.x = rect.right;rb.y = rect.bottom;//将lt和rb的窗口坐标转换为屏幕坐标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);		//隐藏鼠标光标}//*****************************************************************************************
// Name: Direct3D_Render()
// Desc: 进行图形的渲染操作
// Point:【Direct3D渲染五步曲】
//		1.渲染五步曲之一,清屏操作
//		2.渲染五步曲之二,开始绘制
//		3.渲染五步曲之三,正式绘制
//		4.渲染五步曲之四,结束绘制
//		5.渲染五步曲之五,翻转显示
//*****************************************************************************************void Direct3D_Render(HWND hwnd,FLOAT fTimeDelta)
{//--------------------------------------------------------------------------------------// 【Direct3D渲染五步曲之一】:清屏操作//--------------------------------------------------------------------------------------g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, D3DCOLOR_XRGB(100, 255, 255), 1.0f, 0);//--------------------------------------------------------------------------------------// 【Direct3D渲染五步曲之二】:开始绘制//--------------------------------------------------------------------------------------g_pd3dDevice->BeginScene();                     // 开始绘制//--------------------------------------------------------------------------------------// 【Direct3D渲染五步曲之三】:正式绘制//--------------------------------------------------------------------------------------//以下这段代码用于绘制游戏角色D3DXMATRIX mScal,mTrans1,mTrans2,mTrans3,mFinal1,mFinal2,mFinal3;   //定义一些矩阵,准备对模型进行矩阵变换//第一个角色的绘制,首先是“调合”出这个角色合适的世界矩阵,然后再绘制D3DXMatrixTranslation(&mTrans1,50.0f,1200.0f,0.0f);D3DXMatrixScaling(&mScal,3.0f,3.0f,3.0f);mFinal1=mScal*mTrans1*g_matWorld;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);  //渲染地形,且第二个参数设为false,表示不渲染出地形的线框//绘制天空D3DXMATRIX matSky,matTransSky,matRotSky;D3DXMatrixTranslation(&matTransSky,0.0f,-12000.0f,0.0f);D3DXMatrixRotationY(&matRotSky, -0.00005f*timeGetTime());   //旋转天空网格, 简单模拟云彩运动效果matSky=matTransSky*matRotSky;g_pSkyBox->RenderSkyBox(&matSky, false);//绘制雪花粒子系统g_pSnowParticles->UpdateSnowParticle(fTimeDelta);g_pSnowParticles->RenderSnowParticle();//绘制文字信息HelpText_Render(hwnd);//--------------------------------------------------------------------------------------// 【Direct3D渲染五步曲之四】:结束绘制//--------------------------------------------------------------------------------------g_pd3dDevice->EndScene();                       // 结束绘制//--------------------------------------------------------------------------------------// 【Direct3D渲染五步曲之五】:显示翻转//--------------------------------------------------------------------------------------g_pd3dDevice->Present(NULL, NULL, NULL, NULL);  // 翻转与显示}void HelpText_Render(HWND hwnd)
{//定义一个矩形,用于获取主窗口矩形RECT formatRect;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));
}//*****************************************************************************************
// Name:Get_FPS()函数
// Desc: 用于计算帧速率
//*****************************************************************************************
float Get_FPS()
{//定义四个静态变量static float  fps = 0; //我们需要计算的FPS值static int    frameCount = 0;//帧数static float  currentTime =0.0f;//当前时间static float  lastTime = 0.0f;//持续时间frameCount++;//每调用一次Get_FPS()函数,帧数自增1currentTime = timeGetTime()*0.001f;//获取系统时间,其中timeGetTime函数返回的是以毫秒为单位的系统时间,所以需要乘以0.001,得到单位为秒的时间//如果当前时间减去持续时间大于了1秒钟,就进行一次FPS的计算和持续时间的更新,并将帧数值清零if(currentTime - lastTime > 1.0f) //将时间控制在1秒钟{fps = (float)frameCount /(currentTime - lastTime);//计算这1秒钟的FPS值lastTime = currentTime; //将当前时间currentTime赋给持续时间lastTime,作为下一秒的基准时间frameCount    = 0;//将本次帧数frameCount值清零}return fps;
}//*****************************************************************************************
// Name: Direct3D_CleanUp()
// Desc: 对Direct3D的资源进行清理,释放COM接口对象
//*****************************************************************************************
void Direct3D_CleanUp()
{//释放COM接口对象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个模型的选择之前已经说了,非常有代表性,来自地狱代表队的地狱恶魔一头,来自人类代表队的人族骑士一个,来自天堂代表队的天堂雷龙一只。

我们来看一下运行截图:


首先是纵览图一张:

然后三张模型的正面图:

然后三张侧面图:



再来一张纵览:

特写镜头一张:划破天际的锋利刀刃



文章最后,依旧是放出本篇文章配套源代码的下载:


本节笔记配套源代码请点击这里下载:


【浅墨DirectX提高班】配套源代码之十九下载 

 


 

 

以上就是本节笔记的全部内容,更多精彩内容,且听下回分解。

浅墨在这里,希望喜欢游戏开发系列文章的朋友们能留下你们的评论,每次浅墨登陆博客看到大家的留言的时候都会非常开心,感觉自己正在传递一种信仰,一种精神。

 


文章最后,依然是【每文一语】栏目,今天的句子是: 


成功的人都是从逆境中坚持下来的,我们应感谢生命赐予的不幸和挫折,让我们证明我们的坚强和勇敢。


 

下周一,让我们离游戏开发的梦想更近一步。

下周一,游戏开发笔记,我们,不见不散。




查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. Android Content Provider 之Contacts数据库操作

    一篇不错的讲Android Sqlite的文章 http://blog.csdn.net/nieweilin/archive/2010/10/02/5919013.aspxpackage com.android.testapp;import java.io.ByteArrayOutputStream; import java.io.InputStream;import android.app.Activity; import android.content.ContentResolver;…...

    2024/4/26 17:09:20
  2. java工作流引擎Jflow父子流程demo

    关键字驰骋工作流引擎 流程快速开发平台 workflow ccflow jflow .net开源工作流定义 一个流程A的一个节点,因工作的需要调起另外的流程B,A就叫父流程,B就叫子流程。如果流程B的一个节点在调用流程C,那么B相对于C来说就叫父流程,C叫子流程。是子流程还是父流程来说都是相对…...

    2024/4/18 11:36:20
  3. 编程语言学习方法总结

    编程语言学习方法总结在学习编程语言的过程中,我走了许多弯路,也踩了许多坑。以下是我在学习了几门编程语言后总结出的一些学习方法:一、规划在学习一门编程语言时,需要先规划好学习时间。对于总体的学习时间,以及每天的学习时间和每天学习的内容,都要有明确的规划。并且…...

    2024/4/18 13:25:43
  4. 设计模式_改进策略模式_策略模式与简单工厂模式结合(Java)

    上一篇我们介绍了《设计模式_策略模式(Java)》,同时讲述了策略模式与状态模式的区别,如果仔细查看代码或者类图,我们会发现策略模式在一定程度上是存在缺陷的,Client(Test类)必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着Client必须理解这些算法的区别,…...

    2024/4/17 6:36:10
  5. 常用的编程语言的30个深度学习库!

    AlphaGo击败了围棋高手李世石后,令本来就热度不减的深度学习更是火了一把。随着深度学习需求的大大增加,IT人对深度学习库的需求也随之而增加起来。今天,就由大圣众包威客平台为你介绍包括Python、Java、Haskell等在内的一系列编程语言的深度学习库。一、PythonBlocks是一种…...

    2024/4/18 1:32:31
  6. 3D技术有发展前景吗?

    今天听课了解了一下3D技术。开场观看了一些视觉华丽的 由3D技术制作而成的电影以及游戏。譬如画皮,阿凡达,X战警,魔戒(魔戒里面的特效个人非常喜欢,咕噜是我蛮喜欢的一个角色),梦幻西游,DNF,CF,英雄联盟等等。3D技术给一个电影可以增加如此多华丽的场景,真叫人心生感慨…...

    2024/4/19 14:40:52
  7. Android Contacts源码解析

    Android contacts 联系人 通讯录 源码 完全解析 1简介 2软件架构 3各功能模块分析 1联系人数据的显示 1联系人列表显示 2联系人详细信息数据的显示2联系人数据的编辑和存储 1编辑界面相关 2数据存储相关3Sim联系人数据的整合 1Sim卡联系人数据的显示 2开机自动导入Sim卡联系人 …...

    2024/3/31 20:41:28
  8. 如何用Python一门语言通吃高性能并发、GPU计算和深度学习

    【CTO讲堂】如何用Python一门语言通吃高性能并发、GPU计算和深度学习发表于2016-01-04 15:11| 4374次阅读| 来源CSDN| 4 条评论|作者蒲婧CTO俱乐部CTOCTO讲堂Python深度学习GPUallowtransparency="true" frameborder="0" scrolling="no" src=&qu…...

    2024/4/17 6:35:40
  9. 设计模式实例(简单工厂模式,工厂方法模式,抽象工厂模式)

    一、题目分析 (1)、简单工厂模式 使用简单工厂模式模拟女娲(Nvwa)造人(Person),如果传入参数M,则返回一个Man对象,如果传入参数W,则返回一个Woman对象,请实现该场景。现需要增加一个新的Robot类,如果传入参数R,则返回一个Robot对象,对代码进行修改并注意女娲的变化…...

    2024/4/11 12:40:03
  10. 程序员必备5个编程自学网站,你都用到过吗?

    有的人觉得编程难学,而有的人,编程对人家来说就是小菜一叠!其实想学好编程,并没有那么难分享5个程序员必备编程自学网站,看到大家都没有用过赶紧来看一看吧小编是一个有着5年工作经验的java程序员,对于java,自己有做资料的整合,一个完整学习java的路线,学习资料和工具…...

    2024/4/24 19:19:27
  11. 简单的实现人物的移动,跳跃,视角的转动等

    using UnityEngine; using System.Collections; //开始时+一个限制 必须有刚 [RequireComponent (typeof(Rigidbody ))] //碰撞器[RequireComponent(typeof (CapsuleCollider ))] public class playerControll : MonoBehaviour {[System.Serializable] //可视化 //将与速度有关…...

    2024/3/31 20:41:24
  12. 国外在线学习编程网址大全

    国外在线学习编程网址大全 1. http://www.codecademy.com/ 在Codecademy学习如何编写激动人心的网页、游戏和程序。通过Codecademy学习编程。简单、互动、有趣,和你的朋友们一起来吧!该网站提供了基于浏览器交互式教程,探讨了基础编程概念以及具备什么样类型,以便你了解编程…...

    2024/4/19 21:43:29
  13. Ansible安装部署以及常用模块详解

    一. Ansible 介绍Ansible是一个配置管理系统configuration management system, python 语言是运维人员必须会的语言, ansible 是一个基于python 开发的(集合了众多运维工具 puppet、cfengine、chef、func、fabric的优点)自动化运维工具, 其功能实现基于ssh远程连接服务, ans…...

    2024/4/20 14:08:34
  14. Python入门深度学习完整指南

    介绍深度学习目前已经成为了人工智能领域的突出话题。它在“计算机视觉”和游戏(AlphaGo)等领域的突出表现而闻名,甚至超越了人类的能力。近几年对深度学习的关注度也在不断上升,这里有一个调查结果可以参考。这里有一个 Google 的搜索趋势图:如果你对这个话题感兴趣,这里…...

    2024/4/21 20:52:04
  15. [设计模式] 抽象工厂模式

    定义 抽象工厂模式,由一个抽象工厂提供一个接口,用于创建相关或依赖对象,而不需要明确指定具体类。 使用场景 需要创建一个对象家族或者想要使创建的产品集合起来时,可以使用抽象工厂模式。 UML类图抽象工厂模式和工厂方法模式相比,二者的共同点是都可以将对象的创建进行封…...

    2024/4/18 1:33:36
  16. 深度学习中用到的python包

    其中用到的Python包有: * numpy是使用Python进行科学计算的基础包。 * matplotlib是Python中著名的绘图库。 * h5py在Python提供读取HDF5二进制数据格式文件的接口,本次的训练及测试图片集是以HDF5储存的。 * PIL(Python Image Library)为Python提供图像处理功能。 * sci…...

    2024/4/17 6:36:58
  17. 从零开始学安全(十二)●建立自己的DNS服务器

    我们的环境windows server 2012 虚拟机 打开服务器的添加角色和向导功能 添加DNF服务器安装点击在正向查找区域 反键新建区域这里我一般输入一级域名 这是输入baidu.com 一直下一步默认 让后新建主机这里我们输入 www ip 地址就是dnf 在解析用户输入的域名后 要跳到的ip…...

    2024/4/24 8:56:44
  18. contacts模块功能分析

    1. 简介 本文基于MTK6516代码进行分析联系人模块的功能及数据库操作的流程。 联系人是手机功能中不可缺少的模块,主要记录用户的联系人数据,方便用户快捷的操作和使用,主要包括本机联系人和Sim卡联系人。 本机联系人主要存储在手机内部存储空间,Android平台上是通过数据…...

    2024/4/17 6:37:04
  19. spring代理工厂类图

    最近在整理和复习spring事务控制,顺便复习了下spring aop,也顺便调整下博客的风格。 这个系列包括 (1)spring 代理工厂 (2)spring 代理的类图 (3)spring事务的配置 (4)spring事务拦截器实现 本文中希望达到的目标: 通过类图展示出spring代理工厂是怎么实现的…...

    2024/4/17 6:36:58
  20. python、机器学习、深度学习资源推荐

    一、公众号资源推荐——公众号“勇敢AI”“勇敢AI”——一个专注于人工智能的微信公众平台。本人新开创了一个公众号,经过长时间的积累,也积累了大量的资源,有众多的福利与大家分享,希望有兴趣的关注一下福利如下:1、海量电子书资源后面还会持续收录相关的电子书,希望大家…...

    2024/4/17 6:36:58

最新文章

  1. ubuntu samba 安装与配置

    ubuntu samba 安装与配置 一&#xff1a;安装二&#xff1a;添加samba访问账号及密码三&#xff1a;修改配置文件四&#xff1a;重启服务五&#xff1a;登录 一&#xff1a;安装 sudo apt update sudo apt install samba samba-common二&#xff1a;添加samba访问账号及密码 …...

    2024/4/27 9:13:33
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. DDIM,多样性与运行效率之间的trade off

    DDPM的重大缺陷在于其在反向扩散的过程中需要逐步从 x t x_t xt​倒推到 x 0 x_0 x0​&#xff0c;因此其推理速度非常缓慢。相反&#xff0c;DDPM的训练过程是很快的&#xff0c;可以直接根据 x 0 x_0 x0​到 x t x_t xt​添加的高斯噪声 ϵ \epsilon ϵ完成一次训练。 为了解…...

    2024/4/25 10:12:11
  4. 【讲解下Docker in Docker的原理与实践】

    &#x1f308;个人主页:程序员不想敲代码啊&#x1f308; &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f3c6; &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提…...

    2024/4/26 14:50:15
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/26 18:09:39
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/26 20:12:18
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/26 23:05:52
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/27 4:00:35
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/25 18:39:22
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/25 18:39:22
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/26 21:56:58
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/27 9:01:45
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/26 16:00:35
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/25 18:39:16
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/26 22:01:59
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/25 2:10:52
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/25 18:39:00
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/26 19:46:12
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/25 18:38:58
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/27 8:32:30
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57