【游戏程序设计】Direct 3D光照与材质

运行结果:

【游戏程序设计】Direct 3D光照与材质

源代码:

#include <d3d9.h>
#include <d3dx9.h>

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define WINDOW_TITLE L"Direct 3D光照与材质"
#define SAFE_RELEASE(p) { if(p) {(p)->Release(); (p) = NULL;}}										//销毁指针
//---------------------------------------【全局变量声明部分】------------------------------------------------
//描述:全局变量的声明
//-----------------------------------------------------------------------------------------------------------
LPDIRECT3DDEVICE9 g_pd3dDevice;																//Direct 3D设备对象
ID3DXFont* g_pFont;																			//字体COM接口
LPD3DXMESH g_teapot;																		//茶壶对象
LPD3DXMESH g_cube;																			//立方体对象
LPD3DXMESH g_sphere;																		//球体对象
LPD3DXMESH g_torus;																			//圆环对象
D3DXMATRIX g_WorldMatrix[4], R;																//四个物体的变换矩阵

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT Direct3D_Init(HWND);													//在这个函数中继续Direct3D的初始化
HRESULT Objects_Init(HWND);														//在这个函数中进行要绘制的物体的资源初始化
void Direct3D_Render(HWND);														//在这个函数中进行Direct3D渲染代码的书写
void Direct3D_ClearUp();														//在这个函数中清理COM资源以及其他资源
void Matrix_Set();																//变换函数
void Light_Set(UINT);															//封装了Direct3D光照函数
//----------------------------------------【WinMain()函数】-------------------------------------------------
//描述:Windows应用程序的入口函数
//-------------------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wndClass = {0};
	wndClass.cbSize = sizeof(WNDCLASSEX);
	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = (WNDPROC)WndProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = (HICON)LoadImage(NULL, L"icon.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = L"3DGameBase";
	if(!RegisterClassEx(&wndClass))
		return -1;

	HWND hWnd = CreateWindow(L"3DGameBase", WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
		WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
	MoveWindow(hWnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true);
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	PlaySound(L"Final Fantasy XIII.wav", NULL, SND_LOOP | SND_ASYNC | SND_FILENAME);
	
	if(FAILED(Direct3D_Init(hWnd)))
		MessageBox(hWnd, L"Direct3D 初始化失败!", L"消息窗口", 0);
	MSG msg = {0};
	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
			Direct3D_Render(hWnd);
	}

	UnregisterClass(L"3DGameBase", wndClass.hInstance);
	return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch(message)
	{
	case WM_PAINT:
		Direct3D_Render(hWnd);
		ValidateRect(hWnd, NULL);													//使窗口区域生效
		break;
	case WM_KEYDOWN:
		if(wParam == VK_ESCAPE)
			DestroyWindow(hWnd);
		break;
	case WM_DESTROY:
		//调用自定义的资源清理函数Direct3D_ClearUp();进行退出前的资源清理
		Direct3D_ClearUp();
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}

	return 0;
}
//---------------------------------------------【Direct3D_Init()函数】-----------------------------------------
//描述:Direct3D初始化函数,进行Direct3D的初始化
//---------------------------------------------------------------------------------------------------------------
HRESULT Direct3D_Init(HWND hWnd)
{
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D初始化步骤一】:创建Direct3D接口对象,以便用该Direct3D对象创建Direct3D设备对象
	//---------------------------------------------------------------------------------------------------------------
	LPDIRECT3D9 pD3D = NULL; //Direct3D接口对象的创建。

	if((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)						//初始化Direct3D接口对象,并进行DirectX版本协商。
		return E_FAIL;
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D初始化步骤二】:获取硬件设备信息
	//---------------------------------------------------------------------------------------------------------------
	D3DCAPS9 caps;
	int vp = 0;
	if(FAILED(pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps))) 
		return E_FAIL;
	if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
		vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;								//支持硬件顶点运算,采用硬件顶点运算
	else
		vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;								//不支持硬件顶点运算,采用软件顶点运算

	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D初始化步骤三】:填充D3DPRESENT_PARAMETERS结构体
	//---------------------------------------------------------------------------------------------------------------
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));

	d3dpp.BackBufferWidth = WINDOW_WIDTH;
	d3dpp.BackBufferHeight = WINDOW_HEIGHT;
	d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
	d3dpp.BackBufferCount = 1;
	d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
	d3dpp.MultiSampleQuality = 0;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow = hWnd;
	d3dpp.Windowed = true;
	d3dpp.EnableAutoDepthStencil = true;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
	d3dpp.Flags = 0;
	d3dpp.FullScreen_RefreshRateInHz = 0;
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D初始化步骤四】:创建Direct3D设备接口。
	//---------------------------------------------------------------------------------------------------------------
	if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, vp, &d3dpp, &g_pd3dDevice)))
		return E_FAIL;
	
	SAFE_RELEASE(pD3D);														//LPDIRECT3D9接口对象的使命完成,将其释放掉
	if(FAILED(Objects_Init(hWnd)))											// 调用一次Objects_Init,进行渲染资源的初始化
		return E_FAIL;
		
	return S_OK;
}
//---------------------------------------------------------------------------------------------------------------
//------------------------------------------【Objects_Init()】函数---------------------------------------------
//描述:渲染资源初始化函数,在此函数中进行要被渲染的物体的资源的初始化
//---------------------------------------------------------------------------------------------------------------
HRESULT Objects_Init(HWND hWnd)
{
	//创建字体
	if(FAILED(D3DXCreateFont(g_pd3dDevice, 72, 0, 0, 1, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, 
													DEFAULT_QUALITY, 0, TEXT("微软雅黑"), &g_pFont)))
		return E_FAIL;
	//创建物体
	if(FAILED(D3DXCreateBox(g_pd3dDevice, 2, 2, 2, &g_cube, NULL)))						//立方体的创建
		return false;
	if(FAILED(D3DXCreateTeapot(g_pd3dDevice, &g_teapot, NULL)))							//茶壶的创建
		return false;
	if(FAILED(D3DXCreateSphere(g_pd3dDevice, 1.5, 25, 25, &g_sphere, NULL)))			//球体的创建
		return false;
	if(FAILED(D3DXCreateTorus(g_pd3dDevice, 0.5f, 1.2f, 25, 25, &g_torus, NULL)))		//圆环的创建
		return false;
	//材质的创建
	D3DMATERIAL9 mtrl;
	ZeroMemory(&mtrl, sizeof(mtrl));
	mtrl.Ambient = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
	mtrl.Diffuse = D3DXCOLOR(0.6f, 0.6f, 0.6f, 1.0f);
	mtrl.Specular = D3DXCOLOR(0.3f, 0.3f, 0.3f, 0.3f);
	mtrl.Emissive = D3DXCOLOR(0.3f, 0.0f, 0.1f, 1.0f);
	g_pd3dDevice->SetMaterial(&mtrl);
	
	Matrix_Set();
	//光照的设置
	Light_Set(1);

	g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, true);
	g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);
	g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true);
	
	return S_OK;
}

