演示程序下载地址:http://download.csdn.net/detail/jiangcaiyang123/4060455
程序的截图如下所示:
设计游戏菜单背景循环移动
DirectX的纹理很重要。就像一个人的脸一样。如果没有它,就好像人的脸上没有五官一样难看。所以要对于我们这些初学者来说,掌握纹理的处理就相当于了解相当部分的DirectX知识一样。这回我就利用上了DirectX中纹理的一些知识,来实现游戏中常常出现的菜单背景循环移动的场景。
要使用纹理,首先要学会载入纹理。我使用D3DXCreateTextureFromFileEx()这个函数。因为它可控制的参数多,可以达到很好的效果。欲了解此函数的参数,请查阅MSDN。载入了图片后,我使用其中的D3DXIMAGE_INFO的结构体来获得它的宽和高。获得了以后可以将该纹理平铺至屏幕上。这里假设屏幕的分辨率是640×480。
在载入了纹理之后,使用自定义的顶点格式。该格式的定义如下:
struct STVertex// 定义自己的顶点结构体
{
float x, y, z;// 纹理坐标位置
float u, v;
// 纹理坐标内的位置
}
其中控制纹理的平铺则使用的是U和V这两个变量。那么接下来我就在渲染的过程中改变这两个变量,获得循环移动的效果。在U和V处于0以下或者是1.0以上的范围,它的渲染行为通常是不固定的。但是DirectX内部默认的是平铺的效果。也可以改变其为镜面平铺、不渲染的效果(参见《Real Time Rendering》丛书)。我们不必更改,使用默认平铺效果即可。
最后设置灵活顶点格式(FVF),设置顶点流的源,和使用DrawPrimitive来绘制图形。
以下是程序的部分代码:
// BackgroundMove.cpp 实现文件 #include "BackgroundMove.h" CBackgroundMove::CBackgroundMove( HINSTANCE hInst, HWND hWnd, LPDIRECT3DDEVICE9 pDevice, int width, int height ) // 构造函数 { // 成员赋值 m_pDevice = pDevice; m_TexOffsetX = 0.0f; m_TexOffsetY = 0.0f; m_MoveSpeedX = 0.005f; m_MoveSpeedY = 0.02f; // 初始化输入系统 m_ImmediateInput.Initialize( IMMEDIATE, hInst, hWnd ); m_BufferInput.Initialize( BUFFERED, hInst, hWnd ); // 设置视角范围 SetViewport( width, height ); // 初始化顶点 InitializeVertices( ); // 设置纹理 SetTexture( width, height ); } void CBackgroundMove::SetViewport( int width, int height ) // 设置视角 { ZeroMemory( &m_Viewport, sizeof( m_Viewport ) );// 清零 m_Viewport.X = 0; m_Viewport.Y = 0; m_Viewport.Width = width; m_Viewport.Height = height; m_Viewport.MinZ = 0.0f; m_Viewport.MaxZ = 1.0f; m_pDevice->SetViewport( &m_Viewport ); } void CBackgroundMove::Draw( void ) // 绘图 { m_pDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); // 绘图函数 // 开始交互 m_ImmediateInput.UpdateKeyState( ); if ( m_ImmediateInput.KeyDown( DIK_UP ) ) { m_pVertices[1].y += 0.05f; m_pVertices[3].y += 0.05f; } if ( m_ImmediateInput.KeyDown( DIK_DOWN ) ) { m_pVertices[1].y -= 0.05f; m_pVertices[3].y -= 0.05f; } // 调整移动速率的 if ( m_ImmediateInput.KeyDown( DIK_D ) ) { m_MoveSpeedX += 0.005f; } if ( m_ImmediateInput.KeyDown( DIK_A ) ) { m_MoveSpeedX -= 0.005f; } if ( m_ImmediateInput.KeyDown( DIK_W ) ) { m_MoveSpeedY += 0.005f; } if ( m_ImmediateInput.KeyDown( DIK_S ) ) { m_MoveSpeedY -= 0.005f; } // 纹理的背景自动移动 int i; for ( i = 0; i < 4; i++ ) { m_pVertices[i].u += m_MoveSpeedX; m_pVertices[i].v += m_MoveSpeedY; } } unsigned long CBackgroundMove::Release( void ) // 释放空间 { if ( m_pBuffer != 0 ) { m_pBuffer->Release( ); m_pBuffer = 0; } if ( m_pTexture != 0 ) { m_pBuffer->Release( ); m_pBuffer = 0; } m_ImmediateInput.Release( ); m_BufferInput.Release( ); return 0; } void CBackgroundMove::InitializeVertices( void ) // 初始化顶点 { // 创建顶点缓存 HRESULT hr; hr = m_pDevice->CreateVertexBuffer( 4 * sizeof( STVertex ), D3DUSAGE_WRITEONLY, TEXTURE_FVF, D3DPOOL_MANAGED, &m_pBuffer, NULL ); ThrowIfFailed( hr, "不会吧,这都无法创建顶点缓存。⊙﹏⊙b汗" ); hr = m_pBuffer->Lock( 0, 4 * sizeof( STVertex ), (void**)&m_pVertices, D3DLOCK_DISCARD ); ThrowIfFailed( hr, "不可能,顶点怎么会锁住失败呢??o(>﹏<)o" ); hr = m_pBuffer->Unlock( ); ThrowIfFailed( hr, "不可能,顶点怎么会也会解锁失败呢??o(>﹏<)o" ); // 设置顶点缓存和灵活顶点格式 m_pDevice->SetStreamSource( 0, m_pBuffer, 0, sizeof( STVertex ) ); // 相同资源的顶点缓存要在一起为好 m_pDevice->SetFVF( TEXTURE_FVF ); } void CBackgroundMove::SetTexture( int width, int height ) // 设置纹理 { // 载入纹理 D3DXIMAGE_INFO imageInfo; HRESULT hr; hr = D3DXCreateTextureFromFileEx( // 从文件创建纹理 m_pDevice, // DIRECT3DDEVICE9结构指针 TEXT( "试验图片.png" ), // 载入的图像文件名 D3DX_DEFAULT, // 宽 D3DX_DEFAULT, // 高 D3DX_FROM_FILE, // mip级别 0, // 用途 D3DFMT_A8R8G8B8, // 格式 D3DPOOL_MANAGED, // 内存池格式 D3DX_DEFAULT, // 滤波器 D3DX_DEFAULT, // mip滤波器 0, // 关键色(作掩码用) &imageInfo, // 源文件信息 NULL, // 调色板 &m_pTexture ); // IDirect3DTexture9指针 ThrowIfFailed( hr, "不可能,载入纹理竟然会失败!是不是文件名错误了呢?" ); // 设置顶点 float nU, nV; nU = float( width ) / float( imageInfo.Width ), nV = float( height ) / float( imageInfo.Height ); m_pVertices[0].Set( -1.0f, -1.0f, 1.0f, m_TexOffsetX, m_TexOffsetY + nV ); m_pVertices[1].Set( -1.0f, 1.0f, 1.0f, m_TexOffsetX, m_TexOffsetY ); m_pVertices[2].Set( 1.0f, -1.0f, 1.0f, m_TexOffsetX + nU, m_TexOffsetY + nV ); m_pVertices[3].Set( 1.0f, 1.0f, 1.0f, m_TexOffsetX + nU, m_TexOffsetY ); // 设置关灯 hr = m_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); ThrowIfFailed( hr, "怎么不能关灯了呢?" ); // 设置纹理 hr = m_pDevice->SetTexture( 0, m_pTexture ); ThrowIfFailed( hr, "不可能啊,设置纹理竟然错误?" ); }
程序的截图如下所示: