⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.cpp

📁 选自《3D游戏编程》第5章 实战例题:3D编程技术的实战例题
💻 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 + -