directX基础学习系列7 网格(自己创建)
D3DXMesh 以及 D3DXPMesh都是从ID3DXBaseMesh类中集成,mesh基本是对三角单元进行操作
ID3DXBaseMesh主要函数:
HRESULT DrawSubset( DWORD AttribId);
HRESULT GetIndexBuffer( LPDIRECT3DINDEXBUFFER9 * ppIB);
HRESULT GetVertexBuffer( LPDIRECT3DVERTEXBUFFER9 * ppVB);
HRESULT LockIndexBuffer( DWORD Flags, LPVOID * ppData);
HRESULT UnlockIndexBuffer();
HRESULT CloneMesh( DWORD Options, CONST D3DVERTEXELEMENT9 * pDeclaration, LPDIRECT3DDEVICE9pDevice, LPD3DXMESH * ppCloneMesh);
HRESULT CloneMeshFVF( DWORD Options, DWORD FVF, LPDIRECT3DDEVICE9 pDevice, LPD3DXMESH * ppCloneMesh);
DWORD GetOptions();获得当前网格的选项
DWORD GetFVF();
DWORD GetNumVertices();
DWORD GetNumBytesPerVertex();
DWORD GetNumFaces();
1 子集和属性缓存
子集:mesh由子集构成,一个子集是网格中相同属性的三角新单元,每个子集有子集属性ID
属性缓存:三角形单元属性ID存储位置,和网格索引中三角形单元的数目相同,属性缓存项与网格索引缓存中的数据一一对应。
获得索引的办法:
HRESULT LockAttributeBuffer( DWORD Flags, DWORD ** ppData);
HRESULT UnlockAttributeBuffer();
2绘制
HRESULT DrawSubset( DWORD AttribId);
3优化
对网格中的索引和顶点进行重组
HRESULT OptimizeInplace( DWORD Flags, 优化标记 CONST DWORD * pAdjacencyIn, 指向未经优化的网格临街信息数组的指针 DWORD * pAdjacencyOut, 指向优化后的网格临街信息数组的指针 3 * GetNumFaces() DWORD * pFaceRemap, 优化过程中 原始面片被移动到新的面片位置 GetNumFaces()
LPD3DXBUFFER * ppVertexRemap 顶点被移动到新的顶点位置 GetNumFaces()
);
//优化标记
typedef enum D3DXMESHOPT { D3DXMESHOPT_COMPACT = 0x01000000,移除没用的顶点和索引 D3DXMESHOPT_ATTRSORT = 0x02000000, 根据属性重新排序 D3DXMESHOPT_VERTEXCACHE = 0x04000000, 提高顶点高速缓存的命中率 D3DXMESHOPT_STRIPREORDER = 0x08000000, 对索引进行重组 D3DXMESHOPT_IGNOREVERTS = 0x10000000, D3DXMESHOPT_DONOTSPLIT = 0x20000000, D3DXMESHOPT_DEVICEINDEPENDENT = 0x40000000, } D3DXMESHOPT, *LPD3DXMESHOPT;
另一个优化函数:会修改原始网格数据
HRESULT Optimize( DWORD Flags, CONST DWORD * pAdjacencyIn, DWORD * pAdjacencyOut, DWORD * pFaceRemap, LPD3DXBUFFER * ppVertexRemap, LPD3DXMESH * ppOptMesh);
4属性表
属性表经过D3DXMESHOPT_ATTRSORT标志排序后,相同属性的三角形面片的属性信息和顶点列表就会存储在连续的区域中,可以通过 函数:
HRESULT GetAttributeTable( D3DXATTRIBUTERANGE * pAttribTable, DWORD * pAttribTableSize)
来获得网格中属性信息列表,属性信息列表的结构:
typedef struct D3DXATTRIBUTERANGE { DWORD AttribId; 属性ID DWORD FaceStart; 索引缓存中的其实位置 3* FaceStart
DWORD FaceCount; 面片数目 DWORD VertexStart;顶点缓存其实位置 DWORD VertexCount; } D3DXATTRIBUTERANGE, *LPD3DXATTRIBUTERANGE;
属性表获取:
GetAttributeTable(0,&num);
D3DXATTRIBUTERANGE table = new D3DXATTRIBUTERANGE[num];
GetAttributeTable(table ,&num);
设置属性表:
HRESULT SetAttributeTable( CONST D3DXATTRIBUTERANGE * pAttribTable, DWORD cAttribTableSize);
5邻接信息
每个三角形面片有三个边,最多三个邻接信息,无效邻接信息为-1或者ULONG_MAX
邻接数组大小为Get FaceNun*3
获得邻接数据函数:
HRESULT GenerateAdjacency( FLOAT Epsilon, DWORD * pAdjacency);
Epsilon:指定两个点距离多近可以算作同一个点
pAdjacency:DWORD数组
6网格顶点复制
HRESULT CloneMeshFVF( DWORD Options, DWORD FVF, LPDIRECT3DDEVICE9 pDevice, LPD3DXMESH * ppCloneMesh);
Options:创建网格副本是的可选项
FVF:灵活顶点格式
DWORD GetOptions();获得当前网格的选项
7创建网格
HRESULT D3DXCreateMesh( DWORD NumFaces, DWORD NumVertices, DWORD Options, CONST LPD3DVERTEXELEMENT9 * pDeclaration, LPDIRECT3DDEVICE9 pD3DDevice, LPD3DXMESH * ppMesh);
HRESULT D3DXCreateMeshFVF( DWORD NumFaces, DWORD NumVertices, DWORD Options, DWORD FVF, LPDIRECT3DDEVICE9 pD3DDevice, LPD3DXMESH * ppMesh);
typedef struct D3DVERTEXELEMENT9 { WORD Stream; WORD Offset; BYTE Type; BYTE Method; BYTE Usage; BYTE UsageIndex; } D3DVERTEXELEMENT9, *LPD3DVERTEXELEMENT9;
8网格创建与绘制
1创建网格对象
2将面片数据写入网格缓存
3指定每个面片所属的子集
4生成邻接信息,优化网格
5绘制网格
#include "d3dUtility.h" #include <fstream> #include <vector> // // Globals // IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; ID3DXMesh* Mesh = 0; const DWORD NumSubsets = 3; IDirect3DTexture9* Textures[3] = {0, 0, 0};// texture for each subset std::ofstream OutFile; // used to dump mesh data to file // // Prototypes // void dumpVertices(std::ofstream& outFile, ID3DXMesh* mesh); void dumpIndices(std::ofstream& outFile, ID3DXMesh* mesh); void dumpAttributeBuffer(std::ofstream& outFile, ID3DXMesh* mesh); void dumpAdjacencyBuffer(std::ofstream& outFile, ID3DXMesh* mesh); void dumpAttributeTable(std::ofstream& outFile, ID3DXMesh* mesh); // // Classes and Structures // struct Vertex { Vertex(){} Vertex(float x, float y, float z, float nx, float ny, float nz, float u, float v) { _x = x; _y = y; _z = z; _nx = nx; _ny = ny; _nz = nz; _u = u; _v = v; } float _x, _y, _z, _nx, _ny, _nz, _u, _v; static const DWORD FVF; }; const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; // // Framework functions // bool Setup() { HRESULT hr = 0; // // We are going to fill the empty mesh with the geometry of a box, // so we need 12 triangles and 24 vetices. // hr = D3DXCreateMeshFVF( 12, 24, D3DXMESH_MANAGED, Vertex::FVF, Device, &Mesh); if(FAILED(hr)) { ::MessageBox(0, "D3DXCreateMeshFVF() - FAILED", 0, 0); return false; } // // Fill in vertices of a box // Vertex* v = 0; Mesh->LockVertexBuffer(0, (void**)&v); // fill in the front face vertex data v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f); v[1] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f); v[2] = Vertex( 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f); v[3] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f); // fill in the back face vertex data v[4] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); v[5] = Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f); v[6] = Vertex( 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f); v[7] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f); // fill in the top face vertex data v[8] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); v[9] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f); v[10] = Vertex( 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f); v[11] = Vertex( 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f); // fill in the bottom face vertex data v[12] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f); v[13] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f); v[14] = Vertex( 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f); v[15] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f); // fill in the left face vertex data v[16] = Vertex(-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f); v[17] = Vertex(-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f); v[18] = Vertex(-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f); v[19] = Vertex(-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f); // fill in the right face vertex data v[20] = Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f); v[21] = Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f); v[22] = Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f); v[23] = Vertex( 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f); Mesh->UnlockVertexBuffer(); // // Define the triangles of the box // WORD* i = 0; Mesh->LockIndexBuffer(0, (void**)&i); // fill in the front face index data i[0] = 0; i[1] = 1; i[2] = 2; i[3] = 0; i[4] = 2; i[5] = 3; // fill in the back face index data i[6] = 4; i[7] = 5; i[8] = 6; i[9] = 4; i[10] = 6; i[11] = 7; // fill in the top face index data i[12] = 8; i[13] = 9; i[14] = 10; i[15] = 8; i[16] = 10; i[17] = 11; // fill in the bottom face index data i[18] = 12; i[19] = 13; i[20] = 14; i[21] = 12; i[22] = 14; i[23] = 15; // fill in the left face index data i[24] = 16; i[25] = 17; i[26] = 18; i[27] = 16; i[28] = 18; i[29] = 19; // fill in the right face index data i[30] = 20; i[31] = 21; i[32] = 22; i[33] = 20; i[34] = 22; i[35] = 23; Mesh->UnlockIndexBuffer(); // // Specify the subset each triangle belongs to, in this example // we will use three subsets, the first two faces of the cube specified // will be in subset 0, the next two faces will be in subset 1 and // the the last two faces will be in subset 2. // DWORD* attributeBuffer = 0; Mesh->LockAttributeBuffer(0, &attributeBuffer); for(int a = 0; a < 4; a++) attributeBuffer[a] = 0; for(int b = 4; b < 8; b++) attributeBuffer[b] = 1; for(int c = 8; c < 12; c++) attributeBuffer[c] = 2; Mesh->UnlockAttributeBuffer(); // // Optimize the mesh to generate an attribute table. // std::vector<DWORD> adjacencyBuffer(Mesh->GetNumFaces() * 3); Mesh->GenerateAdjacency(0.0f, &adjacencyBuffer[0]); hr = Mesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, &adjacencyBuffer[0], 0, 0, 0); // // Dump the Mesh Data to file. // OutFile.open("Mesh Dump.txt"); dumpVertices(OutFile, Mesh); dumpIndices(OutFile, Mesh); dumpAttributeTable(OutFile, Mesh); dumpAttributeBuffer(OutFile, Mesh); dumpAdjacencyBuffer(OutFile, Mesh); OutFile.close(); // // Load the textures and set filters. // D3DXCreateTextureFromFile( Device, "brick0.jpg", &Textures[0]); D3DXCreateTextureFromFile( Device, "brick1.jpg", &Textures[1]); D3DXCreateTextureFromFile( Device, "checker.jpg", &Textures[2]); Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); // // Disable lighting. // Device->SetRenderState(D3DRS_LIGHTING, false); // // Set camera. // D3DXVECTOR3 pos(0.0f, 0.f, -4.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH( &V, &pos, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); // // Set projection matrix. // D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, D3DX_PI * 0.5f, // 90 - degree (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); return true; } void Cleanup() { d3d::Release<ID3DXMesh*>(Mesh); d3d::Release<IDirect3DTexture9*>(Textures[0]); d3d::Release<IDirect3DTexture9*>(Textures[1]); d3d::Release<IDirect3DTexture9*>(Textures[2]); } bool Display(float timeDelta) { if( Device ) { // // Update: Rotate the cube. // D3DXMATRIX xRot; D3DXMatrixRotationX(&xRot, D3DX_PI * 0.2f); static float y = 0.0f; D3DXMATRIX yRot; D3DXMatrixRotationY(&yRot, y); y += timeDelta; if( y >= 6.28f ) y = 0.0f; D3DXMATRIX World = xRot * yRot; Device->SetTransform(D3DTS_WORLD, &World); // // Render // Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0); Device->BeginScene(); for(int i = 0; i < NumSubsets; i++) { Device->SetTexture( 0, Textures[i] ); Mesh->DrawSubset( i ); } Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; }