【游戏程序设计】Direct 3D天空系统

运行结果:

源代码:

SkyBoxClass.h:

//=============================================================================
//一个封装了三维天空盒系统的类的头文件
//=============================================================================

#pragma once
#include <d3d9.h>
#include <d3dx9.h>
#include "D3DUtil.h"

//为天空盒类定义一个FVF灵活顶点格式
struct SKYBOXVERTEX
{
	float x, y, z;
	float u, v;
};
#define D3DFVF_SKYBOXVERTEX (D3DFVF_XYZ | D3DFVF_TEX1) 

class SkyBoxClass
{
private:
	LPDIRECT3DDEVICE9 m_pd3dDevice;										//D3D设备对象
	LPDIRECT3DVERTEXBUFFER9 m_pVertexBuffer;							//顶点缓存对象
	LPDIRECT3DTEXTURE9 m_pTextures[5];									//5个纹理接口对象
	float m_length;														//天空盒边长	

public:
	SkyBoxClass(LPDIRECT3DDEVICE9 pd3dDevice);							//构造函数
	~SkyBoxClass(void);													//析构函数
	//从文件加载天空盒5个方向的纹理
	bool LoadSkyTextureFromFile(wchar_t *pFrontTextureFile, 
		wchar_t *pBackTextureFile,wchar_t *pLeftTextureFile, 
		wchar_t *pRightTextureFile,wchar_t *pTopTextureFile);
	//初始化天空盒函数
	bool InitSkyBox(float length);										
	//渲染天空盒,根据第一个参数设定天空盒矩阵,第二个参数设定是否渲染出边框
	void RenderSkyBox(D3DXMATRIX *pMatWorld, bool bRenderFrame = false);
};

SkyBoxClass.cpp:

//=============================================================================
//一个封装了三维天空盒系统的类的源文件
//=============================================================================

