【Ogre引擎架构-第三讲】 Xml模型文件的网格数据化MeshSerializer(一)

前端之家收集整理的这篇文章主要介绍了【Ogre引擎架构-第三讲】 Xml模型文件的网格数据化MeshSerializer(一)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

经过前面两讲的内容,读者可以做到的是将.mesh文件转变为.xml文件,可以用浏览器打开查看其内容树结构,通过OgreXmlConverter的XmlDocument,XmlElement将.xml文件读取到Xml树结构中.XmlDocument继承自XmlNode,在这颗树里保存了我们的模型数据,获取数据只要调用XmlDocument::RootElement就可以递归整个树了,下面我们Ogre的类MeshSerializer就要粉末登场了,通过它你可以把XmlDocument里的数据转变到Mesh里,转变完成后,就可以通过渲染系统把他渲染出来了,当然内容比较庞大,还需要很多讲.

下面先来张示意图,作者自己写的Demo,完成显示后的效果



下面进入MeshSerializer:

通过结构图,可以看到,整个树的根是一个<mesh>节点,这个节点由<submeshes>和<skeletonlink>组成,<submeshes>由若干<submesh>组成,<submesh>内部是顶点数据面数据,骨骼数据。理解清楚结构,就容易理解Ogre的Mesh类,Mesh类内部有一个SubMesh类的vector<SubMesh*>用来存储Sinbad身体的每一部分,比如Eyes,Body等等。接下来,进入MeshSerializer::Import

void MeshSerializer::Import(const char* filename,Mesh* pMesh)
	{
	//submeshes 读取Submeshes
		const XmlElement* elem=rootElem->FirstChildElement("submeshes");
		if(elem)
			ReadSubMeshes(elem);
	}
	void MeshSerializer::ReadSubMeshes(const XmlElement* mElem)
	{
		for(const XmlElement* smElem=mElem->FirstChildElement();smElem;smElem=smElem->NextSiblingElement()){
			SubMesh* sm=m_pMesh->CreateSubMesh();
			//material
			const char* material=smElem->Attribute("material");
			if(material)
				sm->SetMaterialName(string(material));
			//usesharedvertices
			const char* useSharedVertices=smElem->Attribute("usesharedvertices");
			if(useSharedVertices)
				sm->m_bUseSharedVertices=StringConverter::ParseBool(useSharedVertices);
			//operation type
			bool bReadFaces=true;//判断是否需要读取面信息
			const char* operType=smElem->Attribute("operationtype");
			if(operType){
				if(!strcmp(operType,"triangle_list"))
					sm->m_OperationType=RenderOperation::OT_TRIANGLE_LIST;
			}

			//index bits 16 or 32
			bool bUse32bitIndex=false;
			const char* tmp=smElem->Attribute("use32bitindexes");
			if(tmp)
				bUse32bitIndex=StringConverter::ParseBool(tmp);

			//Faces
			if(bReadFaces){
				//判断一下面的数量是否正确
				int actualCount=0;
				const XmlElement* faces=smElem->FirstChildElement("faces");
				if(faces){
					for(const XmlElement* face=faces->FirstChildElement();face;face=face->NextSiblingElement())
						++actualCount;

					const char* claimCount=faces->Attribute("count");
					if(claimCount){
						int iClaimCount=StringConverter::ParseInt(claimCount);
						if(actualCount != iClaimCount){
							LogManager::GetSingleton().LogMessage("ReadSubMeshes faces actualCount!=iClaimCount");
							return ;
						}
					}
					//把数据存入索引数据块内
					if(actualCount>0){
						switch(sm->m_OperationType){
						case RenderOperation::OT_TRIANGLE_LIST:
							sm->m_pIndexData->m_IndexCount=3*actualCount;
							break;
						}
					}
				}
				//allocate space
				HardwareIndexBufferSharedPtr ptrIndexBuffer=HardwareBufferManager::GetSingleton().CreateIndexBuffer(
					bUse32bitIndex?HardwareIndexBuffer::IT_32BIT:HardwareIndexBuffer::IT_16BIT,sm->m_pIndexData->m_IndexCount,HardwareBuffer::HBU_DYNAMIC);

				sm->m_pIndexData->m_IndexBufferPtr=ptrIndexBuffer;
				//将索引数据装入已分配的内存
				unsigned int *pInt=0;
				unsigned short *pShort=0;

				if(bUse32bitIndex){
					pInt=static_cast<unsigned int*>(ptrIndexBuffer->Lock(HardwareBuffer::HBL_DISCARD));
				}else{
					pShort=static_cast<unsigned short*>(ptrIndexBuffer->Lock(HardwareBuffer::HBL_DISCARD));
				}

				for(const XmlElement* face=faces->FirstChildElement();face;face=face->NextSiblingElement()){
					if(bUse32bitIndex){
						*(pInt++)=StringConverter::ParseInt(face->Attribute("v1"));
						*(pInt++)=StringConverter::ParseInt(face->Attribute("v2"));
						*(pInt++)=StringConverter::ParseInt(face->Attribute("v3"));
					}else{
						*(pShort++)=StringConverter::ParseInt(face->Attribute("v1"));
						*(pShort++)=StringConverter::ParseInt(face->Attribute("v2"));
						*(pShort++)=StringConverter::ParseInt(face->Attribute("v3"));
					}
				}
				ptrIndexBuffer->Unlock();
			}
			//geometry
			if(!sm->m_bUseSharedVertices){
				const XmlElement* geoElem=smElem->FirstChildElement("geometry");
				if(geoElem)
					ReadGeometry(geoElem,sm->m_pVertexData);
			}
			//bone assignments
			const XmlElement* boneAssignElem = smElem->FirstChildElement("boneassignments");
			if(boneAssignElem)
				ReadBoneAssignments(boneAssignElem,sm);
		}
	}

可以看到,ReadSubmeshes里循环读取每一个SubMesh,读取顺序和上方的文件内容对应,faces,geometry(暂不考虑boneassignment),faces就是顶点索引数据,当然你必须熟练DirectX或者OpenGL,否则就不要学Ogre了,geometry就是顶点相关数据,法向量,纹理数据。可能现在你对上面的函数唯一感觉比较吃力的就是HardwareBuffer了,没关系,先理清读取流程,ReadBoneAssignments先不要去看,多看几遍ReadGeometry内部的实现,下一讲讲解HardwareBuffer的内容,敬请期待,作者新浪博客http://weibo.com/1012294255/profile?topnav=1&wvr=6

猜你在找的XML相关文章