📄 xfileload.cpp
字号:
//-----------------------------------------------------------------------------
// 名称: RenderSene.cpp
//
// 功能: 进行3D场景的渲染——使用显示内存的顶点缓冲区。
//
//-----------------------------------------------------------------------------
// 包含Direct3D头文件
#include <d3d8.h>
#include <d3dx8.h>
// Windows类的名称宏定义
#define MY_WINCLASS_NAME "Direct3D"
#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000)? 1 : 0)
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000)? 0 : 1)
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
inline DWORD FtoDW( FLOAT f ) { return *((DWORD*)&f); }
struct PLAYER
{
D3DXVECTOR3 LookAt[3];
};
// 定义全局变量
LPDIRECT3D8 g_pd3d = NULL; // 定义Direct3D对象的指针
LPDIRECT3DDEVICE8 g_pd3dDevice = NULL; // 定义Direct3D设备指针
LPD3DXMESH g_pMesh = NULL; // 定义指向网格对象的指针
D3DMATERIAL8* g_pMaterialsMesh = NULL; // 定义网格模型的材质指针
LPDIRECT3DTEXTURE8* g_pTexturesMesh = NULL; // 定义用于模型渲染的纹理指针变量
DWORD g_dwNumMaterials = 0L; // 定义网格模型使用材质数量的变量
PLAYER g_Player;
float g_Angle = 0;
//-----------------------------------------------------------------------------
// 名称: LoadXfile()
// 功能: 从一个文件中载入一个模型文件,包括创建相关的材质和纹理资源。
// 函数返回E_FAIL表示失败,返回E_OK表示成功。
//-----------------------------------------------------------------------------
HRESULT LoadXfile(LPSTR pFilename)
{
LPD3DXBUFFER pD3DXMtrlBuffer;
// 从模型文件中读入模型数据
if( FAILED( D3DXLoadMeshFromX( pFilename, D3DXMESH_SYSTEMMEM,
g_pd3dDevice, NULL,
&pD3DXMtrlBuffer, &g_dwNumMaterials,
&g_pMesh ) ) )
{
return E_FAIL;
}
// 获取模型的材质和纹理信息
D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
// 根据材质的数量创建材质资源
g_pMaterialsMesh = new D3DMATERIAL8[g_dwNumMaterials];
// 创建包含所有纹理指针的数组
g_pTexturesMesh = new LPDIRECT3DTEXTURE8[g_dwNumMaterials];
for( DWORD i=0; i<g_dwNumMaterials; i++ )
{
// 复制材质信息
g_pMaterialsMesh[i] = d3dxMaterials[i].MatD3D;
// 设置材质的散射光颜色
g_pMaterialsMesh[i].Ambient = g_pMaterialsMesh[i].Diffuse;
// 根据纹理的文件名创建纹理资源,如果创建失败,纹理指针必须赋成NULL
if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice,
d3dxMaterials[i].pTextureFilename,
&g_pTexturesMesh[i] ) ) )
{
g_pTexturesMesh[i] = NULL;
}
}
// 材质信息已经保存到g_pMeshMaterials中,释放临时资源
pD3DXMtrlBuffer->Release();
return S_OK;
}
//-----------------------------------------------------------------------------
// 名称: InitD3D()
// 功能: 初始化3D环境的函数,函数中创建了Direct3D对象和Direct3D设备。
// 函数返回E_FAIL表示失败,返回E_OK表示成功。
//-----------------------------------------------------------------------------
HRESULT InitMy3D( HWND hWnd )
{
// 创建Direct3D对象,是使用Direct3D的第一步操作
if( NULL == ( g_pd3d = Direct3DCreate8( D3D_SDK_VERSION ) ) )
return E_FAIL;
// 获取当前Windows桌面的显示模式,保存到定义的d3ddm结构中
D3DDISPLAYMODE d3ddm;
if( FAILED( g_pd3d->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
return E_FAIL;
// 定义Present结构
D3DPRESENT_PARAMETERS d3dpp;
// 把结构清零,创建设备时,结构中成员值为0表示使用缺省值
ZeroMemory( &d3dpp, sizeof(d3dpp) );
// 指定创建的Direct3D是支持窗口的设备
d3dpp.Windowed = TRUE;
// 指定交换效果为D3DSWAPEFFECT_DISCARD,即把后台表面显示到前台表面以后,
// 原来的后台表面包含的信息自动丢失
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
// 后台缓冲区的的点格式与当前显示模式的点格式一致
d3dpp.BackBufferFormat = d3ddm.Format;
// 创建Direct3D设备:
// 1. 使用主显卡创建设备,参数D3DADAPTER_DEFAULT
// 2. 设备类型为硬件抽象设备,使用硬件加速功能,参数D3DDEVTYPE_HAL
// 3. 使用前面创建的窗口用于目标表面的显示,参数hWnd
// 4. 指定设备的对于顶点的处理能力为软件处理顶点,这是为了能够让所有
// 的显卡支持,参数D3DCREATE_SOFTWARE_VERTEXPROCESSING
if( FAILED( g_pd3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}
// 载入模型文件
if(FAILED(LoadXfile("tiger.x")))
{
return E_FAIL;
}
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );
g_Player.LookAt[0] = D3DXVECTOR3( -3.0f, 0.0f, 0.0f );
g_Player.LookAt[1] = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
g_Player.LookAt[2] = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
return S_OK;
}
//-----------------------------------------------------------------------------
// 名称: MatricesTrans()
// 功能: 处理转换操作
//-----------------------------------------------------------------------------
VOID MatricesTrans()
{
// 世界坐标系转换,让模型在Y轴方向上旋转
D3DXMATRIX matWorld;
D3DXMatrixRotationY( &matWorld, timeGetTime()/1000.0f );
// g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
// 进行观察坐标系转换
D3DXMATRIX matView;
D3DXMatrixLookAtLH( &matView, &(g_Player.LookAt[0]),
&(g_Player.LookAt[1]),
&(g_Player.LookAt[2]) );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
// 进行透视转换
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/2.5, 1.0f, 1.0f, 1000.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}
//-----------------------------------------------------------------------------
// 名称: ProcInput()
// 功能: 处理外部控制设备的输入
//-----------------------------------------------------------------------------
VOID ProcInput()
{
if(KEYDOWN(VK_DOWN))
{
g_Player.LookAt[0].x = g_Player.LookAt[0].x-sinf(g_Angle)/20;
g_Player.LookAt[0].z = g_Player.LookAt[0].z-cosf(g_Angle)/20;
g_Player.LookAt[1].x = g_Player.LookAt[1].x-sinf(g_Angle)/20;
g_Player.LookAt[1].z = g_Player.LookAt[1].z-cosf(g_Angle)/20;
}
if(KEYDOWN(VK_UP))
{
g_Player.LookAt[0].x = g_Player.LookAt[0].x+sinf(g_Angle)/20;
g_Player.LookAt[0].z = g_Player.LookAt[0].z+cosf(g_Angle)/20;
g_Player.LookAt[1].x = g_Player.LookAt[1].x+sinf(g_Angle)/20;
g_Player.LookAt[1].z = g_Player.LookAt[1].z+cosf(g_Angle)/20;
}
if(KEYDOWN(VK_RIGHT))
{
g_Angle+=0.01f;
g_Player.LookAt[1].x = g_Player.LookAt[0].x+sinf(g_Angle);
g_Player.LookAt[1].z = g_Player.LookAt[0].z+cosf(g_Angle);
}
if(KEYDOWN(VK_LEFT))
{
g_Angle-=0.01f;
g_Player.LookAt[1].x = g_Player.LookAt[0].x+sinf(g_Angle);
g_Player.LookAt[1].z = g_Player.LookAt[0].z+cosf(g_Angle);
}
return;
}
//-----------------------------------------------------------------------------
// 名称: RenderSene()
// 功能: 渲染3D场景
//-----------------------------------------------------------------------------
VOID RenderSene()
{
D3DXMATRIX matWorld;
D3DXMATRIX matWorldRo;
//检查Direct3D设备是否已经创建,如果没有创建就直接返回
if( NULL == g_pd3dDevice )
return;
// 清除Direct3D设备的后台表面
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(255,255,255), 1.0f, 0 );
// 打开3D渲染开关
g_pd3dDevice->BeginScene();
//**************************************************************
// 渲染模型
//**************************************************************
// 通过一个循环来渲染网格模型的各个子部分
for( DWORD i=0; i<g_dwNumMaterials; i++ )
{
// 为网格模型的一个子部分设置材质和纹理
g_pd3dDevice->SetMaterial( &g_pMaterialsMesh[i] );
g_pd3dDevice->SetTexture( 0, g_pTexturesMesh[i] );
// 渲染出一个子部分
g_pMesh->DrawSubset( i );
}
// 关闭3D渲染开关
g_pd3dDevice->EndScene();
// 展现后台表面到窗口的客户区域中,即把渲染后的图像显示到窗口中
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
return;
}
//-----------------------------------------------------------------------------
// 名称: Cleanup()
// 功能: 释放创建过的Direct3D对象和设备
//-----------------------------------------------------------------------------
VOID Cleanup()
{
// 释放材质数组
if( g_pMaterialsMesh != NULL )
delete[] g_pMaterialsMesh;
if( g_pTexturesMesh )
{
// 使用一个循环释放纹理资源
for( DWORD i = 0; i < g_dwNumMaterials; i++ )
{
if( g_pTexturesMesh[i] )
g_pTexturesMesh[i]->Release();
}
// 释放纹理指针的数组内存
delete[] g_pTexturesMesh;
}
// 释放网格模型资源
if( g_pMesh != NULL )
g_pMesh->Release();
// 释放时的顺序为先释放后创建的对象,设备后创建,先释放
SAFE_RELEASE(g_pd3dDevice);
// Direct3D对象最先创建,但需要最后释放
SAFE_RELEASE(g_pd3d);
return;
}
//-----------------------------------------------------------------------------
// 名称: MsgProc()
// 功能: Windows的消息处理函数
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
//-----------------------------------------------------------------------------
// 名称: WinMain()
// 功能: Windows主函数,程序启动时,从这里开始执行
//-----------------------------------------------------------------------------
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// 定义一个Windows类,指定消息的处理函数为MsgProc
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
MY_WINCLASS_NAME, NULL };
// 注册这个窗口类
RegisterClassEx( &wc );
// 创建应用程序窗口
HWND hWnd = CreateWindow( MY_WINCLASS_NAME, "3D游戏编程——载入模型",
WS_OVERLAPPEDWINDOW, 100, 100, 400, 300,
GetDesktopWindow(), NULL, wc.hInstance, NULL );
// 调用InitMy3D函数进行3D对象和设备的创建,传入参数为窗口的句柄hWnd
if( SUCCEEDED( InitMy3D( hWnd ) ) )
{
// 显示窗口
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
// 程序主循环,进行窗口消息的分发,消息的处理在MsgProc函数中完成
MSG msg;
while( msg.message != WM_QUIT)
{
if(PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ))
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
ProcInput();
MatricesTrans();
RenderSene();
}
}
// 调用Cleanup函数清除3D对象和设备
Cleanup();
// 注销窗口类
UnregisterClass( MY_WINCLASS_NAME, wc.hInstance );
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -