【游戏程序设计】Direct 3D 三维地形系统
运行结果:
源代码:
TerrainClass.h:
#pragma once
//=============================================================================
//一个封装了三维地形系统的类的头文件
//=============================================================================#include <d3d9.h>
#include <d3dx9.h>
#include <vector>
#include <fstream>
#include "D3DUtil.h"class TerrainClass
{
private:LPDIRECT3DDEVICE9 m_pd3dDevice; //D3D设备LPDIRECT3DTEXTURE9 m_pTexture; //纹理LPDIRECT3DVERTEXBUFFER9 m_pVertexBuffer; //顶点缓存LPDIRECT3DINDEXBUFFER9 m_pIndexBuffer; //索引缓存int m_nCellsPerRow; //每行的单元格数目int m_nCellsPerCol; //每列的单元格数目int m_nVertsPerRow; //每行的顶点数int m_nVertsPerCol; //每列的顶点数int m_nNumVertices; //顶点总数float m_fTerrainWidth; //地形的宽度float m_fTerrainDepth; //地形的深度float m_fCellSpacing; //单元格间的间距float m_fHeightScale; //高度缩放系数std::vector<float> m_vHeightInfo; //用于存放高度信息//定义一个地形的FVF格式struct TERRAINVERTEX{float x, y, z;float u, v;TERRAINVERTEX(float _x, float _y, float _z, float _u, float _v):x(_x), y(_y), z(_z), u(_u), v(_v){}static const DWORD FVF = D3DFVF_XYZ | D3DFVF_TEX1;};
public:TerrainClass(LPDIRECT3DDEVICE9 pd3dDevice); //构造函数~TerrainClass(void); //析构函数bool LoadTerrainFromFile(wchar_t *pRawFileName, wchar_t *pTextureName); //从文件加载高度图和纹理的函数bool InitTerrain(int nRows, int nCols, float fSpace, float fScale); //地形初始化函数void RenderTerrain(D3DXMATRIX *pMatWorld, bool bDrawFrame = false); //地形渲染函数
};
TerrainClass.cpp
#include "TerrainClass.h"
//=============================================================================
//一个封装了三维地形系统的类的源文件
//=============================================================================//-----------------------------------------------------------------------------
//构造函数
//-----------------------------------------------------------------------------
TerrainClass::TerrainClass(LPDIRECT3DDEVICE9 pd3dDevice)
{//给各个成员变量赋初值m_pd3dDevice = pd3dDevice;m_pTexture = NULL;m_pVertexBuffer = NULL;m_pIndexBuffer = NULL;m_nCellsPerRow = 0;m_nCellsPerCol = 0;m_nVertsPerRow = 0;m_nVertsPerCol = 0;m_nNumVertices = 0;m_fTerrainWidth = 0.0f;m_fTerrainDepth = 0.0f;m_fCellSpacing = 0.0f;m_fHeightScale = 0.0f;
}
//-----------------------------------------------------------------------------
//加载地形高度信息以及纹理
//-----------------------------------------------------------------------------
bool TerrainClass::LoadTerrainFromFile(wchar_t *pRawFileName, wchar_t *pTextureName)
{//从文件中读取高度信息std::ifstream inFile;inFile.open(pRawFileName, std::ios::binary); //用二进制的方式打开文件inFile.seekg(0, std::ios::end); //把文件移动到文件末尾//用模板定义一个vector<byte>的变量inData并初始化,其值为缓冲区的当前位置,即缓冲区大小std::vector<byte> inData(inFile.tellg()); //将文件指针移动到文件的开头,准备读取高度信息inFile.seekg(std::ios::beg);//读取整个高度信息inFile.read((char *)&inData[0], inData.size()); //操作结束,可以关闭文件了inFile.close(); //遍历整个缓冲区,将inData中的值赋给m_vHeightInfofor(unsigned int i = 0; i < inData.size(); ++i)m_vHeightInfo.push_back(inData[i]);//加载地形纹理if(FAILED(D3DXCreateTextureFromFile(m_pd3dDevice, pTextureName, &m_pTexture)))return false;return true;
}
//-----------------------------------------------------------------------------
//初始化地形的高度,填充顶点和索引缓存
//-----------------------------------------------------------------------------
bool TerrainClass::InitTerrain(int nRows, int nCols, float fSpace, float fScale)
{m_nCellsPerRow = nRows; //每行的单元格数目m_nCellsPerCol = nCols; //每列的单元格数目m_fCellSpacing = fSpace; //单元格间的间距m_fHeightScale = fScale; //高度缩放系数m_nVertsPerRow = nRows + 1; //每行的顶点数m_nVertsPerCol = nCols + 1; //每列的顶点数m_nNumVertices = m_nVertsPerRow * m_nVertsPerCol; //顶点总数m_fTerrainWidth = nRows * fSpace; //地形的宽度m_fTerrainDepth = nCols * fSpace; //地形的深度//通过一个for循环,逐个把地形原始高度乘以缩放系数,得到缩放后的高度for(unsigned int i = 0; i < m_vHeightInfo.size(); ++i)m_vHeightInfo[i] *= fScale;//处理地形的顶点//创建顶点缓存if(FAILED(m_pd3dDevice->CreateVertexBuffer(m_nNumVertices * sizeof(TERRAINVERTEX), D3DUSAGE_WRITEONLY, TERRAINVERTEX::FVF, D3DPOOL_MANAGED, &m_pVertexBuffer, 0)))return false;//加锁TERRAINVERTEX *pVertices = NULL;m_pVertexBuffer->Lock(0, m_nNumVertices * sizeof(TERRAINVERTEX), (void **)&pVertices, 0);//访问,赋值float fStartX = -m_fTerrainWidth / 2.0f; //指定起始点和结束点的X坐标值float fEndX = m_fTerrainWidth / 2.0f; float fStartZ = m_fTerrainDepth / 2.0f; //指定起始点和结束点的Z坐标值float fEndZ = -m_fTerrainDepth / 2.0f;float fCoordU = 3.0f / m_nCellsPerRow; //指定纹理的横坐标值float fCoordV = 3.0f / m_nCellsPerCol; //指定纹理的纵坐标值int index = 0;int i, j;for(float z = fStartZ, i = 0; z >= fEndZ; z -= m_fCellSpacing, ++i) //Z坐标方向上起始顶点到结束顶点行间的遍历for(float x = fStartX, j = 0; x <= fEndX; x += m_fCellSpacing, ++j) //X坐标方向上起始顶点到结束顶点行间的遍历{//指定当前顶点在顶点缓存的位置index = i * m_nVertsPerRow + j;//把顶点位置索引在高度图中对应的各个顶点参数以及纹理坐标赋值给当前的顶点pVertices[index] = TERRAINVERTEX(x, m_vHeightInfo[index], z, j*fCoordU, i*fCoordV);}m_pVertexBuffer->Unlock();//处理地形的索引//创建索引缓存if(FAILED(m_pd3dDevice->CreateIndexBuffer(m_nCellsPerRow * m_nCellsPerCol * 6 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_pIndexBuffer, 0)))return false;WORD *pIndices = NULL;//加锁m_pIndexBuffer->Lock(0, m_nCellsPerRow * m_nCellsPerCol * 6 * sizeof(WORD), (void**)&pIndices, 0);//访问,赋值index = 0;for(int i = 0; i < m_nVertsPerRow - 1; ++i) //遍历每行,遍历每列for(int j = 0; j < m_nVertsPerCol - 1; ++j){//三角形ABC的三个顶点pIndices[index] = i*m_nVertsPerRow + j; //顶点ApIndices[index+1] = i*m_nVertsPerRow + j + 1; //顶点BpIndices[index+2] = (i + 1)*m_nVertsPerRow + j; //顶点C//三角形CBD的三个顶点pIndices[index+3] = (i + 1)*m_nVertsPerRow + j; //顶点CpIndices[index+4] = i*m_nVertsPerRow + j + 1; //顶点BpIndices[index+5] = (i+1)*m_nVertsPerRow + j + 1; //顶点D//处理每一个单元格,索引加6index += 6;}//解锁m_pIndexBuffer->Unlock();return true;
}
//-----------------------------------------------------------------------------
//绘制出地形,可以通过第二个参数选择是否绘制出线框
//-----------------------------------------------------------------------------
void TerrainClass::RenderTerrain(D3DXMATRIX *pMatWorld, bool bDrawFrame)
{m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); //关闭光照//把包含的几何体信息的顶点缓存和渲染流水线相关联m_pd3dDevice->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(TERRAINVERTEX));//指定我们使用的灵活顶点格式的宏名称m_pd3dDevice->SetFVF(TERRAINVERTEX::FVF);//设置索引缓存m_pd3dDevice->SetIndices(m_pIndexBuffer);//设置世界矩阵m_pd3dDevice->SetTransform(D3DTS_WORLD, pMatWorld);//设置纹理m_pd3dDevice->SetTexture(0, m_pTexture);//绘制顶点m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, m_nNumVertices, 0, m_nCellsPerRow * m_nCellsPerCol * 2);m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, true); //打开光照m_pd3dDevice->SetTexture(0, NULL); //纹理置空//如果要渲染出线框的话if(bDrawFrame) {//填充模式设为线框填充m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); //绘制顶点m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, m_nNumVertices, 0, m_nCellsPerRow * m_nCellsPerCol * 2);//把填充模式调回实体填充m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); }
}
//-----------------------------------------------------------------------------
//析构函数
//-----------------------------------------------------------------------------
TerrainClass::~TerrainClass(void)
{SAFE_RELEASE(m_pTexture);SAFE_RELEASE(m_pVertexBuffer);SAFE_RELEASE(m_pIndexBuffer);
}
WinMain.cpp
#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#include "CameraClass.h"
#include "DirectInputClass.h"
#include "TerrainClass.h"#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#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; //地形类的指针实例
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; //支持硬件顶点运算,采用硬件顶点运算elsevp = 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, 12000.0f, -30000.0f)); //设置摄像机所在的位置g_pCamera->SetTargetPosition(&D3DXVECTOR3(0.0f, 6000.0f, 0.0f)); //设置目标观察点所在的位置g_pCamera->SetViewMatrix(); //设置取景变换矩阵g_pCamera->SetProjMatrix(); //创建并初始化地形g_pTerrain = new TerrainClass(g_pd3dDevice);g_pTerrain->LoadTerrainFromFile(L"heighmap.raw", L"green.jpg"); //从文件读取高度图和纹理g_pTerrain->InitTerrain(200, 200, 500.0f, 60.0f); //顶点行数,顶点列数,顶点间间距,缩放系数//设置投影变换矩阵//以下这段代码用于限制鼠标光标移动区域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, <);ClientToScreen(hWnd, &rb);//以屏幕坐标重新设定矩形区域rect.left = lt.x;rect.top = lt.y;rect.right = rb.x;rect.bottom = rb.y;//限制鼠标光标移动区域ClipCursor(&rect);// 从X文件中加载网格数据LPD3DXBUFFER pAdjBuffer = NULL;LPD3DXBUFFER pMtrlBuffer = NULL;// 读取材质和纹理数据D3DXLoadMeshFromX(L"bee.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, 8000.0f, 100.0f, 50000.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(-10.0f);if (g_pDInput->IsKeyDown(DIK_D)) g_pCamera->MoveAlongRightVec( 10.0f);if (g_pDInput->IsKeyDown(DIK_W)) g_pCamera->MoveAlongLookVec( 10.0f);if (g_pDInput->IsKeyDown(DIK_S)) g_pCamera->MoveAlongLookVec(-10.0f);if (g_pDInput->IsKeyDown(DIK_I)) g_pCamera->MoveAlongUpVec( 10.0f);if (g_pDInput->IsKeyDown(DIK_K)) g_pCamera->MoveAlongUpVec(-10.0f);//沿摄像机各分量旋转视角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_J)) g_pCamera->RotationLookVec(-0.001f);if (g_pDInput->IsKeyDown(DIK_L)) 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);//定义一个矩形,用来获取主窗口矩形RECT formatRect;GetClientRect(hWnd, &formatRect);//---------------------------------------------------------------------------------------------------------------//【Direct3D渲染步骤二】:开始绘制//---------------------------------------------------------------------------------------------------------------g_pd3dDevice->BeginScene(); //开始绘制//---------------------------------------------------------------------------------------------------------------//【Direct3D渲染步骤三】:正式绘制//---------------------------------------------------------------------------------------------------------------//绘制大黄蜂D3DXMATRIX mScal,mRot1,mRot2,mTrans,mFinal; //定义一些矩阵,准备对大黄蜂进行矩阵变换D3DXMatrixScaling(&mScal,20.0f,20.0f,20.0f); D3DXMatrixTranslation(&mTrans,0,8000,0);D3DXMatrixRotationX(&mRot1, D3DX_PI/2); D3DXMatrixRotationY(&mRot2, D3DX_PI/2); mFinal=mScal*mRot1*mRot2*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, -10000.0f, 0.0f, -15000.0f + (i * 20000.0f));FinalMatrix = RotMatrix * TransMatrix ;g_pd3dDevice->SetTransform(D3DTS_WORLD, &FinalMatrix);g_pCylinder->DrawSubset(0);D3DXMatrixTranslation(&TransMatrix, 10000.0f, 0.0f, -15000.0f + (i * 20000.0f));FinalMatrix = RotMatrix * TransMatrix ;g_pd3dDevice->SetTransform(D3DTS_WORLD, &FinalMatrix);g_pCylinder->DrawSubset(0);}//绘制文字信息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" I:垂直向上飞翔 K:垂直向下飞翔", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));formatRect.top += 25;g_pTextHelper->DrawText(NULL, L" J:向左倾斜 L:向右倾斜", -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(0, 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_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);
}
【游戏程序设计】Direct 3D 三维地形系统相关推荐
- 【Visual C++】游戏开发四十八 浅墨DirectX教程十六 三维地形系统的实现
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...
- 【Visual C++】游戏开发四十八 浅墨DirectX教程十六 三维地形系统的实现
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/zhmxy555/article/details/8685546 作者:毛星云(浅墨) ...
- 构建地形系统(翻译)1
FW: http://www.sf.org.cn/design/Design_Tutorial/design_19213.html 地形系统是一块薄片,我们在这块薄片上面调制我们关卡的美味大餐.嘿!那 ...
- 【游戏程序设计】Direct 3D第一人称摄像机
因为浅墨的摄像机有镜头倾斜的问题,根据评论对其做了一些改变,最终可以让镜头不倾斜了. 具体改动的函数是绕上向量旋转的函数.将绕上向量旋转改为绕Y轴旋转即可.因为根据人的视觉习惯是绕Y轴旋转的. //- ...
- 【游戏程序设计】三维游戏示例-战术竞技游戏Demo(二)
突然相遇: 然后死掉. 源代码以及实现方法: 首先定义一个Character类为角色的基类,然后英雄魔兽(战士)类Warcraft与托尼(法师)类Timy继承于它.分别实现对应的方法. 角色类有许多的 ...
- 什么是机房三维(3D)监控系统,什么是机房可视化动力环境监控系统?
随着计算机技术的迅速发展,数字交换技术的日新月异,计算机通信已经深入到社会生活并对社会经济的发展起着决定性的作用,而在这其中计算机机房数据中心作为载体更是整体生态链中的重中之重.如果没有统一的监控系统 ...
- 机房三维(3D)监控系统和机房可视化动力环境监控系统两者有什么特点?
随着计算机技术的迅速发展,数字交换技术的日新月异,计算机通信已经深入到社会生活并对社会经济的发展起着决定性的作用,而在这其中计算机机房数据中心作为载体更是整体生态链中的重中之重.如果没有统一的监控系统 ...
- 游戏设计之基于高程图的三维地形绘制
2015年完成的游戏设计课程大型实验论文(基础应用) -- 引用请联系博主 一.概述 地形绘制是室外三维游戏中必须面对的问题.三维真实感地形是虚拟场景中的基础部分,利用Visual C++,以通用的标 ...
- 三维可视化建模-园区3d可视化-3d数字孪生系统建设
3D虚实联动三维仿真园区可视化展示系统可以实时显示数据,提出需求发现问题,并且作出及时准确的反馈,商迪3D通过3D建模.大数据.物联网.3d可视化.虚拟现实等数字化手段,把园区设备映射到虚拟仿真空间可 ...
最新文章
- php-函数小知识点
- WCF后传系列(3):深入WCF寻址Part 3—消息过滤引擎
- Linux上Svn环境搭建
- git reset 怎么还原_如何在Git中重置、恢复,返回到以前的状态
- [转载] python并行处理任务_Python 并行任务技巧
- Linux硬盘分区与文件系统---学习笔记
- 181212每日一句
- VOSviewer初步学习
- c语言小车程序,循迹小车程序C语言
- teamview linux命令行安装参数
- con 元器件符号_altium designer常用元件电气符号和封装形式
- 二乘二(二阶)魔方教程,看完教程拼不出来我给你钱!
- linux 配置局域网内部www服务器,局域网内部邮件服务器搭建方法
- QQ群反向昵称、恶搞昵称的原理
- html的nofollow、noindex标签
- vue3中的provide/inject(提供/注入)
- 3蛋白wb_99% 的实验小白都会收藏,WB、ELISA、IHC 进阶攻略
- C语言学习之指针 *p++、*(p++)、(*p)++
- python math模块
- 电脑蓝屏,错误代码为“KERNEL STACK INPAGE ERROR”
热门文章
- 如何在Windows 10上控制多个显示器的功能
- 关于IE、Firefox、Opera页面呈现异同 (转于纯蓝)
- 世界名画陈列馆(最少机器人问题和不重复监视问题)
- python机器学习——决策树(分类)及“泰坦尼克号沉船事故”数据集案例操作
- 五一影视圈的神仙打架,揭开了内容市场暗自角力的真相
- 人类一败涂地!DeepMind再次制霸Atari游戏,比两年前快了200倍
- java/php/net/python守望先锋网站设计
- 【Android折叠屏适配】基于AutoSize框架适配折叠屏并兼容多窗口模式
- 我在windows10下,使用CMake gui 编译krita源码
- Powershell无法执行脚本问题解决方案