void Matrix_Set()
{
	D3DXMATRIX matView;
	D3DXVECTOR3 vEye(0.0f, 0.0f, -15.0f);
	D3DXVECTOR3 vAt(0.0f, 0.0f, 0.0f);
	D3DXVECTOR3 vUp(0.0f, 1.0f, 0.0f);
	D3DXMatrixLookAtLH(&matView, &vEye, &vAt, &vUp);
	g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);

	D3DXMATRIX matProj;
	D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4.0f, 1.0f, 1.0f, 1000.0f); 
	g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);

	D3DVIEWPORT9 vp;
	vp.X = 0;
	vp.Y = 0;
	vp.Width = WINDOW_WIDTH;
	vp.Height = WINDOW_HEIGHT;
	vp.MinZ = 0.0f;
	vp.MaxZ = 1.0f;
	g_pd3dDevice->SetViewport(&vp);
}
//-----------------------------------------【Light_Set函数】-----------------------------------------------------
//该函数封装了光源类型及相关光源类型参数的设置
//---------------------------------------------------------------------------------------------------------------
void Light_Set(UINT nType)
{
	//定义一个光照对象并初始化
	static D3DLIGHT9 light;
	ZeroMemory(&light, sizeof(light));
    //设置光照类型
	switch(nType)
	{
	case 1:														//点光源
		light.Type = D3DLIGHT_POINT;
		light.Ambient = D3DXCOLOR(0.6f, 0.6f, 0.6f, 1.0f);
		light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
		light.Specular = D3DXCOLOR(0.3f, 0.3f, 0.3f, 1.0f);
		light.Position = D3DXVECTOR3(0.0f, 200.0f, 1.0f);
		light.Attenuation0 = 1.0f;								//点光源要求此参数
		light.Attenuation1 = 0.0f;
		light.Attenuation2 = 0.0f;
		light.Range = 300.0f;
		break;
	case 2:														//平行光
		light.Type = D3DLIGHT_DIRECTIONAL;
		light.Ambient = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
		light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
		light.Specular = D3DXCOLOR(0.3f, 0.3f, 0.3f, 1.0f);
		light.Direction = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
		break;
	case 3:														//聚光灯
		light.Type = D3DLIGHT_SPOT;
		light.Ambient = D3DXCOLOR(0.3f, 0.3f, 0.3f, 1.0f);
		light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
		light.Specular = D3DXCOLOR(0.3f, 0.3f, 0.3f, 0.3f);
		light.Position = D3DXVECTOR3(100.0f, 100.0f, 100.0f);
		light.Direction = D3DXVECTOR3(-1.0f, -1.0f, -1.0f);
		light.Attenuation0 = 1.0f;
		light.Attenuation1 = 0.0f;
		light.Attenuation2 = 0.0f;
		light.Range = 300.0f;
		light.Falloff = 0.1f;									//控制光强如何从内锥体的外侧向外锥体的内侧减弱的
		light.Phi = D3DX_PI / 3.0f;  
		light.Theta = D3DX_PI / 6.0f;
		break; 
	}

	g_pd3dDevice->SetLight(0, &light);							//设置光源
	g_pd3dDevice->LightEnable(0, true);							//启用光源
	g_pd3dDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(36, 36, 36));							//设置环境光
}