#include "SkyBoxClass.h"
//-----------------------------------------------------------------------------
//构造函数
//-----------------------------------------------------------------------------
SkyBoxClass::SkyBoxClass(LPDIRECT3DDEVICE9 pd3dDevice)
{
	m_pd3dDevice = pd3dDevice;
	m_pVertexBuffer = NULL;
	for(int i = 0; i < 5; ++i)
		m_pTextures[i] = NULL;
	m_length = 0.0f;
}
//-----------------------------------------------------------------------------
//天空盒纹理加载函数
//-----------------------------------------------------------------------------
bool SkyBoxClass::LoadSkyTextureFromFile(wchar_t *pFrontTextureFile, 
		wchar_t *pBackTextureFile,wchar_t *pLeftTextureFile, 
		wchar_t *pRightTextureFile,wchar_t *pTopTextureFile)
{
	//从文件中加载五张纹理
	if(D3DXCreateTextureFromFile(m_pd3dDevice, pFrontTextureFile, &m_pTextures[0]))			//前面
		return false;
	if(D3DXCreateTextureFromFile(m_pd3dDevice, pBackTextureFile, &m_pTextures[1]))			//后面
		return false;
	if(D3DXCreateTextureFromFile(m_pd3dDevice, pLeftTextureFile, &m_pTextures[2]))			//左面
		return false;
	if(D3DXCreateTextureFromFile(m_pd3dDevice, pRightTextureFile, &m_pTextures[3]))			//右面
		return false;
	if(D3DXCreateTextureFromFile(m_pd3dDevice, pTopTextureFile, &m_pTextures[4]))			//上面
		return false;

	return true;
}
//-----------------------------------------------------------------------------
//天空盒初始化函数,顶点缓冲区的赋值
//-----------------------------------------------------------------------------
bool SkyBoxClass::InitSkyBox(float length)
{
	m_length = length;
	//创建顶点缓存
	if(FAILED(m_pd3dDevice->CreateVertexBuffer(20*sizeof(SKYBOXVERTEX), 0, D3DFVF_SKYBOXVERTEX,
												D3DPOOL_MANAGED, &m_pVertexBuffer, NULL)))
		return false;
	//用一个结构体把顶点数据准备好,因为是在盒子里面,所以要顶点顺序反向
	SKYBOXVERTEX vertices[] = 
	{
		//前面的四个顶点
		{ -m_length/2, 0.0f,    m_length/2, 0.0f, 1.0f, },
		{ -m_length/2, m_length/2,   m_length/2, 0.0f, 0.0f, },
		{  m_length/2, 0.0f,    m_length/2, 1.0f, 1.0f, },
		{  m_length/2, m_length/2,   m_length/2, 1.0f, 0.0f, },

		//背面的四个顶点
		{  m_length/2, 0.0f,   -m_length/2, 0.0f, 1.0f, },
		{  m_length/2, m_length/2,  -m_length/2, 0.0f, 0.0f, },
		{ -m_length/2, 0.0f,   -m_length/2, 1.0f, 1.0f, },
		{ -m_length/2, m_length/2,  -m_length/2, 1.0f, 0.0f, },

		//左面的四个顶点
		{ -m_length/2, 0.0f,   -m_length/2, 0.0f, 1.0f, },
		{ -m_length/2, m_length/2,  -m_length/2, 0.0f, 0.0f, },
		{ -m_length/2, 0.0f,    m_length/2, 1.0f, 1.0f, },
		{ -m_length/2, m_length/2,   m_length/2, 1.0f, 0.0f, },

		//右面的四个顶点
		{ m_length/2, 0.0f,   m_length/2, 0.0f, 1.0f, },
		{ m_length/2, m_length/2,  m_length/2, 0.0f, 0.0f, },
		{ m_length/2, 0.0f,  -m_length/2, 1.0f, 1.0f, },
		{ m_length/2, m_length/2, -m_length/2, 1.0f, 0.0f, },

		//上面的四个顶点
		{  m_length/2, m_length/2, -m_length/2, 1.0f, 0.0f, },
		{  m_length/2, m_length/2,  m_length/2, 1.0f, 1.0f, },
		{ -m_length/2, m_length/2, -m_length/2, 0.0f, 0.0f, },
		{ -m_length/2, m_length/2,  m_length/2, 0.0f, 1.0f, },
	};
	//准备填充顶点数据
	void *pVertices = NULL;
	//加锁
	if(FAILED(m_pVertexBuffer->Lock(0, 20*sizeof(SKYBOXVERTEX), &pVertices, 0)))
		return false;
	//访问。把结构体中的数据直接拷到顶点缓存区中
	memcpy(pVertices, vertices, sizeof(vertices));
	m_pVertexBuffer->Unlock();
	return true;
}
//-----------------------------------------------------------------------------
//绘制出天空盒,可以通过第二个参数选择是否渲染出边框
//-----------------------------------------------------------------------------
void SkyBoxClass::RenderSkyBox(D3DXMATRIX *pMatWorld, bool bRenderFrame)
{
	//将纹理颜色混合的第一个参数用于输出
	m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
	//纹理颜色混合的第一个参数就取纹理值
	m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
	//设置世界矩阵
	m_pd3dDevice->SetTransform(D3DTS_WORLD, pMatWorld);
	//把包含的几何体的顶点信息的顶点缓存和渲染流水线相关联
	m_pd3dDevice->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(SKYBOXVERTEX)); 
	//设置FVF灵活顶点格式
	m_pd3dDevice->SetFVF(D3DFVF_SKYBOXVERTEX); 
	//一个for循环,将5个面绘制出来
	for(int i = 0; i < 5; ++i)
	{
		m_pd3dDevice->SetTexture(0, m_pTextures[i]);
		m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, i*4, 2);
	}
	//纹理设为NULL
	m_pd3dDevice->SetTexture(0, NULL);
	//对是否渲染线框的处理代码
	if(bRenderFrame)																		//如果要渲染出线框的话
	{
		//把填充模式设为线框填充
		m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
		//1个for循环,将5个面的线框绘制出来
		for(int i = 0; i < 5; ++i)
			m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, i*4, 2);						//绘制顶点
		//把填充模式设为实体填充
		m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
	}
}
//-----------------------------------------------------------------------------
//析构函数
//-----------------------------------------------------------------------------
SkyBoxClass::~SkyBoxClass(void)
{
	SAFE_RELEASE(m_pVertexBuffer);
	for(int i = 0; i < 5; ++i)
		SAFE_RELEASE(m_pTextures[i]);
}

