📄 main.cpp
字号:
/**-----------------------------------------------------------------------------
* \brief 广告牌处理
* 文件: main.cpp
*
* 说明: 熟悉广告牌处理方法
*
*------------------------------------------------------------------------------
*/
#define MAINBODY
#include <d3d9.h>
#include <d3dx9.h>
#include "ZCamera.h"
#include "ZFLog.h"
#include "ZWater.h"
#define WINDOW_W 500
#define WINDOW_H 500
#define WINDOW_TITLE "Billboard"
/**-----------------------------------------------------------------------------
* 全局参数
*------------------------------------------------------------------------------
*/
HWND g_hwnd = NULL;
LPDIRECT3D9 g_pD3D = NULL; // 创建D3D设备的D3D对象参数
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // 渲染中使用的D3D设备
LPDIRECT3DTEXTURE9 g_pTexBillboard[4] = { NULL, NULL, NULL, NULL };// 广告牌使用的纹理
D3DXMATRIXA16 g_matAni;
D3DXMATRIXA16 g_matWorld;
D3DXMATRIXA16 g_matView;
D3DXMATRIXA16 g_matProj;
DWORD g_dwMouseX = 0; // 鼠标的坐标
DWORD g_dwMouseY = 0; // 鼠标的坐标
BOOL g_bBillboard = TRUE; // 进行广告牌处理吗?
BOOL g_bWireframe = FALSE; // 绘制线框吗?
ZCamera* g_pCamera = NULL; // Camera 类
ZWater* g_pWater = NULL;
/**-----------------------------------------------------------------------------
* Direct3D初始化
*------------------------------------------------------------------------------
*/
HRESULT InitD3D( HWND hWnd )
{
// 创建一个用来创建设备的D3D对象
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
// 创建设备的结构体
// 绘制复杂对象时需要Z-缓冲.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
/// 创建设备
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}
// 基本卷起, CCW
g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
// 起到Z-缓冲功能.
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
return S_OK;
}
/**-----------------------------------------------------------------------------
* 创建矩阵
*------------------------------------------------------------------------------
*/
void InitMatrix()
{
/// 创建世界矩阵
D3DXMatrixIdentity( &g_matWorld );
g_pd3dDevice->SetTransform( D3DTS_WORLD, &g_matWorld );
/// 创建视图矩阵
D3DXVECTOR3 vEyePt( 0.0f, 5.0f, (float)-3.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 5.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMatrixLookAtLH( &g_matView, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &g_matView );
/// 实际投影矩阵
D3DXMatrixPerspectiveFovLH( &g_matProj, D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &g_matProj );
/// Frustum 卷起用投影矩阵
D3DXMatrixPerspectiveFovLH( &g_matProj, D3DX_PI/4, 1.0f, 1.0f, 200.0f );
/// 摄像机初始化
g_pCamera->SetView( &vEyePt, &vLookatPt, &vUpVec );
}
/**-----------------------------------------------------------------------------
* 几何信息初始化
*------------------------------------------------------------------------------
*/
HRESULT InitGeometry()
{
InitMatrix();
// 广告牌使用的纹理图像
D3DXCreateTextureFromFile( g_pd3dDevice, "tree01S.dds", &g_pTexBillboard[0] );
D3DXCreateTextureFromFile( g_pd3dDevice, "tree02S.dds", &g_pTexBillboard[1] );
D3DXCreateTextureFromFile( g_pd3dDevice, "tree35S.dds", &g_pTexBillboard[2] );
D3DXCreateTextureFromFile( g_pd3dDevice, "hiah.bmp", &g_pTexBillboard[3] );
// 保存最初的鼠标位置
POINT pt;
GetCursorPos( &pt );
g_dwMouseX = pt.x;
g_dwMouseY = pt.y;
return S_OK;
}
HRESULT InitObjects()
{
g_pLog = new ZFLog( ZF_LOG_TARGET_WINDOW );
g_pCamera = new ZCamera;
g_pWater = new ZWater;
g_pWater->Create( g_pd3dDevice, 64, 64, 100 );
return S_OK;
}
void DeleteObjects()
{
/// 删除注册的类
S_DEL( g_pWater );
S_DEL( g_pLog );
S_DEL( g_pCamera );
}
/**-----------------------------------------------------------------------------
* 删除初始化对象
*------------------------------------------------------------------------------
*/
VOID Cleanup()
{
for( int i = 0 ; i < 4 ; i++ ) S_REL( g_pTexBillboard[i] );
S_REL( g_pd3dDevice );
S_REL( g_pD3D );
}
/**-----------------------------------------------------------------------------
* 创建光源
*------------------------------------------------------------------------------
*/
VOID SetupLights()
{
/// 创建材质(material)
/// 在设备中创建一个材质.
D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f;
mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
g_pd3dDevice->SetMaterial( &mtrl );
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); /// 打开光源设置
g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff ); /// 设定环境光源(ambient light)的值
}
/**-----------------------------------------------------------------------------
* 输出Status信息
*------------------------------------------------------------------------------
*/
void LogStatus( void )
{
g_pLog->Log( "Wireframe:%d", g_bWireframe );
g_pLog->Log( "BillBoard:%d", g_bBillboard );
}
/**-----------------------------------------------------------------------------
* FPS(Frame Per Second)输出
*------------------------------------------------------------------------------
*/
void LogFPS(void)
{
static DWORD nTick = 0;
static DWORD nFPS = 0;
/// 1秒过去?
if( GetTickCount() - nTick > 1000 )
{
nTick = GetTickCount();
/// FPS值输出
g_pLog->Log("FPS:%d", nFPS );
nFPS = 0;
LogStatus(); /// 输出状态信息(1秒1次)
return;
}
nFPS++;
}
/**-----------------------------------------------------------------------------
* 鼠标输入处理
*------------------------------------------------------------------------------
*/
void ProcessMouse( void )
{
POINT pt;
float fDelta = 0.001f; // 鼠标的灵敏度,该值越大移动越多.
GetCursorPos( &pt );
int dx = pt.x - g_dwMouseX; // 鼠标的变化值
int dy = pt.y - g_dwMouseY; // 鼠标的变化值
g_pCamera->RotateLocalX( dy * fDelta ); // 鼠标的Y轴旋转值为 3D world的X轴旋转值
g_pCamera->RotateLocalY( dx * fDelta ); // 鼠标的X轴旋转值为 3D world的Y轴旋转值
D3DXMATRIXA16* pmatView = g_pCamera->GetViewMatrix(); // 获得摄像机矩阵.
g_pd3dDevice->SetTransform( D3DTS_VIEW, pmatView ); // 设置摄像机矩阵
// 鼠标在窗口的中央初始化
// SetCursor( NULL ); // 鼠标消失.
RECT rc;
GetClientRect( g_hwnd, &rc );
pt.x = (rc.right - rc.left) / 2;
pt.y = (rc.bottom - rc.top) / 2;
ClientToScreen( g_hwnd, &pt );
SetCursorPos( pt.x, pt.y );
g_dwMouseX = pt.x;
g_dwMouseY = pt.y;
}
/**-----------------------------------------------------------------------------
* 广告牌处理
*------------------------------------------------------------------------------
*/
void ProcessKey( void )
{
if( GetAsyncKeyState( 'A' ) ) g_pCamera->MoveLocalZ( 0.5f ); // 摄像机前进!
if( GetAsyncKeyState( 'Z' ) ) g_pCamera->MoveLocalZ( -0.5f ); // 摄像机后退!
}
/**-----------------------------------------------------------------------------
* 输入处理
*------------------------------------------------------------------------------
*/
void ProcessInputs( void )
{
ProcessMouse();
ProcessKey();
}
/**-----------------------------------------------------------------------------
* 创建动画
*------------------------------------------------------------------------------
*/
VOID Animate()
{
D3DXMatrixIdentity( &g_matAni );
SetupLights();
ProcessInputs();
LogFPS();
}
void DrawBillboard()
{
// 通过R通道,获得透明纹理效果
g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x08 );
g_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
struct MYVERTEX
{
enum { FVF = D3DFVF_XYZ | D3DFVF_TEX1 };
float px, py, pz;
float tu, tv;
};
// 广告牌顶点
MYVERTEX vtx[4] =
{
{ -1, 0, 0, 0, 1 },
{ -1, 4, 0, 0, 0 },
{ 1, 0, 0, 1, 1 },
{ 1, 4, 0, 1, 0 }
};
D3DXMATRIXA16 matBillboard;
D3DXMatrixIdentity( &matBillboard );
// 在0号纹理指定广告牌纹理
g_pd3dDevice->SetTexture( 1, NULL );
g_pd3dDevice->SetFVF( MYVERTEX::FVF );
if( g_bBillboard )
{
// Y轴旋转矩阵 旋转值输入_11, _13, _31, _33号矩阵
// 读取摄像机 Y轴 旋转矩阵值,如果创建逆矩阵,
// 可以创建X和 Z轴固定,Y轴旋转的广告牌矩阵
matBillboard._11 = g_pCamera->GetViewMatrix()->_11;
matBillboard._13 = g_pCamera->GetViewMatrix()->_13;
matBillboard._31 = g_pCamera->GetViewMatrix()->_31;
matBillboard._33 = g_pCamera->GetViewMatrix()->_33;
D3DXMatrixInverse( &matBillboard, NULL, &matBillboard );
}
// 变换广告牌的坐标,拍摄
for( int z = 0 ; z <= 40 ; z += 5 )
{
for( int x = 0 ; x <= 40 ; x += 5 )
{
matBillboard._41 = x - 20;
matBillboard._42 = 0;
matBillboard._43 = z - 20;
g_pd3dDevice->SetTexture( 0, g_pTexBillboard[(x+z)%4] );
g_pd3dDevice->SetTransform( D3DTS_WORLD, &matBillboard );
g_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, vtx, sizeof(MYVERTEX) );
}
}
g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );
g_pd3dDevice->SetTransform( D3DTS_WORLD, &g_matWorld );
}
/**-----------------------------------------------------------------------------
* 绘图
*------------------------------------------------------------------------------
*/
VOID Render()
{
/// 后置缓冲和Z-缓冲初始化
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(200,200,200), 1.0f, 0 );
g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, g_bWireframe ? D3DFILL_WIREFRAME : D3DFILL_SOLID );
/// 创建动画矩阵
Animate();
/// 开始渲染
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
g_pWater->Draw();
DrawBillboard();
/// 结束渲染
g_pd3dDevice->EndScene();
}
/// 显示后置缓冲的画面!
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
/**-----------------------------------------------------------------------------
* 窗口过程
*------------------------------------------------------------------------------
*/
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY :
Cleanup();
PostQuitMessage( 0 );
return 0;
case WM_KEYDOWN :
switch( wParam )
{
case VK_ESCAPE :
PostMessage( hWnd, WM_DESTROY, 0, 0L );
break;
case '1' :
g_bWireframe = !g_bWireframe;
break;
case '2' :
g_bBillboard = !g_bBillboard;
break;
}
break;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
/**-----------------------------------------------------------------------------
* 程序的起始地址
*------------------------------------------------------------------------------
*/
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
/// 注册窗口类
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"BasicFrame", NULL };
RegisterClassEx( &wc );
/// 创建窗口
HWND hWnd = CreateWindow( "BasicFrame", WINDOW_TITLE,
WS_OVERLAPPEDWINDOW, 100, 100, WINDOW_W, WINDOW_H,
GetDesktopWindow(), NULL, wc.hInstance, NULL );
g_hwnd = hWnd;
srand( GetTickCount() );
/// Direct3D初始化
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
if( SUCCEEDED( InitObjects() ) )
{
if( SUCCEEDED( InitGeometry() ) )
{
/// 显示窗口
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
/// 消息循环
MSG msg;
ZeroMemory( &msg, sizeof(msg) );
while( msg.message!=WM_QUIT )
{
/// 消息队列中有消息时,调用相应的处理过程
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
/// 如果没有需要处理的消息,调用Render()函数
Render();
}
}
}
}
DeleteObjects();
UnregisterClass( "BasicFrame", wc.hInstance );
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -