Direct3D学习手记十:网格一【手动创建网格】
2013-12-30 11:23
253 查看
本文介绍网格技术并手动创建一个立方体网格
网格模型:
网格模型是一种将物体的顶点数据、材质信息、纹理信息存储在一个外部文件中的3D物体模型。网格接口:
网格接口有ID3DXMesh和ID3DPMesh(渐进网格),这两个接口都继承自ID3DBaseMesh接口创建空白网格:
HRESULT D3DXCreateMeshFVF( DWORD NumFaces, DWORD NumVertices, DWORD Options,DWORD FVF, LPDIRECT3DDEVICE9 pD3DDevice, LPD3DXMESH * ppMesh);NumFaces为网格的三角形面片数,此次我们绘制一个立方体,就有12个三角形面片
NumVertices为网格的顶点数,此次为24个
Options为创建标志,包括D3DXMESH_32BIT表示使用32位的索引,还有D3DXMESH_MANAGED等等
FVF为顶点格式,此次我们只使用了D3DFVF_XYZ和D3DFVF_TEX1
pD3DDevice为设备指针
ppMesh用于存储创建的空白网格
例如:
hr=D3DXCreateMeshFVF(12,//三角形图元个数
24,//顶点个数,这里因为使用了纹理坐标,所以顶点个数不是8而是24
D3DXMESH_MANAGED,//创建标记
VERTEX::FVF,//灵活顶点格式
g_pd3dDevice,//设备指针
&g_pBoxMesh);//存储网格对象的指针
网格的几何信息:
网格的几何信息包括顶点数据和索引数据,网格创建完成后就可以通过以下函数分别得到网格的顶点缓存和索引缓存:
HRESULT GetVertexBuffer( LPDIRECT3DVERTEXBUFFER9 * ppVB);
HRESULT GetIndexBuffer( LPDIRECT3DINDEXBUFFER9 * ppIB);
得到顶点缓存和索引缓存指针后,就可以直接读写其中的数据,可以使用如下函数对其加、解锁:
HRESULT LockVertexBuffer( DWORD Flags, LPVOID * ppData);
HRESULT LockIndexBuffer( DWORD Flags, LPVOID * ppData);
HRESULT UnlockVertexBuffer();
HRESULT UnlockIndexBuffer();在加锁和解锁之间就可以直接向缓存中写入顶点数据和索引数据,例如:
写顶点数据:
//Step 2:填充顶点数据
VERTEX * pVertexBuf=NULL;
if(SUCCEEDED(g_pBoxMesh->LockVertexBuffer(0,(LPVOID *)&pVertexBuf)))
{
//上面
pVertexBuf[0]=VERTEX(-1.0f,1.0f,1.0f,0.0f,0.0f);
pVertexBuf[1]=VERTEX(1.0f,1.0f,1.0f,1.0f,0.0f);
pVertexBuf[2]=VERTEX(1.0f,1.0f,-1.0f,1.0f,1.0f);
pVertexBuf[3]=VERTEX(-1.0f,1.0f,-1.0f,0.0f,1.0f);
//下面
pVertexBuf[4]=VERTEX(-1.0f,-1.0f,-1.0f,0.0f,0.0f);
pVertexBuf[5]=VERTEX(1.0f,-1.0f,-1.0f,1.0f,0.0f);
pVertexBuf[6]=VERTEX(1.0f,-1.0f,1.0f,1.0f,1.0f);
pVertexBuf[7]=VERTEX(-1.0f,-1.0f,1.0f,0.0f,1.0f);
//左面
pVertexBuf[8]=VERTEX(-1.0f,1.0f,1.0f,0.0f,0.0f);
pVertexBuf[9]=VERTEX(-1.0f,1.0f,-1.0f,1.0f,0.0f);
pVertexBuf[10]=VERTEX(-1.0f,-1.0f,-1.0f,1.0f,1.0f);
pVertexBuf[11]=VERTEX(-1.0f,-1.0f,1.0f,0.0f,1.0f);
//右面
pVertexBuf[12]=VERTEX(1.0f,1.0f,-1.0f,0.0f,0.0f);
pVertexBuf[13]=VERTEX(1.0f,1.0f,1.0f,1.0f,0.0f);
pVertexBuf[14]=VERTEX(1.0f,-1.0f,1.0f,1.0f,1.0f);
pVertexBuf[15]=VERTEX(1.0f,-1.0f,-1.0f,0.0f,1.0f);
//前面
pVertexBuf[16]=VERTEX(-1.0f,1.0f,-1.0f,0.0f,0.0f);
pVertexBuf[17]=VERTEX(1.0f,1.0f,-1.0f,1.0f,0.0f);
pVertexBuf[18]=VERTEX(1.0f,-1.0f,-1.0f,1.0f,1.0f);
pVertexBuf[19]=VERTEX(-1.0f,-1.0f,-1.0f,0.0f,1.0f);
//后面
pVertexBuf[20]=VERTEX(1.0f,1.0f,1.0f,0.0f,0.0f);
pVertexBuf[21]=VERTEX(-1.0f,1.0f,1.0f,1.0f,0.0f);
pVertexBuf[22]=VERTEX(-1.0f,-1.0f,1.0f,1.0f,1.0f);
pVertexBuf[23]=VERTEX(1.0f,-1.0f,1.0f,0.0f,1.0f);
g_pBoxMesh->UnlockVertexBuffer();
}
写索引数据:
//Step 3:设置顶点索引
WORD * pIndexBuf=NULL;
if(SUCCEEDED(g_pBoxMesh->LockIndexBuffer(0,(LPVOID *)&pIndexBuf)))
{
//上面
pIndexBuf[0]=0,pIndexBuf[1]=1,pIndexBuf[2]=2;
pIndexBuf[3]=0,pIndexBuf[4]=2,pIndexBuf[5]=3;
//下面
pIndexBuf[6]=4,pIndexBuf[7]=5,pIndexBuf[8]=6;
pIndexBuf[9]=4,pIndexBuf[10]=6,pIndexBuf[11]=7;
//左面
pIndexBuf[12]=8,pIndexBuf[13]=9,pIndexBuf[14]=10;
pIndexBuf[15]=8,pIndexBuf[16]=10,pIndexBuf[17]=11;
//右面
pIndexBuf[18]=12,pIndexBuf[19]=13,pIndexBuf[20]=14;
pIndexBuf[21]=12,pIndexBuf[22]=14,pIndexBuf[23]=15;
//前面
pIndexBuf[24]=16,pIndexBuf[25]=17,pIndexBuf[26]=18;
pIndexBuf[27]=16,pIndexBuf[28]=18,pIndexBuf[29]=19;
//后面
pIndexBuf[30]=20,pIndexBuf[31]=21,pIndexBuf[32]=22;
pIndexBuf[33]=20,pIndexBuf[34]=22,pIndexBuf[35]=23;
g_pBoxMesh->UnlockIndexBuffer();
}
属性和子集:
网格有很多子集组成,一个子集是相同材质、纹理的众多三角形图元的集合。为了区分不同的子集,就为其指定所属子集的ID,即属性ID(DWORD类型),
存储属性ID的是属性缓存,其中保存了每个三角形图元的属性ID
和顶点缓存及索引缓存一样,也可以直接读写,
这里我们使立方体的一个面的两个三角形图元属于同一个子集,即属性ID相同,
例如,立方体的上面的两个三角形图元0和图元1,设置其属性ID为0,其他的类似,
程序中我使用如下方式为每个三角形图元赋予一个属性ID:
//Step 4:设置每个图元的属性,即所属于的子集,每个子集使用不同的材质
//使每个面的2个三角形图元属于同一个子集,即属性ID相同
DWORD * pAttrBuf=NULL;
if(SUCCEEDED(g_pBoxMesh->LockAttributeBuffer(0,&pAttrBuf)))
{
for(int i=0,j=0;i<TEXTURE_NUM;i++)
{
pAttrBuf[j++]=i;
pAttrBuf[j++]=i;
}
g_pBoxMesh->UnlockAttributeBuffer();
}
邻接信息:
在网格中每个三角形都会与其他三角形相邻,所以使用DWORD类型的数组保存网格三角形的邻接信息,可以使用如下方式得到:
std::vector<DWORD> vAdjBuf(g_pBoxMesh->GetNumFaces()*3);//存储邻接图元信息,每个图元最多有3个邻接图元
g_pBoxMesh->GenerateAdjacency(0.0f,&vAdjBuf[0]);//得到邻接信息
网格优化:
网格优化在使用网格时可有可无,但使用它可以提高绘制效率:g_pBoxMesh->OptimizeInplace(D3DXMESHOPT_COMPACT//优化标志,移除无用的顶点和索引
|D3DXMESHOPT_ATTRSORT//根据属性ID对三角形图元进行排序
|D3DXMESHOPT_VERTEXCACHE,//提高顶点高速缓存的命中率
&vAdjBuf[0],//指向尚未优化的网格的邻接数组的指针
NULL,//存储优化后的网格的邻接信息
NULL,
NULL);
加载纹理:
在使用网格时,可以为每个子集的图元设置纹理和材质(可以相同或不同),此次我们只使用了纹理,//加载纹理贴图
WCHAR file[MAX_PATH]={0};
for(int i=0;i<TEXTURE_NUM;i++)
{
swprintf(file,L"Demo_10_Media\\texture%d.bmp",i+1);
D3DXCreateTextureFromFileW(g_pd3dDevice,file,&g_pFaceTextures[i]);
}
绘制网格:
网格创建完成并且数据填写完成就可以绘制网格了,循环使用DrawSubnet绘制每个子集,并设置子集的纹理://绘制立方体网格
for(int i=0;i<TEXTURE_NUM;i++)
{
//设置纹理
g_pd3dDevice->SetTexture(0,g_pFaceTextures[i]);
//绘制子集i
g_pBoxMesh->DrawSubset(i);
}
Setup函数:
在函数Setup函数里完成了网格的创建与顶点数据的填写/****************************************************************
*函数名 : Setup
*功能 : 创建与初始化资源、缓存、变换等
*输入 : hWnd:窗口句柄
*输出 : 无
*返回值 : 成功:TRUE 失败:FALSE
****************************************************************/
BOOL Setup(HWND hWnd)
{
if(NULL==hWnd)
return FALSE;
//创建字体
//方式一
D3DXCreateFont(g_pd3dDevice,20,14,600,D3DX_DEFAULT,FALSE,DEFAULT_CHARSET,0,0,0,TEXT("微软雅黑"),&g_pHelpFont);
//方式二
D3DXFONT_DESC fd;
ZeroMemory(&fd,sizeof(D3DXFONT_DESC));
fd.Height=20;
fd.Width=14;
fd.Weight=600;
fd.MipLevels=D3DX_DEFAULT;
fd.Italic=TRUE;
fd.CharSet=DEFAULT_CHARSET;
fd.OutputPrecision=0;
fd.PitchAndFamily=0;
fd.Quality=0;
_tcscpy_s(fd.FaceName,TEXT("Times New Roman"));
D3DXCreateFontIndirect(g_pd3dDevice,&fd,&g_pTipFont);
//加载纹理贴图
WCHAR file[MAX_PATH]={0};
for(int i=0;i<TEXTURE_NUM;i++)
{
swprintf(file,L"Demo_10_Media\\texture%d.bmp",i+1);
D3DXCreateTextureFromFileW(g_pd3dDevice,file,&g_pFaceTextures[i]);
}
//手动创建立方体网格
HRESULT hr=E_FAIL;
//Step 1:创建网格
hr=D3DXCreateMeshFVF(12,//三角形图元个数
24,//顶点个数,这里因为使用了纹理坐标,所以顶点个数不是8而是24
D3DXMESH_MANAGED,//创建标记
VERTEX::FVF,//灵活顶点格式
g_pd3dDevice,//设备指针
&g_pBoxMesh);//存储网格对象的指针
if(FAILED(hr))
return FALSE;
//Step 2:填充顶点数据
VERTEX * pVertexBuf=NULL;
if(SUCCEEDED(g_pBoxMesh->LockVertexBuffer(0,(LPVOID *)&pVertexBuf)))
{
//上面
pVertexBuf[0]=VERTEX(-1.0f,1.0f,1.0f,0.0f,0.0f);
pVertexBuf[1]=VERTEX(1.0f,1.0f,1.0f,1.0f,0.0f);
pVertexBuf[2]=VERTEX(1.0f,1.0f,-1.0f,1.0f,1.0f);
pVertexBuf[3]=VERTEX(-1.0f,1.0f,-1.0f,0.0f,1.0f);
//下面
pVertexBuf[4]=VERTEX(-1.0f,-1.0f,-1.0f,0.0f,0.0f);
pVertexBuf[5]=VERTEX(1.0f,-1.0f,-1.0f,1.0f,0.0f);
pVertexBuf[6]=VERTEX(1.0f,-1.0f,1.0f,1.0f,1.0f);
pVertexBuf[7]=VERTEX(-1.0f,-1.0f,1.0f,0.0f,1.0f);
//左面
pVertexBuf[8]=VERTEX(-1.0f,1.0f,1.0f,0.0f,0.0f);
pVertexBuf[9]=VERTEX(-1.0f,1.0f,-1.0f,1.0f,0.0f);
pVertexBuf[10]=VERTEX(-1.0f,-1.0f,-1.0f,1.0f,1.0f);
pVertexBuf[11]=VERTEX(-1.0f,-1.0f,1.0f,0.0f,1.0f);
//右面
pVertexBuf[12]=VERTEX(1.0f,1.0f,-1.0f,0.0f,0.0f);
pVertexBuf[13]=VERTEX(1.0f,1.0f,1.0f,1.0f,0.0f);
pVertexBuf[14]=VERTEX(1.0f,-1.0f,1.0f,1.0f,1.0f);
pVertexBuf[15]=VERTEX(1.0f,-1.0f,-1.0f,0.0f,1.0f);
//前面
pVertexBuf[16]=VERTEX(-1.0f,1.0f,-1.0f,0.0f,0.0f);
pVertexBuf[17]=VERTEX(1.0f,1.0f,-1.0f,1.0f,0.0f);
pVertexBuf[18]=VERTEX(1.0f,-1.0f,-1.0f,1.0f,1.0f);
pVertexBuf[19]=VERTEX(-1.0f,-1.0f,-1.0f,0.0f,1.0f);
//后面
pVertexBuf[20]=VERTEX(1.0f,1.0f,1.0f,0.0f,0.0f);
pVertexBuf[21]=VERTEX(-1.0f,1.0f,1.0f,1.0f,0.0f);
pVertexBuf[22]=VERTEX(-1.0f,-1.0f,1.0f,1.0f,1.0f);
pVertexBuf[23]=VERTEX(1.0f,-1.0f,1.0f,0.0f,1.0f);
g_pBoxMesh->UnlockVertexBuffer();
}
//Step 3:设置顶点索引
WORD * pIndexBuf=NULL;
if(SUCCEEDED(g_pBoxMesh->LockIndexBuffer(0,(LPVOID *)&pIndexBuf)))
{
//上面
pIndexBuf[0]=0,pIndexBuf[1]=1,pIndexBuf[2]=2;
pIndexBuf[3]=0,pIndexBuf[4]=2,pIndexBuf[5]=3;
//下面
pIndexBuf[6]=4,pIndexBuf[7]=5,pIndexBuf[8]=6;
pIndexBuf[9]=4,pIndexBuf[10]=6,pIndexBuf[11]=7;
//左面
pIndexBuf[12]=8,pIndexBuf[13]=9,pIndexBuf[14]=10;
pIndexBuf[15]=8,pIndexBuf[16]=10,pIndexBuf[17]=11;
//右面
pIndexBuf[18]=12,pIndexBuf[19]=13,pIndexBuf[20]=14;
pIndexBuf[21]=12,pIndexBuf[22]=14,pIndexBuf[23]=15;
//前面
pIndexBuf[24]=16,pIndexBuf[25]=17,pIndexBuf[26]=18;
pIndexBuf[27]=16,pIndexBuf[28]=18,pIndexBuf[29]=19;
//后面
pIndexBuf[30]=20,pIndexBuf[31]=21,pIndexBuf[32]=22;
pIndexBuf[33]=20,pIndexBuf[34]=22,pIndexBuf[35]=23;
g_pBoxMesh->UnlockIndexBuffer();
}
//Step 4:设置每个图元的属性,即所属于的子集,每个子集使用不同的材质
//使每个面的2个三角形图元属于同一个子集,即属性ID相同
DWORD * pAttrBuf=NULL;
if(SUCCEEDED(g_pBoxMesh->LockAttributeBuffer(0,&pAttrBuf)))
{
for(int i=0,j=0;i<TEXTURE_NUM;i++)
{
pAttrBuf[j++]=i;
pAttrBuf[j++]=i;
}
g_pBoxMesh->UnlockAttributeBuffer();
}
//Step 5:对网格进行优化,可有可无
std::vector<DWORD> vAdjBuf(g_pBoxMesh->GetNumFaces()*3);//存储邻接图元信息,每个图元最多有3个邻接图元
g_pBoxMesh->GenerateAdjacency(0.0f,&vAdjBuf[0]);//得到邻接信息
g_pBoxMesh->OptimizeInplace(D3DXMESHOPT_COMPACT//优化标志,移除无用的顶点和索引
|D3DXMESHOPT_ATTRSORT//根据属性ID对三角形图元进行排序
|D3DXMESHOPT_VERTEXCACHE,//提高顶点高速缓存的命中率
&vAdjBuf[0],//指向尚未优化的网格的邻接数组的指针
NULL,//存储优化后的网格的邻接信息
NULL,
NULL);
//设置取景变换矩阵
D3DXMATRIX matView;
D3DXVECTOR3 vEye(0.0f,0.0f,-5.0f);
D3DXVECTOR3 vAt(0.0f,0.0f,0.0f);
D3DXVECTOR3 vUp(0.0f,1.0f,0.0f);
D3DXMatrixLookAtLH(&matView,&vEye,&vAt,&vUp);
g_pd3dDevice->SetTransform(D3DTS_VIEW,&matView);
//设置投影变换矩阵
D3DXMATRIX matProjection;
::D3DXMatrixPerspectiveFovLH(&matProjection,D3DX_PI/4.0F,(FLOAT)g_nWidth/(FLOAT)g_nHeight,1.0F,1000.0F);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION,&matProjection);
//关闭光照
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING,false);
//显示窗口
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
return TRUE;
}
程序运行结果:
源代码与工程文件下载地址:
百度网盘相关文章推荐
- Direct3D学习手记十一:网格二【从.x文件中加载网格】
- Linux驱动学习(3-设备节点-手动创建)
- Direct3D学习手记九:字体
- Direct3D学习手记四:光照、材质与顶点法向量
- ROS学习手记 - 7 创建ROS msg & srv
- Direct3D 9学习笔记(13)网格(Mesh)4
- 《项目管理利器Maven》学习(二):手动创建第一个Maven案例maven01
- 图形学 Direct3D中手动创建3D模型
- Direct3D学习手记三:绘制彩色3D物体
- DirectX 9.0c游戏开发手记之“龙书”第二版学习笔记之2: Chap4: Direct3D Initialization
- Gridsim学习笔记(1)--- Gridsim初始化与创建网格资源
- directX基础学习系列7 网格(自己创建)
- 手动创建活动之学习笔记
- Direct3D学习手记一:实现Direct3D程序框架
- Direct3D学习手记五:纹理映射
- ROS学习手记 - 1了解并安装ROS+创建ROS_Package
- Maven学习二:手动创建maven project并编译
- java编程思想学习笔记(6)--手动创建、编译、运行Java程序
- ADO.NET学习笔记——如何手动创建类型化DataSet对象