yzwalkman

——用数绘画

导航

Ogre源代码浅析——Mesh文件结构及加载(二)

    Ogre中的Mesh类对应着渲染所需的模型网格,其数据来自于Mesh文件。调用SceneManager::createEntity()时,Ogre会自动创建Mesh类对象,并从指定的Mesh文件中读取相应模型数据。createEntity()将形成以下call stack。

 1 SceneManager::createEntity()
 2                 ||
 3                 \/
 4 
 5               ... ...
 6 
 7                 ||
 8                 \/
 9 MeshManager::load()
10                 ||
11                 \/
12 Resource::load()
13                 ||
14                 \/
15 Mesh::loadImpl()

    其中,Mesh::loadImpl()函数展开后为:

 1     void Mesh::loadImpl()
 2     {
 3         MeshSerializer serializer;
 4         serializer.setListener(MeshManager::getSingleton().getListener());
 5 
 6         // If the only copy is local on the stack, it will be cleaned
 7         // up reliably in case of exceptions, etc
 8         DataStreamPtr data(mFreshFromDisk);
 9         mFreshFromDisk.setNull();
10 
11         if (data.isNull()) {
12             OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
13                         "Data doesn't appear to have been prepared in " + mName,
14                         "Mesh::loadImpl()");
15         }
16 
17         serializer.importMesh(data, this);
18 
19         /* check all submeshes to see if their materials should be
20            updated.  If the submesh has texture aliases that match those
21            found in the current material then a new material is created using
22            the textures from the submesh.
23         */
24         updateMaterialForAllSubMeshes();
25     }

     Ogre将以二进制方式保存的外部数据描述为数据流,并以串行的方式逐字节读取数据流中数据。为此,Ogre专门引入了DataStream类和Serializer类,DataStream类对应着数据流概念,Serializer类对应着串行器。不同性质的数据流需要通过不同的串行器来帮助读取,MeshSerializer作为Serializer的派生类,主要用来读取Mesh文件中的数据。MeshSerializer是对网格数据流串行器的抽象,其作用在第一段代码17行中体现,17行代码展开为:

 1     void MeshSerializer::importMesh(DataStreamPtr& stream, Mesh* pDest)
 2     {
 3         determineEndianness(stream);
 4 
 5         // Read header and determine the version
 6         unsigned short headerID;
 7         
 8         // Read header ID
 9         readShorts(stream, &headerID, 1);
10         
11         if (headerID != HEADER_CHUNK_ID)
12         {
13             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "File header not found",
14                 "MeshSerializer::importMesh");
15         }
16         // Read version
17         String ver = readString(stream);
18         // Jump back to start
19         stream->seek(0);
20 
21         // Find the implementation to use
22         MeshSerializerImpl* impl = 0;
23         for (MeshVersionDataList::iterator i = mVersionData.begin(); 
24              i != mVersionData.end(); ++i)
25         {
26             if ((*i)->versionString == ver)
27             {
28                 impl = (*i)->impl;
29                 break;
30             }
31         }            
32         if (!impl)
33             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Cannot find serializer implementation for "
34                         "mesh version " + ver, "MeshSerializer::importMesh");
35         
36         // Call implementation
37         impl->importMesh(stream, pDest, mListener);
38         // Warn on old version of mesh
39         if (ver != mVersionData[0]->versionString)
40         {
41             LogManager::getSingleton().logMessage("WARNING: " + pDest->getName() + 
42                 " is an older format (" + ver + "); you should upgrade it as soon as possible" +
43                 " using the OgreMeshUpgrade tool.");
44         }
45 
46     }

      由于不同版本的的Mesh文件有不同的格式(参见:http://www.cnblogs.com/yzwalkman/archive/2013/02/20/2916953.html Ogre源代码浅析——Mesh文件结构及加载(一)),Ogre又以Serializer为基类派生出了MeshSerializerImpl、MeshSerializerImpl_v1_41、MeshSerializerImpl_v1_4、MeshSerializerImpl_v1_3、MeshSerializerImpl_v1_2等类,根据网格数据流进行读取和解析的具体工作是由MeshSerializerImpl及其派生类对象来完成的。在第二段代码的MeshSerializer::importMesh()函数中,Ogre首先会根据网格文件的版本号找到相应的Mesh串行器(23-31行),然后再用具体的MeshSerializerImpl类对象进行网格数据的实际导入(37行)。

 

posted on 2013-02-21 14:34  yzwalkman  阅读(2818)  评论(0编辑  收藏  举报