WinMain.cpp

#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#include "CameraClass.h"
#include "DirectInputClass.h"
#include "TerrainClass.h"
#include "SkyBoxClass.h"

#define WINDOW_TITLE L"Direct 3D天空系统"
//---------------------------------------【全局变量声明部分】------------------------------------------------
//描述:全局变量的声明
//-----------------------------------------------------------------------------------------------------------
LPDIRECT3DDEVICE9 g_pd3dDevice;																//Direct 3D设备对象
D3DXMATRIX g_matWorld;																		//世界矩阵
DirectInputClass *g_pDInput;																//一个DirectInput类的指针
LPD3DXFONT g_pTextAdapterName;																//显卡名字的2D文本
LPD3DXFONT g_pTextHelper;																	//帮助文本的2D文本
LPD3DXFONT g_pTextInfor;																	//绘制信息的2D文本
LPD3DXFONT g_pTextFPS;																		//FPS文本的2D文本
wchar_t g_strAdapterName[60];																//包括显卡名字的字符串		
wchar_t g_strFPS[50];																		//包含帧频率的字符数组
CameraClass *g_pCamera;																		//虚拟摄像机指针
TerrainClass *g_pTerrain;																	//地形类的指针实例
SkyBoxClass *g_pSkyBox;																		//天空盒类的指针
LPD3DXMESH g_pMesh;																			//网格对象
D3DMATERIAL9 *g_pMaterials;																	//网格的材质信息
LPDIRECT3DTEXTURE9 *g_pTextures;															//网格的纹理信息
DWORD g_dwNumMtrls;																			//材质的数目
LPD3DXMESH g_pCylinder;																		//柱子网格对象
D3DMATERIAL9 g_cylinderMaterial;															//柱子的材质

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资源以及其他资源
float Get_FPS();
void Direct3D_Update();
void HelpText_Render(HWND);
//----------------------------------------【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);

	g_pDInput = new DirectInputClass();
	g_pDInput->Init(hWnd, hInstance, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); 

	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_Update();
			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;

	//获取显卡信息到g_strAdapterName中,并在显卡名称前加上“当前显卡型号:”字符串
	//定义一个D3DADAPTER_IDENTIFIER9结构体,用于存储显卡信息  
	D3DADAPTER_IDENTIFIER9 Adapter;
	//调用GetAdapterIdentifier,获取显卡信息
	if(FAILED(pD3D->GetAdapterIdentifier(0, 0, &Adapter)))
		return E_FAIL;
	//显卡名称现在已经在Adapter.Description中了,但是其为char类型,我们要将其转为wchar_t类型  
	int len = MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, NULL, 0);
	//这步操作完成后,g_strAdapterName中就为当前我们的显卡类型名的wchar_t型字符串了 
	MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, g_strAdapterName, len);
	//定义一个临时字符串,且方便了把"当前显卡型号:"字符串引入我们的目的字符串中  
	wchar_t tempName[50] = L"当前显卡型号:";
	//把当前我们的显卡名加到“当前显卡型号:”字符串后面,结果存在TempName中  
	wcscat_s(tempName, g_strAdapterName);
	//把TempName中的结果拷贝到全局变量g_strAdapterName中
	wcscpy_s(g_strAdapterName, tempName);

	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, 36, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, 
													DEFAULT_QUALITY, 0, L"Calibri", &g_pTextFPS)))
		return E_FAIL;
	if(FAILED(D3DXCreateFont(g_pd3dDevice, 20, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
													DEFAULT_QUALITY, 0, L"华文中宋", &g_pTextAdapterName)))
		return E_FAIL;
	if(FAILED(D3DXCreateFont(g_pd3dDevice, 23, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
													DEFAULT_QUALITY, 0, L"微软雅黑", &g_pTextHelper)))
		return E_FAIL;
	if(FAILED(D3DXCreateFont(g_pd3dDevice, 26, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
													DEFAULT_QUALITY, 0, L"黑体", &g_pTextInfor)))
		return E_FAIL;

	//创建并初始化虚拟摄像机
	g_pCamera = new CameraClass(g_pd3dDevice);
	g_pCamera->SetCameraPosition(&D3DXVECTOR3(0.0f, 1000.0f, -1200.0f));  //设置摄像机所在的位置
	g_pCamera->SetTargetPosition(&D3DXVECTOR3(0.0f, 1200.0f, 0.0f));  //设置目标观察点所在的位置
	g_pCamera->SetViewMatrix();													//设置取景变换矩阵
	g_pCamera->SetProjMatrix();				
	//创建并初始化地形
	g_pTerrain = new TerrainClass(g_pd3dDevice);
	g_pTerrain->LoadTerrainFromFile(L"heighmap.raw", L"terrainstone.jpg");				//从文件读取高度图和纹理
	g_pTerrain->InitTerrain(200, 200, 30.0f, 6.0f);							//顶点行数,顶点列数,顶点间间距,缩放系数
	//创建并初始化天空对象
	g_pSkyBox = new SkyBoxClass(g_pd3dDevice);
	//从文件加载前,后,左,右,上的纹理图
	g_pSkyBox->LoadSkyTextureFromFile(L"frontsnow1.jpg", L"backsnow1.jpg", L"leftsnow1.jpg", 
																	L"rightsnow1.jpg", L"topsnow1.jpg"); 
	//设置天空盒的边长
	g_pSkyBox->InitSkyBox(20000);

	//设置投影变换矩阵
	//以下这段代码用于限制鼠标光标移动区域
	POINT lt, rb;
	RECT rect;
	GetClientRect(hWnd, &rect);//取得窗口内部矩形
	//将矩形左上点坐标存入lt中
	lt.x = rect.left;
	lt.y = rect.top;
	//将矩形右下坐标存入rb中
	rb.x = rect.right;
	rb.y = rect.bottom;
	//将lt和rb的窗口坐标转换为屏幕坐标
	ClientToScreen(hWnd, &lt);
	ClientToScreen(hWnd, &rb);
	//以屏幕坐标重新设定矩形区域
	rect.left = lt.x;
	rect.top = lt.y;
	rect.right = rb.x;
	rect.bottom = rb.y;
	//限制鼠标光标移动区域
	ClipCursor(&rect);
	ShowCursor(false);

	// 从X文件中加载网格数据
	LPD3DXBUFFER pAdjBuffer = NULL;
	LPD3DXBUFFER pMtrlBuffer = NULL;
	// 读取材质和纹理数据
	D3DXLoadMeshFromX(L"95.X", D3DXMESH_MANAGED, g_pd3dDevice, &pAdjBuffer,  
								&pMtrlBuffer, 0, &g_dwNumMtrls, &g_pMesh);
	g_pMaterials = new D3DMATERIAL9[g_dwNumMtrls];
	g_pTextures = new LPDIRECT3DTEXTURE9[g_dwNumMtrls];
	//创建一个D3DXMATERIAL结构体用于读取材质和纹理信息
	D3DXMATERIAL *pMtrl = (D3DXMATERIAL *)pMtrlBuffer->GetBufferPointer();
	for(DWORD i = 0; i < g_dwNumMtrls; ++i)
	{
		//获取材质,并设置一下环境光的颜色值
		g_pMaterials[i] = pMtrl[i].MatD3D;
		g_pMaterials[i].Ambient = g_pMaterials[i].Diffuse;
		//创建一下纹理对象
		D3DXCreateTextureFromFileA(g_pd3dDevice, pMtrl[i].pTextureFilename, &g_pTextures[i]);
	}
	SAFE_RELEASE(pAdjBuffer);
	SAFE_RELEASE(pMtrlBuffer);
	//创建柱子
	D3DXCreateCylinder(g_pd3dDevice, 280.0f, 10.0f, 3000.0f, 60, 60,  &g_pCylinder, 0);
	g_cylinderMaterial.Ambient = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);  
	g_cylinderMaterial.Diffuse = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);  
	g_cylinderMaterial.Specular = D3DXCOLOR(0.5f, 0.0f, 0.3f, 0.3f);  
	g_cylinderMaterial.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
	// 设置光照  
	D3DLIGHT9 light;
	light.Type = D3DLIGHT_DIRECTIONAL;
	light.Ambient       = D3DXCOLOR(0.7f, 0.7f, 0.7f, 1.0f);  
	light.Diffuse       = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);  
	light.Specular      = D3DXCOLOR(0.9f, 0.9f, 0.9f, 1.0f);  
	light.Direction     = D3DXVECTOR3(1.0f, 1.0f, 1.0f);  
	g_pd3dDevice->SetLight(0, &light);
	g_pd3dDevice->LightEnable(0, true);
	g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);
	g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true);

	return S_OK;
}

