一.简介
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;
}