一.简介
d3dx9mesh.h有关网格模型
二.灵活的顶点格式
Direct3D中的顶点不只有空间位置属性,还可以有颜色 法线向量属性等,所以可以自定义一个顶点结构
1.使用
struct ColorVertex{
float _x,_y,_z; //位置
DWORD _color; //颜色
};
#define FVF_COLOR(D3DFVF_XYZ | D3DFVF_DIFFUSE) //包含位置属性和漫反射颜色属
struct NormaolTexVertex{
float _x,_y,_z; //位置
float _nx,_ny,_nz; //法线
float _u,_v; //纹理坐标
};
#define FVF_NORMAL_TEX(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
//灵活的顶点格式 struct Vertex{ Vertex(){} Vertex(float x,float y,float z){ _x=x; _y=y; _z=z; } float _x,_y,_z; static const DWORD FVF; }; const DWORD Vertex::FVF=D3DFVF_XYZ; bool Setup(){ //根据灵活的顶点格式来创建顶点缓存 Device->CreateVertexBuffer( 3*sizeof(Vertex), D3DUSAGE_WRITEONLY, Vertex::FVF, D3DPOOL_MANAGED, &Triangle, 0); } bool Display(float timeDelta){ //根据灵活的顶点格式来绑定模型数据 Device->SetFVF(Vertex::FVF); }
2.FVF宏定义
#define D3DFVF_RESERVED0 0x001
#define D3DFVF_POSITION_MASK 0x400E
#define D3DFVF_XYZ 0x002 //包含三维坐标
#define D3DFVF_XYZRHW 0x004
#define D3DFVF_XYZB1 0x006
#define D3DFVF_XYZB2 0x008
#define D3DFVF_XYZB3 0x00a
#define D3DFVF_XYZB4 0x00c
#define D3DFVF_XYZB5 0x00e
#define D3DFVF_XYZW 0x4002
#define D3DFVF_NORMAL 0x010
#define D3DFVF_PSIZE 0x020
#define D3DFVF_DIFFUSE 0x040
#define D3DFVF_SPECULAR 0x080
#define D3DFVF_TEXCOUNT_MASK 0xf00
#define D3DFVF_TEXCOUNT_SHIFT 8
#define D3DFVF_TEX0 0x000
#define D3DFVF_TEX1 0x100
#define D3DFVF_TEX2 0x200
#define D3DFVF_TEX3 0x300
#define D3DFVF_TEX4 0x400
#define D3DFVF_TEX5 0x500
#define D3DFVF_TEX6 0x600
#define D3DFVF_TEX7 0x700
#define D3DFVF_TEX8 0x800
#define D3DFVF_LASTBETA_UBYTE4 0x1000
#define D3DFVF_LASTBETA_D3DCOLOR 0x8000
#define D3DFVF_RESERVED2 0x6000
三.顶点缓存
一个顶点缓存是一个包含顶点数据的连续内存空间,存放在显存之中,比内存快(用于存储网格顶点)
1.CreateVertexBuffer
注意:静态缓存处理快,但是更新重绘慢.动态缓存处理慢,但是更新重绘快
HRESULT IDirect3DDevice9::CreatVertexBuffer( //创建顶点缓存
UINT Length,DWORD Usage,
DWORD FVF,
D3DPOOL Pool,
IDirect3DVertexBuffer9** ppVertexBuffer,
HANDLE* pSharedHandle
);
Length:为缓存分配的字节数,8个顶点需要8*sizeof(Vertex)
Usage:附加属性
(1)D3DUSAGE_DYNAMIC 将缓存设为动态缓存
(2)D3DUSAGE_POINTS 规定缓存将用于存储点图元
(3)D3DUSAGE_SOFTWAREPROCESSING 指定软件顶点运算方法
(4)D3DUSAGE_WRITEONLY 只写FVF:存储在顶点缓冲的灵活顶点格式,参考宏定义
Pool:容纳缓存的内存池
ppVertexBuffer:用于接收所创建的顶点缓存的指针
pSharedHandle:不使用,设为0
//例子 IDirect3DVertexBuffer9* vb; device->CreateVertexBuffer( 8*sizeof(Vertex), 0, D3DFVF_XYZ, D3DPOOL_MANAGED, &vb, 0);
2.Lock/Unlock
HRESULT IDirect3DVertexBuffer9::Lock(
UINT offsetToLock,
UINT SizeToLock,
BYTE** ppbData,
DWORD Flags
);OffsetToLock:自缓存的起始点到开始锁定的位置的偏移量,单位为字节
SizeToLock:所要锁定的字节数.
如果OffsetToLock和SizeToLock都为0表示锁定整个缓存
//顶点缓存 IDirect3DVertexBuffer9* Triangle=0; //访问顶点缓存内存 Vertex* vertices; Triangle->Lock(0,0,(void**)&vertices,0); ... Triangle->Unlock();
3.示例
//顶点缓存 IDirect3DVertexBuffer9* Triangle=0; void Cleaup(){ d3d::Release<IDirect3DVertexBuffer9*>(VB); } bool Setup{ //用D3D设备类来创建顶点缓存内存 Device->CreateVertexBuffer( 3*sizeof(Vertex), D3DUSAGE_WRITEONLY, Vertex::FVF, D3DPOOL_MANAGED, &Triangle, 0); //访问顶点缓存内存 Vertex* vertices; Triangle->Lock(0,0,(void**)&vertices,0); vertices[0]=Vertex(-1.0f,0.0f,2.0f); vertices[1]=Vertex(0.0f,1.0f,2.0f); vertices[2]=Vertex(1.0f,0.0f,2.0f); Triangle->Unlock(); } bool Display(float timeDelta){ Device->SetStreamSource(0,VB,0,sizeof(Vertex)); }
四.索引缓存
一个索引缓存是一个包含索引数据的连续内存空间,存放于显存之中,比内存快
构建一个3D物体的所有三角形单元中会共享许多公共顶点,为了解决重合顶点问题,用顶点列表(vertex list)和索引列表(index list)来记录坐标(决定顶点应以何种组合方式构成网格的三角形单元)
假设不用索引来表示一个正方形,Vectex v[6]={v0,v1,v2,v1,v2,v3},需要六个顶点坐标
加入索引之后,Vertect v[4]={v0,v1,v2,v3} WORD indexList[6]={0,1,2,1,2,3}; 只需要记录四个顶点坐标
因为索引坐标只是一个整数,用来获取顶点坐标的第几个,所以比三维坐标的Vertex更省内存
1.创建索引缓存
HRESULT IDirect3DDevice9::CreateIndexBuffer( UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9** ppIndexBuffer, HANDLE* pSharedHandle); Length:为缓存分配的字节数,8个顶点需要8*sizeof(Vertex) Usage:附加属性 (1)D3DUSAGE_DYNAMIC 将缓存设为动态缓存 (2)D3DUSAGE_POINTS 规定缓存将用于存储点图元 (3)D3DUSAGE_SOFTWAREPROCESSING 指定软件顶点运算方法 (4)D3DUSAGE_WRITEONLY 只写 Format:指定索引的大小 (1)D3DFMT_INDEX16 表示16位索引 (2)D3DFMT_INDEX32 表示32位索引 Pool:容纳缓存的内存池 ppIndexBuffer:用于接收所创建的索引缓存的指针 pSharedHandle:不使用,设为0
IDirect3DIndexBuffer9* ib; device->CreateIndexBuffer( 36*sizeof(WORD), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ib, 0);
2.访问索引缓存
HRESULT IDirect3DIndexBuffer9::Lock( UINT OffsetToLock, UINT SizeToLock, BYTE** ppbData, DWORD Flags );
3.示例
//索引缓存 IDirect3DIndexBuffer9* IB=0; bool Setup(){ //用D3D设备类来创建索引缓存 Device->CreateIndexBuffer( 36*sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &IB, 0); //访问索引缓存 WORD* Iindices=0; IB->LOCK(0,0,(void**)&indices,0); indices[0]=0;indices[1]=1;indices[2]=2; indices[3] = 0; indices[4] = 2; indices[5] = 3; // back side indices[6] = 4; indices[7] = 6; indices[8] = 5; indices[9] = 4; indices[10] = 7; indices[11] = 6; // left side indices[12] = 4; indices[13] = 5; indices[14] = 1; indices[15] = 4; indices[16] = 1; indices[17] = 0; // right side indices[18] = 3; indices[19] = 2; indices[20] = 6; indices[21] = 3; indices[22] = 6; indices[23] = 7; // top indices[24] = 1; indices[25] = 5; indices[26] = 6; indices[27] = 1; indices[28] = 6; indices[29] = 2; // bottom indices[30] = 4; indices[31] = 0; indices[32] = 3; indices[33] = 4; indices[34] = 3; indices[35] = 7; IB->Unlock(); } void Cleanup(){ d3d::Release<IDirect3DIndexBuffer9*>(IB); } bool Display(float timeDelta){ //绑定模型的索引缓存 Device->SetIndices(IB); }
五.网格
1.网格简介
一个网格由一个或多个子集组成,一个子集(subsets)是网格中一组可用相同属性(材质/纹理/绘制状态)进行绘制的三角形单元
假设一个房子是网格,那么地板/墙/天花板/窗口各有自己的属性,都能用来绘制房子网格
为了区分不同的子集,给每个子集指定一个唯一的非负整数值,该值为DWORD类型所能容纳任何非负整数
网格中的每个三角形单元都被赋予了一个属性ID,该ID指定了该三角形单元所属的子集,这些三角形单元的属性ID被存储在网格的属性缓存(Attribute Buffer)中,该属性缓存实际上就是一个DWORD类型的数组.
由于每个面片(三角形)在属性缓存中都有对应项,所以属性缓存中元素的个数与网格中面皮的个数相等.
2.网格类(ID3DXMesh)的方法
HRESULT ID3DMesh::GetVertexBuffer(LPDIRECT3DVERTEXBUFFER9* ppVB)
HRESULT ID3DMesh::GetIndexBuffer(LPDIRECT3DVERTEXBUFFER9* ppIB)
DWORD GetFVF()
DWORD GetNumVertices()
DWORD GetNumBytesPerVertex()
DWORD GetNumFaces()LockAttributeBuffer()
LockIndexBuffer()
LockVertexBuffer()
UnlockAttributeBuffer()
UnlockIndexBuffer()
UnlockVertexBuffer()
CloneMesh()
CloneMeshFVF()
DrawSubset(DWORD AttribID) //用于绘制由参数AttribId指定的子集中的三角形单元 //例子 Mesh->DrawSubset(0); //绘制子集0中的所有三角形单元 for(int i=0;i<numSubsets;i++){ Device->SetMaterial(mtrls[i]); Device->SetTexture(0,textures[i]); Mesh->DrawSubset(i); }
3.D3D支持网格(ID3DXMESH)的方法
HRESULT WINAPI D3DXCreateMeshFVF(
DWORD NumFaces, //网格所具有的面皮个数
DWORD NumVertices, //网格所具有的顶点个数
DWORD Options, //创建网格时所使用的创建标记
DWORD FVF, // 顶点的灵活格式
LPDIRECT3DDEVICE9 pDevice, // 与网格相关的设备指针
LPD3DXMESH* ppMesh // 所创建的网格对象的指针
);
D3DXCreateMesh() //创建空网格
//绘制内置的网格模型
D3DXCreateTeapot() //茶壶
D3DXCreateBox() //正方体
D3DXCreateCylinder()
D3DXCreateTorus()
D3DXCreateSphere()
D3DXCreaetPolygon()
//多个模型一起绘制 ID3DXMesh* Objects[5] = {0, 0, 0, 0, 0}; // World matrices for each object. These matrices // specify the locations of the objects in the world. D3DXMATRIX ObjWorldMatrices[5]; // // Framework Functions // bool Setup() { // //茶壶模型 // D3DXCreateTeapot( Device, &Objects[0], 0); // //立方体 // D3DXCreateBox( Device, 2.0f, // width 2.0f, // height 2.0f, // depth &Objects[1], 0); // //柱体 // D3DXCreateCylinder( Device, 1.0f, // radius at negative z end 1.0f, // radius at positive z end 3.0f, // length of cylinder 10, // slices 10, // stacks &Objects[2], 0); // //圆环体 // D3DXCreateTorus( Device, 1.0f, // inner radius 3.0f, // outer radius 10, // sides 10, // rings &Objects[3], 0); // //球面体 // D3DXCreateSphere( Device, 1.0f, // radius 10, // slices 10, // stacks &Objects[4], 0); // //多边形 //D3DXCreatePolygon() D3DXMatrixTranslation(&ObjWorldMatrices[0], 0.0f, 0.0f, 0.0f); D3DXMatrixTranslation(&ObjWorldMatrices[1], -5.0f, 0.0f, 5.0f); D3DXMatrixTranslation(&ObjWorldMatrices[2], 5.0f, 0.0f, 5.0f); D3DXMatrixTranslation(&ObjWorldMatrices[3], -5.0f, 0.0f, -5.0f); D3DXMatrixTranslation(&ObjWorldMatrices[4], 5.0f, 0.0f, -5.0f); // // Set the 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); // // Switch to wireframe mode. // Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); return true; } void Cleanup() { for(int i = 0; i < 5; i++) d3d::Release<ID3DXMesh*>(Objects[i]); } bool Display(float timeDelta) { if( Device ) { // Animate the camera: // The camera will circle around the center of the scene. We use the // sin and cos functions to generate points on the circle, then scale them // by 10 to further the radius. In addition the camera will move up and down // as it circles about the scene. static float angle = (3.0f * D3DX_PI) / 2.0f; static float cameraHeight = 0.0f; static float cameraHeightDirection = 5.0f; D3DXVECTOR3 position( cosf(angle) * 10.0f, cameraHeight, sinf(angle) * 10.0f ); // the camera is targetted at the origin of the world D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); // the worlds up vector D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH(&V, &position, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); // compute the position for the next frame angle += timeDelta; if( angle >= 6.28f ) angle = 0.0f; // compute the height of the camera for the next frame cameraHeight += cameraHeightDirection * timeDelta; if( cameraHeight >= 10.0f ) cameraHeightDirection = -5.0f; if( cameraHeight <= -10.0f ) cameraHeightDirection = 5.0f; // // Draw the Scene: // Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); for(int i = 0; i < 5; i++) { // Set the world matrix that positions the object. Device->SetTransform(D3DTS_WORLD, &ObjWorldMatrices[i]); // Draw the object using the previously set world matrix. Objects[i]->DrawSubset(0); } Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; }