void Direct3D_Update()
{
	//使用DirectInput类读取数据
	g_pDInput->GetInput();
	// 沿摄像机各分量移动视角
	if (g_pDInput->IsKeyDown(DIK_A))  g_pCamera->MoveAlongRightVec(-0.3f);
	if (g_pDInput->IsKeyDown(DIK_D))  g_pCamera->MoveAlongRightVec( 0.3f);
	if (g_pDInput->IsKeyDown(DIK_W)) g_pCamera->MoveAlongLookVec( 0.3f);
	if (g_pDInput->IsKeyDown(DIK_S))  g_pCamera->MoveAlongLookVec(-0.3f);
	if (g_pDInput->IsKeyDown(DIK_R))  g_pCamera->MoveAlongUpVec( 0.3f);
	if (g_pDInput->IsKeyDown(DIK_F))  g_pCamera->MoveAlongUpVec(-0.3f);

	//沿摄像机各分量旋转视角
	if (g_pDInput->IsKeyDown(DIK_LEFT))  g_pCamera->RotationUpVec(-0.003f);
	if (g_pDInput->IsKeyDown(DIK_RIGHT))  g_pCamera->RotationUpVec( 0.003f);
	if (g_pDInput->IsKeyDown(DIK_UP))  g_pCamera->RotationRightVec(-0.003f);
	if (g_pDInput->IsKeyDown(DIK_DOWN))  g_pCamera->RotationRightVec( 0.003f);
	if (g_pDInput->IsKeyDown(DIK_Q)) g_pCamera->RotationLookVec(0.001f);
	if (g_pDInput->IsKeyDown(DIK_E)) g_pCamera->RotationLookVec( -0.001f);

	//鼠标控制右向量和上向量的旋转
	g_pCamera->RotationUpVec(g_pDInput->MouseDX()* 0.001f);
	g_pCamera->RotationRightVec(g_pDInput->MouseDY() * 0.001f);
	//计算并设置取景变换矩阵
	g_pCamera->SetViewMatrix();
	//鼠标滚轮控制观察点收缩操作
	static float fPosZ = 0.0f;
	fPosZ += g_pDInput->MouseDZ() * 0.03f;
	//把正确的世界变换矩阵存到g_matWorld中
	D3DXMatrixTranslation(&g_matWorld, 0, 0, fPosZ);
}

//----------------------------------------【Direct3D_Render()函数】--------------------------------------------
//描述:使用Direct3D进行渲染
//---------------------------------------------------------------------------------------------------------------
void Direct3D_Render(HWND hWnd)
{
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步骤一】:清屏操作
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 108, 255), 1.0f, 0);
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步骤二】:开始绘制
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->BeginScene();																				//开始绘制
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步骤三】:正式绘制
	//---------------------------------------------------------------------------------------------------------------
	//绘制人物
	D3DXMATRIX mScal,mRot2,mTrans,mFinal;   //定义一些矩阵,准备对大黄蜂进行矩阵变换
	D3DXMatrixTranslation(&mTrans,0.0f,600.0f,200.0f);
	D3DXMatrixScaling(&mScal,3.0f,3.0f,3.0f);
	mFinal=mScal*mTrans*g_matWorld;
	g_pd3dDevice->SetTransform(D3DTS_WORLD, &mFinal);//设置模型的世界矩阵,为绘制做准备
	// 用一个for循环,进行模型的网格各个部分的绘制
	for (DWORD i = 0; i < g_dwNumMtrls; i++)
	{
		g_pd3dDevice->SetMaterial(&g_pMaterials[i]);  //设置此部分的材质
		g_pd3dDevice->SetTexture(0, g_pTextures[i]);//设置此部分的纹理
		g_pMesh->DrawSubset(i);  //绘制此部分
	}

	//绘制地形
	g_pTerrain->RenderTerrain(&g_matWorld);			//渲染地形,没有第二个参数表示不渲染地形边框

	//绘制柱子
	D3DXMATRIX TransMatrix, RotMatrix, FinalMatrix;
	D3DXMatrixRotationX(&RotMatrix, -D3DX_PI * 0.5f);
	g_pd3dDevice->SetMaterial(&g_cylinderMaterial);
	for(int i = 0; i < 4; i++)
	{
		D3DXMatrixTranslation(&TransMatrix, -300.0f, 0.0f, -350.0f + (i * 500.0f));
		FinalMatrix = RotMatrix * TransMatrix ;
		g_pd3dDevice->SetTransform(D3DTS_WORLD, &FinalMatrix);
		g_pCylinder->DrawSubset(0);

		D3DXMatrixTranslation(&TransMatrix, 300.0f, 0.0f, -350.0f + (i * 500.0f));
		FinalMatrix = RotMatrix * TransMatrix ;
		g_pd3dDevice->SetTransform(D3DTS_WORLD, &FinalMatrix);
		g_pCylinder->DrawSubset(0);
	}
	//绘制天空
	D3DXMATRIX matSky, matTransSky, matRotSky;
	D3DXMatrixTranslation(&matTransSky, 0.0f, -3500.0f, 0.0f);
	//旋转天空网格,模拟云彩运动效果
	D3DXMatrixRotationY(&matRotSky, -0.000005f * timeGetTime());
	matSky = matTransSky * matRotSky;
	g_pSkyBox->RenderSkyBox(&matSky);

	//绘制文字信息
	HelpText_Render(hWnd);
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步骤四】:结束绘制
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->EndScene();																				//结束绘制
	//---------------------------------------------------------------------------------------------------------------
	//【Direct3D渲染步骤五】:显示翻转
	//---------------------------------------------------------------------------------------------------------------
	g_pd3dDevice->Present(NULL, NULL, NULL, NULL);															//翻转与显示
}

