Direct-X学习笔记--封装一个网格模型类

来源:互联网 发布:阿里云os刷机 编辑:程序博客网 时间:2024/05/21 17:47

之前学习了网格模型的导入,绘制,了解了X文件等相关知识,但是,那样绘制比较麻烦,而且绘制一个模型需要好多代码,完全是面向过程的思维,这次,学习一下怎么把网格模型的导入以及绘制等功能封装在一个类中。顺便加深一下对World Transform的理解。感觉自己的3D思维还是没有培养起来,想绘制一个对象,绘制出来和想象中的位置相差甚远。


一.复习一下网格模型相关知识

网格模型就是一个我们在美术工具中制作好的资源,通过一些API接口我们可以将美术童鞋做好的模型很方便的导入程序中。我们只需要了解怎样从文件中创建网格模型和怎么绘制网格模型就行啦!

这次我们跟上一次程序差不多,都是从文件中读取网格文件信息,然后根据读取的信息加载材质纹理,只不过加了一个网格的优化,以及将网格加载和绘制封装在一个类中。


二.优化网格

我们通常使用OptimizeInplace函数来优化一下网格内容,去除一些无用的顶点等信息,这样我们就可以在绘制使用时更加流畅了。
OptimizeInplace函数参数如下,这个函数是直接在原来的Mesh上进行优化的。还有一个Optimize函数,是将优化后的Mesh又输出到另一个Mesh指针所指向的位置中。
HRESULT OptimizeInplace(  [in]   DWORD Flags,//参数,按照例子中的写即可  [in]   const DWORD *pAdjacencyIn,//优化前网格邻接信息数组的指针  [out]  DWORD *pAdjacencyOut,//优化后网格邻接信息数组的指针  [out]  DWORD *pFaceRemap,<//null即可  [out]  LPD3DXBUFFER *ppVertexRemap//null即可);

三.Mesh类的设计

面向对象万岁!来来来,封装一个类!
之前我们绘制一个Mesh需要两个函数,一堆全局变量,这次,我们将其封装在一个类中。

头文件:
/*! * \file Mesh.h * * \author puppet_master * \date 七月 2015 *网格模型类:负责导入模型以及绘制模型 *  */#ifndef __MESH_H_#define __MESH_H_#pragma once#include "stdafx.h"class CMesh{public:CMesh(LPDIRECT3DDEVICE9 pDevice);~CMesh(void);//创建网格对象void CreateMesh(LPSTR filename);//绘制网格对象void DrawMesh(const D3DXMATRIXA16& matWorld);private:LPDIRECT3DDEVICE9 m_pDevice;    //D3D设备指针LPD3DXMESH m_pMesh;//网格对象LPDIRECT3DTEXTURE9* m_pTextures;//网格纹理信息D3DMATERIAL9* m_pMaterials;//网格材质信息DWORD m_dwNumMtrls;//网格材质数目};#endif // !__MESH_H_


cpp文件:
#include "stdafx.h"#include "Mesh.h"CMesh::CMesh(LPDIRECT3DDEVICE9 pDevice) : m_pDevice(pDevice){}CMesh::~CMesh(void){//释放相关资源SAFE_DELETE_ARRAY(m_pMaterials);if (m_pTextures){for (int i = 0; i < m_dwNumMtrls; i++){SAFE_RELEASE(m_pTextures[i]);}SAFE_DELETE_ARRAY(m_pTextures);}SAFE_RELEASE(m_pMesh);}void CMesh::CreateMesh(LPSTR filename){LPD3DXBUFFER pAdjBuffer = NULL;LPD3DXBUFFER pMtrlBuffer = NULL;D3DXLoadMeshFromX(filename, D3DXMESH_MANAGED, m_pDevice, &pAdjBuffer, &pMtrlBuffer, NULL, &m_dwNumMtrls, &m_pMesh);//读取材质和纹理数据D3DXMATERIAL *pMtrl = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer();m_pMaterials = new D3DMATERIAL9[m_dwNumMtrls];m_pTextures = new LPDIRECT3DTEXTURE9[m_dwNumMtrls];for (int i = 0; i < m_dwNumMtrls; i++){m_pMaterials[i] = pMtrl[i].MatD3D;m_pMaterials[i].Ambient = m_pMaterials[i].Diffuse;m_pTextures[i] = NULL;D3DXCreateTextureFromFileA(m_pDevice, pMtrl[i].pTextureFilename, &m_pTextures[i]);}//优化网格模型m_pMesh->OptimizeInplace(D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT| D3DXMESHOPT_STRIPREORDER, (DWORD*)pAdjBuffer->GetBufferPointer(), NULL, NULL, NULL);SAFE_RELEASE(pAdjBuffer);SAFE_RELEASE(pMtrlBuffer);}void CMesh::DrawMesh(const D3DXMATRIXA16& matWorld){m_pDevice->SetTransform(D3DTS_WORLD, &matWorld);m_pDevice->SetRenderState(D3DRS_LIGHTING, false);for (int i = 0; i < m_dwNumMtrls; i++){m_pDevice->SetMaterial(&m_pMaterials[i]);m_pDevice->SetTexture(0, m_pTextures[i]);m_pMesh->DrawSubset(i);}}


四.实际运用一下

这里仅贴出了main函数文件的代码:
// D3DDemo.cpp : 定义应用程序的入口点。//#include "stdafx.h"#include "D3DDemo.h"#include "DirectInput.h"#include "Camera.h"#include "Terrain.h"#include "Mesh.h"#define MAX_LOADSTRING 100// 全局变量:HINSTANCE hInst;// 当前实例TCHAR szTitle[MAX_LOADSTRING];// 标题栏文本TCHAR szWindowClass[MAX_LOADSTRING];// 主窗口类名// 此代码模块中包含的函数的前向声明:HWND                g_hWnd;ATOMMyRegisterClass(HINSTANCE hInstance);BOOLInitInstance(HINSTANCE, int);LRESULT CALLBACKWndProc(HWND, UINT, WPARAM, LPARAM);//---------改造3D窗口需要的内容------------LPDIRECT3D9 g_pD3D = NULL;//D3D接口指针LPDIRECT3DDEVICE9 g_pDevice = NULL;//D3D设备指针CDirectInput* g_pDirectInput = NULL;//控制指针CCamera*      g_pCamera      = NULL;    //摄像机指针CTerrain*     g_pTerrian     = NULL;//地形类指针CMesh*        g_pMesh1       = NULL;//网格对象指针1CMesh*        g_pMesh2       = NULL;//网格对象指针2CMesh*      g_pMesh3       = NULL;//网格对象指针3LPDIRECT3DTEXTURE9  g_pGroundTexture = NULL;//地面纹理D3DXMATRIX g_matWorld;//世界矩阵//------------绘制图形步骤1.定义灵活顶点格式#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_TEX1)//坐标为经过变换的屏幕坐标,顶点的颜色//------------绘制图形步骤2.根据上面定义的顶点格式,创建一个顶点的结构体struct stVertex{float _x, _y, _z;//位置坐标float _u, _v;//纹理坐标stVertex(float x, float y, float z, float u, float v) : _x(x), _y(y), _z(z), _u(u), _v(v){}stVertex(){}};//----------绘制图形步骤3.声明一个顶点缓冲区指针&一个索引缓冲区指针LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;void onCreatD3D(){g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);if (!g_pD3D)return;//检测硬件设备能力的方法/*D3DCAPS9 caps;ZeroMemory(&caps, sizeof(caps));g_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);*///获得相关信息,屏幕大小,像素点属性D3DDISPLAYMODE d3ddm;ZeroMemory(&d3ddm, sizeof(d3ddm));g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);//设置全屏模式D3DPRESENT_PARAMETERS d3dpp;ZeroMemory(&d3dpp, sizeof(d3dpp));/*d3dpp.Windowed = false;d3dpp.BackBufferWidth = d3ddm.Width;d3dpp.BackBufferHeight = d3ddm.Height;*/d3dpp.Windowed = true;d3dpp.BackBufferFormat = d3ddm.Format;d3dpp.BackBufferCount = 1;d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//交换后原缓冲区数据丢弃//是否开启自动深度模板缓冲d3dpp.EnableAutoDepthStencil = true;//当前自动深度模板缓冲的格式d3dpp.AutoDepthStencilFormat = D3DFMT_D16;//每个像素点有16位的存储空间,存储离摄像机的距离g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pDevice);if (!g_pDevice)return;//设置渲染状态,设置启用深度值g_pDevice->SetRenderState(D3DRS_ZENABLE, true);//设置渲染状态,关闭灯光g_pDevice->SetRenderState(D3DRS_LIGHTING, false);//设置渲染状态,裁剪模式g_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);//g_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE) ;}void CreateMesh(){g_pMesh1 = new CMesh(g_pDevice);g_pMesh1->CreateMesh("miki.X");g_pMesh2 = new CMesh(g_pDevice);g_pMesh2->CreateMesh("Demon.X");g_pMesh3 = new CMesh(g_pDevice);g_pMesh3->CreateMesh("dragon.X");}void CreateCamera(){g_pCamera = new CCamera(g_pDevice);g_pCamera->SetCameraPosition(&D3DXVECTOR3(0.0f, 0.0f, -500.0f));g_pCamera->SetTargetPosition(&D3DXVECTOR3(0.0f, 0.0f, 0.0f));g_pCamera->SetViewMatrix();g_pCamera->SetProjectionMartix();}void onInit(){//初始化D3DonCreatD3D();//初始化顶点缓冲区initVB();//创建Mesh模型CreateMesh();//创建摄像机CreateCamera();//创建地形CreateTerrain();}void onDestroy(){SAFE_DELETE(g_pDirectInput);SAFE_DELETE(g_pCamera);SAFE_DELETE(g_pTerrian);SAFE_RELEASE(g_pDevice);}void onLogic(float fElapsedTime){//使用DirectInput类读取数据g_pDirectInput->GetInput();// 沿摄像机各分量移动视角if (g_pDirectInput->IsKeyDown(DIK_A))  g_pCamera->MoveAlongRightVec(-10.0f);if (g_pDirectInput->IsKeyDown(DIK_D))  g_pCamera->MoveAlongRightVec( 10.0f);if (g_pDirectInput->IsKeyDown(DIK_W)) g_pCamera->MoveAlongLookVec( 10.0f);if (g_pDirectInput->IsKeyDown(DIK_S))  g_pCamera->MoveAlongLookVec(-10.0f);if (g_pDirectInput->IsKeyDown(DIK_I))  g_pCamera->MoveAlongUpVec( 10.0f);if (g_pDirectInput->IsKeyDown(DIK_K))  g_pCamera->MoveAlongUpVec(-10.0f);//沿摄像机各分量旋转视角if (g_pDirectInput->IsKeyDown(DIK_LEFT))  g_pCamera->RotationUpVec(-0.003f);if (g_pDirectInput->IsKeyDown(DIK_RIGHT))  g_pCamera->RotationUpVec( 0.003f);if (g_pDirectInput->IsKeyDown(DIK_UP))  g_pCamera->RotationRightVec(-0.003f);if (g_pDirectInput->IsKeyDown(DIK_DOWN))  g_pCamera->RotationRightVec( 0.003f);if (g_pDirectInput->IsKeyDown(DIK_J)) g_pCamera->RotationLookVec(-0.001f);if (g_pDirectInput->IsKeyDown(DIK_L)) g_pCamera->RotationLookVec( 0.001f);//鼠标控制右向量和上向量的旋转//g_pCamera->RotationUpVec(g_pDirectInput->MouseDX()* 0.001f);//g_pCamera->RotationRightVec(g_pDirectInput->MouseDY() * 0.001f);//鼠标滚轮控制观察点收缩操作static FLOAT fPosZ=0.0f;fPosZ += g_pDirectInput->MouseDZ()*3.0f;//计算并设置取景变换矩阵D3DXMATRIX matView;g_pCamera->CalculateViewMatrix(&matView);g_pDevice->SetTransform(D3DTS_VIEW, &matView);//把正确的世界变换矩阵存到g_matWorld中D3DXMatrixTranslation(&g_matWorld, 0.0f, 0.0f, fPosZ);}void onRender(float fElasedTime){//前两个参数是0和NULL时,清空整个游戏窗口的内容(清的是后台)//第三个是清除的对象:前面表示清除颜色缓冲区,后面表示清除深度缓冲区,D3DCLEAR_STENCIL清空模板缓冲区g_pDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,100,100), 1.0f, 0);g_pDevice->BeginScene();D3DXMATRIX matWorld1, matWorld2, matWorld3;  D3DXMatrixTranslation(&matWorld1, 0.0f, 100.0f, 0.0f);  D3DXMatrixTranslation(&matWorld2, 300.0f, 0.0f, 0.0f);D3DXMatrixTranslation(&matWorld3, 0.0f, 0.0f, 0.0f);g_pMesh1->DrawMesh(matWorld1);g_pMesh2->DrawMesh(matWorld2);g_pMesh3->DrawMesh(matWorld3);g_pDevice->EndScene();g_pDevice->Present(NULL, NULL, NULL, NULL);}int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,                     _In_opt_ HINSTANCE hPrevInstance,                     _In_ LPTSTR    lpCmdLine,                     _In_ int       nCmdShow){UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine); // TODO: 在此放置代码。MSG msg;HACCEL hAccelTable;// 初始化全局字符串LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadString(hInstance, IDC_D3DDEMO, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);// 执行应用程序初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_D3DDEMO));ZeroMemory(&msg, sizeof(msg));while (msg.message != WM_QUIT){if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}else{static DWORD dwTime = timeGetTime();DWORD dwCurrentTime = timeGetTime();DWORD dwElapsedTime = dwCurrentTime - dwTime;float fElapsedTime = dwElapsedTime * 0.001f;//------------渲染和逻辑部分代码----------onLogic(fElapsedTime);onRender(fElapsedTime);//-----------------------------------------if (dwElapsedTime < 1000 / 60){Sleep(1000/ 60 - dwElapsedTime);}dwTime = dwCurrentTime;}}onDestroy();return (int) msg.wParam;}////  函数: MyRegisterClass()////  目的: 注册窗口类。//ATOM MyRegisterClass(HINSTANCE hInstance){WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style= CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc= WndProc;wcex.cbClsExtra= 0;wcex.cbWndExtra= 0;wcex.hInstance= hInstance;wcex.hIcon= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_D3DDEMO));wcex.hCursor= LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName= MAKEINTRESOURCE(IDC_D3DDEMO);wcex.lpszClassName= szWindowClass;wcex.hIconSm= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));return RegisterClassEx(&wcex);}////   函数: InitInstance(HINSTANCE, int)////   目的: 保存实例句柄并创建主窗口////   注释:////        在此函数中,我们在全局变量中保存实例句柄并//        创建和显示主程序窗口。//BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){   hInst = hInstance; // 将实例句柄存储在全局变量中   g_hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);   if (!g_hWnd)   {      return FALSE;   }  //初始化DirectInput类   g_pDirectInput = new CDirectInput();   g_pDirectInput->Init(g_hWnd, hInst, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);   SetMenu(g_hWnd, NULL);   ShowWindow(g_hWnd, nCmdShow);   UpdateWindow(g_hWnd);   onInit();   return TRUE;}////  函数: WndProc(HWND, UINT, WPARAM, LPARAM)////  目的: 处理主窗口的消息。////  WM_COMMAND- 处理应用程序菜单//  WM_PAINT- 绘制主窗口//  WM_DESTROY- 发送退出消息并返回////LRESULT CALLBACK WndProc(HWND g_hWnd, UINT message, WPARAM wParam, LPARAM lParam){switch (message){case WM_KEYDOWN:if (wParam == VK_ESCAPE)PostQuitMessage(0);break;case WM_CLOSE:DestroyWindow(g_hWnd);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(g_hWnd, message, wParam, lParam);}return 0;}

好了,其实这次主要是来巩固一下WorldTransform的,感觉学习D3D一小段时间了,还是没有形成3D的思维。

好吧,又从浅墨大大那里偷的资源。。。


龙骑士美少女:

凶神恶煞的东东:


摄像机观察(0,0,0),位置在(0, 0, -500),龙在(0, 0, 0),即摄像机观察点,而初音的模型在(0, 100, 0)处,即在龙上面,而红色怪物在(500, 0, 0)处,即在龙的右侧。



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 狗狗牙齿松动了怎么办 狗狗牙齿掉了怎么办 眼镜金属架断了怎么办 纯钛眼镜架断了怎么办 万次火柴没油了怎么办 火疖子破了流脓怎么办 火疖子没有脓头怎么办 孕妇长火疖子疼怎么办 手上长小水泡痒怎么办 脚上起水泡很痒怎么办 手指上有水泡痒怎么办 手指起小水泡痒怎么办 手过敏起小水泡怎么办 头皮上白色像癣怎么办 脸上长了火疖子怎么办 脸上长硬硬的包怎么办 下身体痒痒得不得了怎么办 头皮干痒头屑多怎么办 头发掉的露头皮怎么办 头上老是有结痂怎么办 婴儿头上的黄痂怎么办 头皮屑多又痒怎么办小偏方 皮肤瘙痒起红疙瘩怎么办 头又油又痒怎么办 头上反复长脓包怎么办 额头上长了粉刺怎么办 身上长红疙瘩很痒怎么办 脸上的痘痘变硬怎么办 痘痘变成硬疙瘩怎么办 痘痘变硬了怎么办知乎 痘痘里面是硬的怎么办 皮肤出油毛孔大怎么办 蹭无线网信号差怎么办 无线网离得太远怎么办 无线网不好使了怎么办 火疖子化脓破了怎么办 脸上长了个疖子怎么办 脸上起了火疖子怎么办 脸上长了火疙瘩怎么办 脸上长疖子了该怎么办? 头上神经线疼怎么办