[引] 加载一个三维模型
//****************************************************************************
//说明:
//开发环境:Visual C++.NET 7.1.3091 DirectX 9.0C
//操作系统:WindowsXP SP2
//硬件:AMD Athlon XP 2500+,DDR400 256MB,Geforce4 MX440 AGP 8X 64MB
//****************************************************************************
#include<d3d9.h>
#include<d3dx9.h>
#include<windows.h>
#include<d3d9types.h>
#include<d3dx9math.h>
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"Winmm.lib")
//变量说明
HWND hWnd;
LPDIRECT3D9 D3d9;
LPDIRECT3DDEVICE9 D3dDevice9;
LPD3DXMESH m_pMesh; //Mesh对象的接口指针
D3DMATERIAL9 *m_pMeshMaterials; //用于保存模型中各个子集的材质
LPDIRECT3DTEXTURE9 *m_pMeshTextures; //用于保存模型中各个子集的纹理
DWORD m_dwNumSubsets; //模型中子集的数目
//函数申明
BOOL InitWindow(HINSTANCE hInstance,int nCmdShow);
LRESULT CALLBACK WinProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
//*******************************************************************
//函数:InitWindow()
//功能:创建窗口
//编写人:梁志斌
//*******************************************************************
static BOOL InitWindow(HINSTANCE hInstance,int nCmdShow)
{
WNDCLASS wndcls;
wndcls.cbClsExtra=0; //分配给窗口类结构之后的额外字节数
wndcls.cbWndExtra=0; //分配给窗口实例之后的额外的字节数
wndcls.hbrBackground=CreateSolidBrush(RGB(0,0,255));//蓝色背景
wndcls.hCursor=LoadCursor(NULL,IDC_ARROW); //窗口中的鼠标形状
wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //窗口图标
wndcls.hInstance=hInstance; //窗口所对应的应用程序的句柄
wndcls.lpfnWndProc=(WNDPROC)WinProc; //窗口消息处理函数的指针
wndcls.lpszClassName="DirectX"; //窗口的类名称
wndcls.lpszMenuName=NULL; //窗口的菜单资源名称
wndcls.style= NULL; //窗口的风格
if(!RegisterClass(&wndcls))
{
::MessageBox(0, "RegisterClass() - FAILED", 0, 0);
return FALSE;
}
hWnd=CreateWindow("DirectX","游戏主窗口",WS_POPUP|WS_MAXIMIZE,0,0,
GetSystemMetrics(SM_CXSCREEN),//此函数返回屏幕宽度
GetSystemMetrics(SM_CYSCREEN),//此函数返回屏幕高度
GetDesktopWindow(),NULL,hInstance,NULL);
if(!hWnd)
{
::MessageBox(0, "CreateWindow() - FAILED", 0, 0);
return FALSE;
}
ShowWindow(hWnd,SW_SHOWNORMAL);
UpdateWindow(hWnd);
return TRUE;
}
//**********************************************************************
//函数:InitD3D()
//功能:初始化D3D
//编写人:梁志斌
//**********************************************************************
bool InitD3D()
{
if(NULL==(D3d9=Direct3DCreate9(D3D_SDK_VERSION)))
{
::MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
return FALSE;
}
D3DDISPLAYMODE d3ddm;
if(D3D_OK!=(D3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddm)))
{
::MessageBox(0,"GetAdapterDisplayMode() - FAILED",0,0);
return FALSE;
}
D3DPRESENT_PARAMETERS D3dpp;
ZeroMemory(&D3dpp, sizeof(D3dpp));
D3dpp.Windowed=false;
D3dpp.hDeviceWindow=hWnd;
D3dpp.SwapEffect=D3DSWAPEFFECT_FLIP;
D3dpp.BackBufferCount=1; //有一个后台缓存
D3dpp.BackBufferWidth=d3ddm.Width;//屏幕宽度
D3dpp.BackBufferHeight=d3ddm.Height;//屏幕长度
//立即显示刷新后的图像
D3dpp.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
D3dpp.BackBufferFormat=D3DFMT_X8R8G8B8;//色彩深度
//开启自动深度缓冲
D3dpp.EnableAutoDepthStencil=true;
D3dpp.AutoDepthStencilFormat=D3DFMT_D24S8;//24位深度缓冲并保留8位模版缓冲(stencil buffer)
if(D3D_OK!=(D3d9->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&D3dpp,&D3dDevice9)))
{
::MessageBox(0, "CreateDevice() - FAILED", 0, 0);
return FALSE;
}
//启用Z缓存,允许消隐处理
D3dDevice9->SetRenderState(D3DRS_ZENABLE,D3DZB_TRUE);
//打开光照处理
D3dDevice9->SetRenderState( D3DRS_LIGHTING, TRUE );
//自动对法线矢量进行归一化处理
D3dDevice9->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );
return true;
}
void SetLight()
{
//创建一个白色的平行光
D3DLIGHT9 light;
::ZeroMemory( &light, sizeof(D3DLIGHT9) );
light.Type = D3DLIGHT_DIRECTIONAL; //灯光类型
light.Diffuse.r = 1.0f;
light.Diffuse.g = 1.0f;
light.Diffuse.b = 1.0f;
light.Direction = D3DXVECTOR3( -1.0f, -1.0f, 0.0f );
light.Range = 1000.0f; //灯光的作用范围
D3dDevice9->SetLight( 0, &light ); //设置灯光,参数1为灯光的索引号
D3dDevice9->LightEnable( 0, TRUE ); //打开灯光,参数1为灯光的索引号
//设置环境光
D3dDevice9->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_RGBA(32,32,32,0) );
}
int InitGeometry()
{
//我们将通过该接口指针访问Mesh对象的材质和纹理
LPD3DXBUFFER pD3DXMtrlBuffer;
//从.x文件创建Mesh对象
if(FAILED(D3DXLoadMeshFromX("su37.x",D3DXMESH_SYSTEMMEM,D3dDevice9,NULL,&pD3DXMtrlBuffer,NULL,&m_dwNumSubsets,&m_pMesh)))
{
::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);
return FALSE;
}
m_pMeshMaterials = new D3DMATERIAL9[m_dwNumSubsets];
m_pMeshTextures = new LPDIRECT3DTEXTURE9[m_dwNumSubsets];
//从接口指针pD3DXMtrlBuffer获得各个子集的材质和纹理图片的文件名
D3DXMATERIAL* d3dxMaterials=(D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
for( DWORD i=0;i<m_dwNumSubsets;i++ )
{
//复制子集的材质
m_pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
//Direct3D在调入Mesh模型时,没有设置材质的环境光颜色,
//这里把它设置成和漫反射一样的颜色。
m_pMeshMaterials[i].Ambient = m_pMeshMaterials[i].Diffuse;
//调入纹理图片
if(FAILED(D3DXCreateTextureFromFile(D3dDevice9,d3dxMaterials[i].pTextureFilename,&m_pMeshTextures[i])))
{
::MessageBox(0, "D3DXCreateTextureFromFile() - FAILED", 0, 0);
return FALSE;
}
}
pD3DXMtrlBuffer->Release(); //释放接口
}
void SetupMatrices()
{
D3DXMATRIX matWorld;
UINT iTime = timeGetTime() % 5000;
FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 5000.0f;//把旋转角换算成弧度
D3DXMatrixRotationY( &matWorld, fAngle );//计算世界变换矩阵
D3dDevice9->SetTransform( D3DTS_WORLD, &matWorld );//把世界变换矩阵设置到渲染环境
D3DXVECTOR3 vEyePt( 0.0f, 15.0f,-25.0f );//观察点
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );//视线目标点
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );//上方向
D3DXMATRIX matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );//计算视角变换矩阵
D3dDevice9->SetTransform( D3DTS_VIEW, &matView );//把视角变换矩阵设置到渲染环境
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );//计算透视投影变换矩阵
D3dDevice9->SetTransform( D3DTS_PROJECTION, &matProj );//把投影变换矩阵设置到渲染环境
}
VOID Cleanup()
{
if(D3dDevice9!=NULL)
D3dDevice9->Release();
if(D3d9!=NULL)
D3d9->Release();
for (DWORD i=0;i<m_dwNumSubsets;i++)
m_pMeshTextures[i]->Release(); //释放纹理对象
delete [] m_pMeshMaterials;
delete [] m_pMeshTextures;
m_pMesh->Release(); //释放Mesh对象
}
VOID Render()
{
//用蓝色清空背景区域
D3dDevice9->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,255),1.0f,0);
// 开始绘制场景
if(SUCCEEDED(D3dDevice9->BeginScene()))
{
SetupMatrices();//设置变换矩阵
SetLight(); //设置灯光
for( DWORD i=0; i < m_dwNumSubsets; i++ )
{
//设置子集的材质
D3dDevice9->SetMaterial( &m_pMeshMaterials[i] );
//设置子集的纹理,混合方式使用缺省值:纹理 × 材质的漫反射
D3dDevice9->SetTexture( 0, m_pMeshTextures[i] );
//绘制子集
m_pMesh->DrawSubset( i );
D3dDevice9->SetTexture( 0, NULL);
}
}
// 结束场景绘制
D3dDevice9->EndScene();
// 显示到屏幕上
D3dDevice9->Present(NULL,NULL,NULL,NULL);
}
//**********************************************************************
//函数:WinMain()
//功能:Windows 程序入口函数。创建主窗口,处理消息循环
//编写人:梁志斌
//**********************************************************************
int WINAPI WinMain(HINSTANCE hInstance, //hInstance:表示该应用程序的句柄
HINSTANCE hPrevInstance, //hPrevInstance:为了保持与16位windows应用程序的兼容性
LPSTR lpCmdLine, //lpCmdLine:指向命令行参数字符串的指针
int nCmdShow) //nCmdShow:指定应用程序窗口显示方式的整数
{
InitWindow(hInstance,nCmdShow);
InitD3D();
InitGeometry();
//Render(); //渲染
MSG msg;
ZeroMemory( &msg, sizeof(msg) );
while(GetMessage(&msg,NULL,0,0))
{
Render(); //渲染
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return (int)msg.wParam;
}
//*******************************************************************
//函数:WinProc()
//功能:处理窗口消息
//编写人:梁志斌
//*******************************************************************
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_KEYDOWN: //击键消息
switch(wParam)
{
case VK_ESCAPE:
DestroyWindow(hWnd); //释放窗口
Cleanup();
PostQuitMessage(0); //给窗口发送WM_QUIT消息
return 0; //处理完一个消息后返回0
}
//case WM_RBUTTONDOWN:
// MessageBox(hWnd,"鼠标右键按下了!","Mouse",MB_OK);
return 0;
}
return DefWindowProc(hWnd,msg,wParam,lParam); //调用缺省消息处理过程
/*
if(GetAsyncKeyState(VK_ESCAPE))
{
DestroyWindow(hWnd); //释放窗口
Cleanup();
PostQuitMessage(0); //给窗口发送WM_QUIT消息
}
*/
return 0;
}