//----------------------------------------【Direct3D_Render()函数】--------------------------------------------
//描述:使用Direct3D进行渲染
//---------------------------------------------------------------------------------------------------------------
void Direct3D_Render(HWND hWnd)
{
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步骤一】:清屏操作
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
	//定义一个矩形,用来获取主窗口矩形
	RECT formatRect;
	GetClientRect(hWnd, &formatRect);
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步骤二】:开始绘制
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->BeginScene();																				//开始绘制
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步骤三】:正式绘制
	//---------------------------------------------------------------------------------------------------------------
	if(GetAsyncKeyState('1') & 0x8000)
		g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
	if(GetAsyncKeyState('2') & 0x8000)
		g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
	if(GetAsyncKeyState('A') & 0x8000)											//按A键 则设置为点光源
		Light_Set(1); 
	if(GetAsyncKeyState('W') & 0x8000)											//按w键 则设置为平行光
		Light_Set(2);
	if(GetAsyncKeyState('E') & 0x8000)											//按e键 则设置为聚光灯
		Light_Set(3);
	//物体的公转
	D3DXMatrixRotationY(&R, timeGetTime() / 1440.0f);
	//立方体的绘制
	D3DXMatrixTranslation(&g_WorldMatrix[0], 3.0f, -3.0f, 0.0f);
	g_WorldMatrix[0] *= R;
	g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_WorldMatrix[0]);
	g_cube->DrawSubset(0);
	//茶壶的绘制
	D3DXMatrixTranslation(&g_WorldMatrix[1], -3.0f, -3.0f, 0.0f);
	g_WorldMatrix[1] *= R;
	g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_WorldMatrix[1]);
	g_teapot->DrawSubset(0);
	//圆环的绘制
	D3DXMatrixTranslation(&g_WorldMatrix[2], 3.0f, 3.0f, 0.0f);
	g_WorldMatrix[2] *= R;
	g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_WorldMatrix[2]);
	g_torus->DrawSubset(0);
	//球体的绘制
	D3DXMatrixTranslation(&g_WorldMatrix[3], -3.0f, 3.0f, 0.0f);
	g_WorldMatrix[3] *= R;
	g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_WorldMatrix[3]);
	g_sphere->DrawSubset(0);
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步骤四】:结束绘制
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->EndScene();																				//结束绘制
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步骤五】:显示翻转
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->Present(NULL, NULL, NULL, NULL);															//翻转与显示
}
//------------------------------------------------【 Direct3D_ClearUp函数】------------------------------------------
//描述:资源清理函数,在此函数中进行程序退出前资源的清理工作
//-------------------------------------------------------------------------------------------------------------------
void Direct3D_ClearUp()
{
	SAFE_RELEASE(g_pd3dDevice);
	//释放COM接口对象
	SAFE_RELEASE(g_pFont);
	SAFE_RELEASE(g_cube);
	SAFE_RELEASE(g_sphere);
	SAFE_RELEASE(g_torus);
	SAFE_RELEASE(g_teapot);
}