在潜水很多天后,今天又有时间来这里写文章了。我今天写的文章是有关于DirectX游戏开头画面的,大家肯定看过一些有名的游戏,它们在开头肯定是会显示游戏公司的商标和游戏的图标。但是为了给大家一种电影的感觉,他们往往会逐渐显示这些二维图片。这种显示方式叫做淡入淡出(fade in and fade out)。下面我就用一个例子程序来说说我是怎么使用DirectX来实现这个效果的。
其实在我学习这个效果的时候,我也想了很多。起初我是想用雾(fog)这种特效来模拟的。但是我突然发现使用雾的特效要设置很多很多的参数,而且我在试验的过程中往往得不到应有的效果。这可使我非常失望。原本想通过一个循环,使雾的颜色随着时间的变化而改变,这样的出来的显示效果应该是很好的,可是实际情况并非如此。我的第一种方法泡了汤。
第二种方法是试图使用一个小小的视频来进行显示。我曾经为了实现这个小小的功能,去了有着悠久历史的gamedev.net网站进行询问。来自世界各地的游戏开发者给了我很多答案。其中有个人给我推荐了使用BINK(见http://baike.baidu.com/view/1313785.htm)来进行游戏开场动画的设计。不过要掌握BINK的话,还要很长的一段路,所以第二种方案也没有被我采纳。
最后没有办法。我想要的效果是,只要使用载入一张图片,然后对图片纹理进行不同的渲染,这样不就行了?我这样想着,对下面这样的结构进行分析。
struct stD3DVertex
{
float x, y, z;
unsigned long color;
float tu, tv;
};
这个结构和我以前使用的结构有所不同,这个结构多了tu和tv这两个变量。查了查书,知道这两个变量是描述纹理坐标起始位置和结束位置的。这些值是0~1之间的任意值。而且我仔细地研究了一下,前面三个xyz变量中,有两个变量x、y是表述载入图像显示的位置的,理论上可以无限大还是无限小,但是过大或过小会使图像看不清,所以应在-0.5到0.5之间是最清楚的。然后以颜色为变量,简单地设置一下循环,诶,效果出来啦。
下面就是我的程序的所有代码。
- /*--------------------------------------------------
- 蒋轶民制作:E-mail:jiangcaiyang123@163.com
- 文件名:GameInit.cpp
- 作用:加载游戏片头动画
- ---------------------------------------------------*/
- /*--------------------------------------------------
- 这里借鉴使用了AllenSherrod的代码
- 所有权归蒋轶民和AllenSherrod所有
- 详情请见《DirectX游戏开发终极指南》
- ---------------------------------------------------*/
- #include<d3d9.h>
- #include<d3dx9.h>
- #pragmacomment(lib,"d3d9.lib")
- #pragmacomment(lib,"d3dx9.lib")
- #defineAPPCLASS"打方块游戏"
- #defineWINDOW_TITLE"打方块游戏"
- #defineWINDOW_WIDTH640
- #defineWINDOW_HEIGHT480
- //函数的原型
- boolInitializeD3D(HWNDhWnd,boolfullscreen);
- boolInitializeObjects(void);
- voidRenderScene(void);
- voidShutdown(void);
- //Direct3D对象和装置
- LPDIRECT3D9g_D3D=NULL;
- LPDIRECT3DDEVICE9g_D3DDevice=NULL;
- boolflagIncre=false;//用来标记是颜色是否变量
- shortvarColor=0;//一个全局变量,用来改变颜色,达到渐显的效果
- //顶点缓存用来保存几何图形
- LPDIRECT3DVERTEXBUFFER9g_VertexBuffer=NULL;
- //矩阵类
- D3DXMATRIXg_projection;
- D3DXMATRIXg_ViewMatrix;
- //用来保存纹理的指针
- LPDIRECT3DTEXTURE9g_Texture=NULL;
- //自定义的顶点结构,用来存储位图
- //其中tu、tv表示起始位置的宽度比和高度比
- structstD3DVertex
- {
- floatx,y,z;
- unsignedlongcolor;
- floattu,tv;
- };
- //自定义的FVF
- #defineD3DFVF_VERTEX(D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
- //自定义顶点对象,参数包括x,y,z,颜色和纹理坐标x,y
- stD3DVertexrectData[6]=
- {
- {-0.3f,-0.4f,0.0f,D3DCOLOR_XRGB(0,0,0),0.0f,1.0f},
- {0.3f,-0.4f,0.0f,D3DCOLOR_XRGB(0,0,0),1.0f,1.0f},
- {0.3f,0.4f,0.0f,D3DCOLOR_XRGB(0,0,0),1.0f,0.0f},
- {0.3f,0.4f,0.0f,D3DCOLOR_XRGB(0,0,0),1.0f,0.0f},
- {-0.3f,0.4f,0.0f,D3DCOLOR_XRGB(0,0,0),0.0f,0.0f},
- {-0.3f,-0.4f,0.0f,D3DCOLOR_XRGB(0,0,0),0.0f,1.0f}
- };
- LRESULTWINAPIMsgProc(HWNDhWnd,UINTmsg,WPARAMwParam,LPARAMlParam)
- {
- switch(msg)
- {
- caseWM_DESTROY:
- PostQuitMessage(0);
- return0;
- break;
- caseWM_KEYUP:
- if(wParam==VK_ESCAPE)PostQuitMessage(0);
- break;
- }
- returnDefWindowProc(hWnd,msg,wParam,lParam);
- }
- intWINAPIWinMain(HINSTANCEhInst,HINSTANCEprevhInst,LPSTRcmd,intshow)
- {
- //注册窗口类
- WNDCLASSEXwc={sizeof(WNDCLASSEX),CS_CLASSDC,MsgProc,
- 0,0,GetModuleHandle(NULL),NULL,NULL,
- NULL,NULL,APPCLASS,NULL};
- RegisterClassEx(&wc);
- //创建窗口
- HWNDhWnd=CreateWindow(APPCLASS,WINDOW_TITLE,
- WS_OVERLAPPEDWINDOW,160,40,
- WINDOW_WIDTH,WINDOW_HEIGHT,GetDesktopWindow(),NULL,
- wc.hInstance,NULL);
- //显示窗口
- ShowWindow(hWnd,SW_SHOWDEFAULT);
- UpdateWindow(hWnd);
- //初始化Direct3D
- if(InitializeD3D(hWnd,false))
- {
- //进入消息循环
- MSGmsg;
- ZeroMemory(&msg,sizeof(msg));
- while(msg.message!=WM_QUIT)
- {
- if(PeekMessage(&msg,NULL,0U,0U,PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- else
- {//开始渲染
- RenderScene();
- }
- }
- }
- elseMessageBox(NULL,"程序初始化出错!","程序信息",MB_OK);
- //解除注册窗口
- UnregisterClass(APPCLASS,wc.hInstance);
- return0;
- }
- //初始化D3D的函数
- boolInitializeD3D(HWNDhWnd,boolfullscreen)
- {
- D3DDISPLAYMODEdisplayMode;
- //创建D3D对象
- g_D3D=Direct3DCreate9(D3D_SDK_VERSION);
- if(g_D3D==NULL)returnfalse;
- //获取电脑的显示模式
- if(FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&displayMode)))
- returnfalse;
- //启动一个结构体,为创建D3D设备做准备
- D3DPRESENT_PARAMETERSd3dpp;
- ZeroMemory(&d3dpp,sizeof(d3dpp));
- if(fullscreen)
- {
- d3dpp.Windowed=FALSE;
- d3dpp.BackBufferWidth=640;
- d3dpp.BackBufferHeight=480;
- }
- else
- d3dpp.Windowed=TRUE;
- d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
- d3dpp.BackBufferFormat=displayMode.Format;
- //创建D3D设备
- if(FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,
- D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&g_D3DDevice)))
- {
- returnfalse;
- }
- //初始化将要显示的对象
- if(!InitializeObjects())
- {
- MessageBox(NULL,"载入初始化对象错误!","程序通知",MB_OK);
- returnfalse;
- }
- returntrue;
- }
- boolInitializeObjects(void)
- {
- //从文件中装载TGA图片
- if(D3DXCreateTextureFromFile(g_D3DDevice,"GIMP_Ubuntu_splash_screen.tga",&g_Texture)!=D3D_OK)
- returnfalse;
- //设置图片的状态
- g_D3DDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
- g_D3DDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
- //设置默认的渲染状态
- g_D3DDevice->SetRenderState(D3DRS_LIGHTING,FALSE);
- g_D3DDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
- //设置投影状态
- D3DXMatrixPerspectiveFovLH(&g_projection,45.0f,WINDOW_WIDTH/WINDOW_HEIGHT,
- 0.1f,1000.0f);
- g_D3DDevice->SetTransform(D3DTS_PROJECTION,&g_projection);
- //定义摄影机状态
- D3DXVECTOR3cameraPos(0.0f,0.0f,-1.0f);
- D3DXVECTOR3lookAtPos(0.0f,0.0f,0.0f);
- D3DXVECTOR3upDir(0.0f,1.0f,0.0f);
- //建立矩阵
- D3DXMatrixLookAtLH(&g_ViewMatrix,&cameraPos,&lookAtPos,&upDir);
- //清除后台缓存
- g_D3DDevice->Clear(0,NULL,D3DCLEAR_TARGET,
- D3DCOLOR_XRGB(0,0,0),1.0f,0);
- returntrue;
- }
- voidRenderScene(void)
- {
- if(flagIncre==false&&varColor<255)//让颜色逐渐达到255(白色)
- varColor+=3;//颜色递增,结果越明亮
- if(flagIncre==false&&varColor>=255)
- {
- flagIncre=true;//标记为已经变亮过
- Sleep(2500);//画面停止2.5秒,让用户仔细看游戏图标
- }
- if(flagIncre==true&&varColor>0)
- varColor-=3;//颜色递减,结果越明暗
- inti;
- for(i=0;i<6;rectData[i].color=D3DCOLOR_XRGB(varColor,varColor,varColor),i++);
- //顶点顶点缓存
- if(FAILED(g_D3DDevice->CreateVertexBuffer(sizeof(rectData),0,D3DFVF_VERTEX,D3DPOOL_DEFAULT,&g_VertexBuffer,NULL)))return;
- //锁住顶点缓存,开始在后台缓存上绘制
- void*ptr;
- if(FAILED(g_VertexBuffer->Lock(0,sizeof(rectData),(void**)&ptr,0)))return;
- memcpy(ptr,rectData,sizeof(rectData));
- g_VertexBuffer->Unlock();//解锁
- //开始渲染
- g_D3DDevice->BeginScene();
- //应用视角
- g_D3DDevice->SetTransform(D3DTS_VIEW,&g_ViewMatrix);
- //绘制矩形
- g_D3DDevice->SetTexture(0,g_Texture);
- g_D3DDevice->SetStreamSource(0,g_VertexBuffer,
- 0,sizeof(stD3DVertex));
- g_D3DDevice->SetFVF(D3DFVF_VERTEX);
- g_D3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,2);
- //结束渲染
- g_D3DDevice->EndScene();
- //D显示场景
- g_D3DDevice->Present(NULL,NULL,NULL,NULL);
- }
- //释放所有的对象
- voidShutdown(void)
- {
- if(g_D3DDevice!=NULL)g_D3DDevice->Release();
- g_D3DDevice=NULL;
- if(g_D3D!=NULL)g_D3D->Release();
- g_D3D=NULL;
- if(g_VertexBuffer!=NULL)g_VertexBuffer->Release();
- g_VertexBuffer=NULL;
- if(g_Texture!=NULL)g_Texture->Release();
- g_Texture=NULL;
- }
程序的截图如下所示:
程序效果还是挺好的,这里需要载入GIMP_Ubuntu_splash_screen.tga文件。这个文件是我使用ubuntu操作系统自带的图片进行的格式转换。顺便说说,ubuntu操作系统下的ginp的确很好,好得能和windows下的photoshop相媲美!
好了,今天我的工作就是这样了。下一次我想制作的是游戏开头的动画,当然不是载入的那种啦,我是想用DirectX的图元进行显示,当然这要花费我更多的时间。不过我最近把我所有的作业都完成了,相信我还是有信心在近日完成的!