在潜水很多天后,今天又有时间来这里写文章了。我今天写的文章是有关于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
- 作用:加载游戏片头动画
- ---------------------------------------------------*/
- /*--------------------------------------------------
- 这里借鉴使用了Allen Sherrod的代码
- 所有权归蒋轶民和Allen Sherrod所有
- 详情请见《DirectX游戏开发终极指南》
- ---------------------------------------------------*/
- #include<d3d9.h>
- #include<d3dx9.h>
- #pragma comment(lib, "d3d9.lib")
- #pragma comment(lib, "d3dx9.lib")
- #define APPCLASS "打方块游戏"
- #define WINDOW_TITLE "打方块游戏"
- #define WINDOW_WIDTH 640
- #define WINDOW_HEIGHT 480
- // 函数的原型
- bool InitializeD3D( HWND hWnd, bool fullscreen );
- bool InitializeObjects( void );
- void RenderScene( void );
- void Shutdown( void );
- // Direct3D 对象和装置
- LPDIRECT3D9 g_D3D = NULL;
- LPDIRECT3DDEVICE9 g_D3DDevice = NULL;
- bool flagIncre = false;// 用来标记是颜色是否变量
- short varColor = 0;// 一个全局变量,用来改变颜色,达到渐显的效果
- // 顶点缓存用来保存几何图形
- LPDIRECT3DVERTEXBUFFER9 g_VertexBuffer = NULL;
- // 矩阵类
- D3DXMATRIX g_projection;
- D3DXMATRIX g_ViewMatrix;
- // 用来保存纹理的指针
- LPDIRECT3DTEXTURE9 g_Texture = NULL;
- // 自定义的顶点结构,用来存储位图
- // 其中tu、tv表示起始位置的宽度比和高度比
- struct stD3DVertex
- {
- float x, y, z;
- unsigned long color;
- float tu, tv;
- };
- // 自定义的FVF
- #define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
- // 自定义顶点对象,参数包括x,y,z,颜色和纹理坐标x,y
- stD3DVertex rectData[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}
- };
- LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- switch(msg)
- {
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0;
- break;
- case WM_KEYUP:
- if(wParam == VK_ESCAPE) PostQuitMessage(0);
- break;
- }
- return DefWindowProc(hWnd, msg, wParam, lParam);
- }
- int WINAPI WinMain( HINSTANCE hInst, HINSTANCE prevhInst, LPSTR cmd, int show )
- {
- // 注册窗口类
- WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc,
- 0, 0, GetModuleHandle(NULL), NULL, NULL,
- NULL, NULL, APPCLASS, NULL };
- RegisterClassEx(&wc);
- // 创建窗口
- HWND hWnd = 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 ) )
- {
- // 进入消息循环
- MSG msg;
- ZeroMemory(&msg, sizeof(msg));
- while(msg.message != WM_QUIT)
- {
- if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- else
- { // 开始渲染
- RenderScene();
- }
- }
- }
- else MessageBox( NULL, "程序初始化出错!", "程序信息", MB_OK );
- // 解除注册窗口
- UnregisterClass(APPCLASS, wc.hInstance);
- return 0;
- }
- // 初始化D3D的函数
- bool InitializeD3D( HWND hWnd, bool fullscreen )
- {
- D3DDISPLAYMODE displayMode;
- // 创建D3D对象
- g_D3D = Direct3DCreate9(D3D_SDK_VERSION);
- if( g_D3D == NULL ) return false;
- // 获取电脑的显示模式
- if(FAILED( g_D3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &displayMode ) ) )
- return false;
- // 启动一个结构体,为创建D3D设备做准备
- D3DPRESENT_PARAMETERS d3dpp;
- 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)))
- {
- return false;
- }
- // 初始化将要显示的对象
- if( !InitializeObjects() )
- {
- MessageBox( NULL, "载入初始化对象错误!", "程序通知", MB_OK );
- return false;
- }
- return true;
- }
- bool InitializeObjects( void )
- {
- // 从文件中装载TGA图片
- if( D3DXCreateTextureFromFile(g_D3DDevice, "GIMP_Ubuntu_splash_screen.tga", &g_Texture) != D3D_OK )
- return false;
- // 设置图片的状态
- 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 );
- // 定义摄影机状态
- D3DXVECTOR3 cameraPos(0.0f, 0.0f, -1.0f);
- D3DXVECTOR3 lookAtPos(0.0f, 0.0f, 0.0f);
- D3DXVECTOR3 upDir(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);
- return true;
- }
- void RenderScene( 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;// 颜色递减,结果越明暗
- int i;
- 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);
- }
- // 释放所有的对象
- void Shutdown( 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的图元进行显示,当然这要花费我更多的时间。不过我最近把我所有的作业都完成了,相信我还是有信心在近日完成的!