void HelpText_Render(HWND hWnd)
{
	//定义一个矩形,用来获取主窗口矩形
	RECT formatRect;
	GetClientRect(hWnd, &formatRect);
	//在窗口右上角处,显示每秒帧数  
	swprintf_s(g_strFPS, L"FPS:%.3f", Get_FPS());
	g_pTextFPS->DrawText(0, g_strFPS, -1, &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_XRGB(255,255,255));
	 //显示显卡类型名  
	g_pTextAdapterName->DrawText(0, g_strAdapterName, -1, &formatRect, DT_TOP | DT_LEFT, D3DXCOLOR(1.0f, 0.5f, 0.0f, 1.0f));
	// 输出帮助信息
	formatRect.left = 0,formatRect.top = 380;
	g_pTextInfor->DrawText(NULL, L"控制说明:", -1, &formatRect, 
		DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235,123,230,255));
	formatRect.top += 35;
	g_pTextHelper->DrawText(NULL, L"    W:向前飞翔     S:向后飞翔 ", -1, &formatRect, 
		DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
	formatRect.top += 25;
	g_pTextHelper->DrawText(NULL, L"    A:向左飞翔     D:向右飞翔", -1, &formatRect, 
		DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
	formatRect.top += 25;
	g_pTextHelper->DrawText(NULL, L"    R:垂直向上飞翔     F:垂直向下飞翔", -1, &formatRect, 
		DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
	formatRect.top += 25;
	g_pTextHelper->DrawText(NULL, L"    Q:向左倾斜       E:向右倾斜", -1, &formatRect, 
		DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
	formatRect.top += 25;
	g_pTextHelper->DrawText(NULL, L"    上、下、左、右方向键、鼠标移动:视角变化 ", -1, &formatRect, 
		DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
	formatRect.top += 25;
	g_pTextHelper->DrawText(NULL, L"     鼠标滚轮:人物模型Y轴方向移动", -1, &formatRect, 
		DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
	formatRect.top += 25;
	g_pTextHelper->DrawText(NULL, L"    ESC键 : 退出程序", -1, &formatRect, 
		DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
}

//-----------------------------------------【Get_FPS()函数】---------------------------------------------------
//描述:用于计算帧频率
//---------------------------------------------------------------------------------------------------------------
float Get_FPS()
{
	//定义四个静态变量
	static int frameCount = 0;																	//帧数
	static float currentTime = 0;																//当前时间 
	static float lastTime = 0;																	//上次计算帧频率的时间
	static float fps = 0;																		//需要计算的fps值
	
	++frameCount;																				//每调用一次此函数,帧数加一
	//获取系统时间, timeGetTime() 返回系统时间,以毫秒为单位,乘以0.001得到秒
	currentTime = timeGetTime() * 0.001f;												
	//如果当前时间减去之前计算帧频率的时间大于1秒钟,就进行帧频率的更新,并将帧数归零
	if(currentTime - lastTime > 1.0f)															//将时间控制在1秒钟
	{
		fps = frameCount / (currentTime - lastTime);											//计算这一秒的fps值
		frameCount = 0;																			//将本次帧数清零
		lastTime = currentTime;								//将当前时间赋给上次计算帧频率的时间,作为下一秒的基准时间
	}

	return fps;
}

//------------------------------------------------【 Direct3D_ClearUp函数】------------------------------------------
//描述:资源清理函数,在此函数中进行程序退出前资源的清理工作
//-------------------------------------------------------------------------------------------------------------------
void Direct3D_ClearUp()
{
	//释放COM接口对象
	SAFE_RELEASE(g_pd3dDevice);
	SAFE_RELEASE(g_pTextFPS);
	SAFE_RELEASE(g_pTextHelper);
	SAFE_RELEASE(g_pTextAdapterName);
	SAFE_RELEASE(g_pTextInfor);
	SAFE_DELETE(g_pDInput);
	SAFE_DELETE(g_pTerrain);
	SAFE_DELETE(g_pCamera);
	SAFE_DELETE(g_pSkyBox);
	SAFE_RELEASE(g_pMesh);
	SAFE_DELETE(g_pMaterials);
	for(DWORD i = 0; i < g_dwNumMtrls; ++i)
		SAFE_RELEASE(g_pTextures[i]);
	SAFE_DELETE(g_pTextures);
	SAFE_RELEASE(g_pCylinder);
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值