龙书笔记(10)

chap 10 网格(前篇)


以前是通过D3DXCreate*(比如茶壶、圆柱体什么的)函数了解一些ID3DXMesh接口,
其实 ID3DXMesh 继承了其父类 ID3DXBaseMesh 的大部分功能,还有一些也继承自 ID3DXBaseMesh 的网格类,
比如 ID3DXPMesh(渐进网格)也拥有ID3DXBaseMesh的很多功能

1.几何信息
ID3DXBaseMesh接口包含一个顶点缓存和一个索引缓存
		//eg:
			IDirect3DVertexBuffer9 *vb = 0;
			Mesh->GetVertexBuffer( &vb );

			IDirect3DIndexBuffer9 *ib = 0;
			Mesh->GetIndexBuffer( &ib );

如果想锁定缓存并且对他们进行读写操作,操作的方式类似Lock,但只有2个参数Lock是4个

		HRESULT ID3DXMesh::LockVertexBuffer( DWORD Flags, BYTE** ppData );
		HRESULT ID3DXMesh::LockIndexBuffer( DWORD Flags, BYTE** ppData );
		//注意,锁定的是整个顶点缓存或者索引缓存

Unlock也与此相仿
		HRESULT ID3DXMesh::UnLockVertexBuffer();
		HRESULT ID3DXMesh::UnLockIndexBuffer();

除了以上的方法外,ID3DXMesh还提供了获取集合信息了一些其他很实用的方法:
		DWORD GetFVF();					//返回一个描述了顶点格式的值
		DWORD GetNumVertices();			//返回顶点缓存中的顶点个数
		DWORD GetNumBytesPerVertex();	//返回每个顶点所占的字节数
		DWORD GetNumFaces();			//返回网格中(三角形)面片的个数


2.子集和缓存属性
(1)一个网格由一个或多个 子集 组成, 一个子集是网格中一组可用 相同属性(材质、纹理、绘制状态)进行绘制的 三角形单元
(2)用来区分不同子集的办法是为每个子集都定义一个非负整数值,比如0,1,2...
(3)网格中为每个三角形单元赋予了 ID, 他代表该三角形单元所属的子集
(4)这些ID被存放在网格的 属性缓存 中,所以属性缓存的数目就等于三角形单元的数目
这四个概念一定要理解透彻!
访问属性缓存:
		DWORD * buffer = 0;
		Mesh->LockAttributeBuffer(lockingFlags, &buffer);
		//读写操作...
		Mesh->UnlockAttributeBuffer();


3.绘制
ID3DXMesh提供了DrawSubset(DWORD AttribID)来绘制由AttribID指定子集中的三角形单元组
		//eg:		
			Mesh->DrawSubset(0);			//绘制子集0中所有三角形单元组
		//eg:
			for(int i; i<numSubsets; i++)				//绘制整个网格
			{
				Device->SetMaterial( mtrl[i] );			//这个子集里面的三角形们使用的纹理
				Device->SetTexture( 0, textures[i] );	//这个子集里面的三角形们使用的材质
				Mesh->DrawSubset(i);					//绘制这个子集
			}

4.网格优化(Optimize)
就是重组该网格中的 顶点和索引缓存
在ID3DXMesh中有对应的方法:
		ID3DXMesh::OptimizeInplace(			
			DWORD Flags,					//优化标记: D3DXMESHOPT_COMPACT "D3DXMESHOPT_ATTSORT"(重点!他依据属性对三角单元排序) D3DXMESHOPT_VERTEXCACHE...
			CONST DWORD *pAdjacencyIn,		//指向未经优化的网格的邻接数组的指针
			DWORD *pAjacencyOut,			//经网格优化后的邻接信息,ID3DXMesh::GetNumFaces() * 3 或者 0
			DWORD *PFaceRemap				//ID3DXMesh::GetNumFaces() 或者 0 
			LPD3DXBUFFER *ppVertexRemap		//ID3DXMesh::GetNumVertices() 或者 0
		);
		//eg:
		DWORD adjacencyInfo[Mesh->GetNumFaces()*3];
		Mesh->GenerateAdjacency( 0.0f, adjacencyInfo );
				
		DWORD optimizeAdjacencyInfo[Mesh->GetNumFaces()*3];
				
		Mesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_COMPACT|D3DXMESHOPT_VERTEXCACHE,
					adjacencyInfo,
					optimizeAdjacencyInfo,
					0,0 );

若使用这个方法,则原网格会被修改,但可以使用 Optimize 方法,他输出优化后的版本,原版本不变


5.属性表
如果一个网格在优化时使用了D3DXMESHOPT_ATTSORT,则构成该网格的三角形面片 和 属性缓存中的内容 就会依据属性进行排序
(使属于同一子集的三角元被保存在 顶点缓存 或 索引缓存 连续的存储空间内)
除了排序外,这种优化还将创建一个属性表, 该属性表是一个 D3DXATTRIBUTERANGE 类型的数组结构
属性表中的每一项对应于网格的一个子集,并指定该子集中面片的几何信息被存储的位置


访问属性表:
		ID3DXMesh::GetAttributeTable(
			D3DXATTRIBUTERANGE *pAttribTable,
			DWORD *pAttribTableSize
		);

		//获取属性表中的属性集的个数
		DWORD numSubsets = 0;
		Mesh->GetAttributeTable(0, &numSubsets);
		//D3DXATTRIBUTERANGE对象可以存储 属性集,所以有多个属性集的话,可以通过创建这个对象的数组(或者用vector)来存储这些属性集
		D3DXATTRIBUTERANGE table = new D3DXATTRIBUTERANGE[numSubsets];
		Mesh->GetAttributeTable( table, &numSubsets );


6.邻接信息
		//eg:
		//获取网格的邻接信息
			DWORD adjacencyInfo[Mesh->GetNumFaces() * 3];
			Mesh->GenerateAdjacency(0.001f, adjacencyInfo);

7.克隆
有时需要创建网格数据的副本
		//eg:
		ID3DXMesh *clone = 0;
		Mesh->CloneMeshFVF(
			Mesh->GetOptions(),
			D3DFVF_XYZ | D3DFVF_NORMAL,
			Device,
			&clone
		);

8.创建网格 (D3DXCreateMeshFVF)
创建“空”网格对象
		//指定网格的 面片数和顶点数, 然后为顶点缓存、索引缓存和属性缓存分配大小合适的内存,最后手工填入网格的数据		
		HRESULT WINAPI D3DXCreateMeshFVF(
			DWORD NumFaces,
			DWORD NumVertices,
			DWORD Options,				//D3DXMESH_MANAGED D3DXMESH_WRITEONLY D3DXMESH_DYNAMIC...
			DWORD FVF,
			LPDIRECT3DDEVICE9 pDevice,
			LPD3DXMESH *ppMesh
		);

另一个创建“空”网格对象的方法:D3DXCreateMesh,这个办法用到了顶点声明ID3DVERTEXELEMENT9,关于顶点声明会在hlsl里说到

9.实例
(1)创建空网格
(2)将立方体的面片数和顶点数写入网格缓存
(3)指定网格中每个面片所属的子集 //这就是填写属性缓存,记住一点:属性缓存用来存放每个面片所属的子集
(4)生成该网格的邻接信息 //优化网格的准备工作
(5)优化网格
(6)绘制网格

1.Setup部分:
		//初始化用到的内容
		ID3DXMesh*         Mesh = 0;
		const DWORD        NumSubsets = 3;
		IDirect3DTexture9* Textures[3] = {0, 0, 0};
		//创建空网格
			hr = D3DXCreateMeshFVF(
				12,					//12个面片
				24,					//24个顶点
				D3DXMESH_MANAGED,
				Vertex::FVF,
				Device,
				&Mesh);			
		//填写顶点缓存
			Vertex* v = 0;
			Mesh->LockVertexBuffer(0, (void**)&v);
			v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
			//...
			Mesh->UnlockVertexBuffer();
		//填写索引缓存
			WORD* i = 0;
			Mesh->LockIndexBuffer(0, (void**)&i);
			i[0] = 0; i[1] = 1; i[2] = 2;	
			//...
			Mesh->UnlockIndexBuffer();
		//填写属性缓存 (属性缓存的总数等于三角形单元的总数)
			DWORD* attributeBuffer = 0;
			Mesh->LockAttributeBuffer(0, &attributeBuffer);
			for(int a = 0; a < 4; a++)
				attributeBuffer[a] = 0;
			//...
			Mesh->UnlockAttributeBuffer();
		//网格优化,先要计算邻接信息
			std::Vector<DWORD> ajacencyBuffer(Mesh->GetNumFaces() * 3);
			Mesh->GenerateAdjacency(0.0f, &adjacencyBuffer[0] );
					
			hr = Mesh->OptimizeInplace(
				D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE,
				&adjacencyBuffer[0],
				0,0,0
			);
		//读入纹理文件,关闭光照,设置 观察矩阵 和 投影矩阵


2.Display部分

旋转矩阵部分略过..

		for(int i=0; i<NumSubsets; i++)
		{
			Device->SetTexture(0, Texture[i]);
			Mesh->DrawSubset( i );
		}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值