ogre 引擎 框架追踪 第五章 资源加载之实加载

来源:互联网 发布:linux创建用户脚本 编辑:程序博客网 时间:2024/05/16 16:57

前一章 ogre 引擎 框架追踪 第四章 资源加载之资源组初始化

作为资源加载的第三期,进入ogre场景主体的真正的加载环节:创建场景。
当然该环节是先创建场景管理器。

mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "ExampleSMInstance");

root调用的SceneManagerEnumerator创建的,具体代码为

SceneManager* inst = 0;String name = instanceName;// Iterate backwards to find the matching factory registered lastfor(Factories::reverse_iterator i = mFactories.rbegin(); i != mFactories.rend(); ++i){    if ((*i)->getMetaData().sceneTypeMask & typeMask)    {        inst = (*i)->createInstance(name);//真正创建的代码        break;    }}// use default factory if noneif (!inst)    inst = mDefaultFactory.createInstance(name);//真正创建的代码/// assign rs if already configuredif (mCurrentRenderSystem)    inst->_setDestinationRenderSystem(mCurrentRenderSystem);        mInstances[inst->getName()] = inst;

场景管理器创建完后创建场景内物体。
创建场景里的某个物体的一句话:

Ogre::Entity *ent=mSceneMgr->createEntity("czEnt","c.mesh");//mSceneMgr为场景管理器,暂时

内部的调用的实际代码:

Entity* SceneManager::createEntity(                                   const String& entityName,                                   const String& meshName,                                   const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */){    // delegate to factory implementation    NameValuePairList params;    params["mesh"] = meshName;    params["resourceGroup"] = groupName;    return static_cast<Entity*>(        createMovableObject(entityName, EntityFactory::FACTORY_TYPE_NAME,             &params));//参数为entity名称、创建movableobject的类型}

再跟的核心代码:

MovableObjectFactory* factory =         Root::getSingleton().getMovableObjectFactory(typeName);//获取工厂MovableObject* newObj = factory->createInstance(name, this, params);

再跟:

MovableObject* MovableObjectFactory::createInstance(        const String& name, SceneManager* manager,         const NameValuePairList* params)    {        MovableObject* m = createInstanceImpl(name, params);//创建的核心        m->_notifyCreator(this);        m->_notifyManager(manager);        return m;    }

再进:

MeshPtr pMesh;if (params != 0){    String groupName = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME;    NameValuePairList::const_iterator ni;    ni = params->find("resourceGroup");    if (ni != params->end())    {        groupName = ni->second;    }    ni = params->find("mesh");    if (ni != params->end())    {        // Get mesh (load if required)        pMesh = MeshManager::getSingleton().load(            ni->second,            // autodetect group location            groupName );//核心的mesh加载    }}return OGRE_NEW Entity(name, pMesh);

下面就是真正的加载了

MeshPtr pMesh = createOrRetrieve(filename,groupName,false,0,0,vertexBufferUsage,indexBufferUsage,                 vertexBufferShadowed,indexBufferShadowed).first;//获取ResourcePtr,创建或返回获取,总之是获取到资源对象。pMesh->load();

resouce加载的过程:prepareImpl->preLoadImpl->loadImpl->postLoadImpl

(1)prepareImpl做的操作:openResource(打开资源文件,返回DataStreamPtr)

ResourceGroupManager::getSingleton().openResource(mName, mGroup, true, this);

mesh资源中包含了resoucegroup的名称、资源名称、archive等,通过这几个条件打开文件足够了。

//ResourceGroupManager中调用的打开 ResourceGroup* grp = getResourceGroup(groupName); //从文件中查找 //resourceIndexCaseSensitive中查找,一般资源组正确的话就会直接能找到。 //resourceIndexCaseInsensitive中查找 //locationList中查找 //再从mResourceGroupMap中的所有group中查找,因为在创建的时候没有写对group名,写的自己检测,所以会走很多弯路。到这儿肯定可以找到了就。找到后需要把资源的组设置一下。 resourceBeingLoaded->changeGroupOwnership(foundGrp->name);//换组 //换组之后再调用一次openResource//跟上就是获取到资源对应的archive并打开,返回DataStreamPtrDataStreamPtr stream = pArch->open(resourceName);

mesh中已经读取保存好DataStreamPtr的数据。然后就是把这数据解析成mesh的数据格式

(2)preLoadImpl //mesh的是空的

(3)loadImpl

mesh真正的创建之地。

 MeshSerializer serializer;        serializer.setListener(MeshManager::getSingleton().getListener());//mesh加载的监听,用作mesh加载的监听、进度条显示        DataStreamPtr data(mFreshFromDisk);//拿到刚才读取的文件数据        mFreshFromDisk.setNull();        serializer.importMesh(data, this);//最核心的mesh文件数据编程mesh的过程        updateMaterialForAllSubMeshes();

importMesh的跟进

determineEndianness(stream);// Read header and determine the versionunsigned short headerID;// Read header ID,读取头id,固定的 为4096readShorts(stream, &headerID, 1);if (headerID != HEADER_CHUNK_ID){//报错}// Read version,版本String ver = readString(stream);// Jump back to startstream->seek(0);// Find the implementation to useMeshSerializerImpl* impl = 0;for (MeshVersionDataList::iterator i = mVersionData.begin();         i != mVersionData.end(); ++i)//获取下支持的所有版本中是否有该版本。这东西是在创建MeshSerializer时创建的。{    if ((*i)->versionString == ver)    {        impl = (*i)->impl;        break;    }}           if (!impl) OGRE_EXCEPT; //报错// Call implementationimpl->importMesh(stream, pDest, mListener);//数据导入成mesh// Warn on old version of meshif (ver != mVersionData[0]->versionString){}

跟进导入 MeshSerializerImpl::importMesh->readMesh。读取之后,就获取到了真正的mesh

if (!stream->eof()){    unsigned short streamID = readChunk(stream);    while(!stream->eof() &&        (streamID == M_GEOMETRY ||            streamID == M_SUBMESH ||            streamID == M_MESH_SKELETON_LINK ||            streamID == M_MESH_BONE_ASSIGNMENT ||            streamID == M_MESH_LOD ||            streamID == M_MESH_BOUNDS ||            streamID == M_SUBMESH_NAME_TABLE ||            streamID == M_EDGE_LISTS ||            streamID == M_POSES ||            streamID == M_ANIMATIONS ||            streamID == M_TABLE_EXTREMES))    {        switch(streamID)        {        case M_GEOMETRY:            pMesh->sharedVertexData = OGRE_NEW VertexData();            try {                readGeometry(stream, pMesh, pMesh->sharedVertexData);//mesh的共享顶点buffer            }            catch (Exception& e)            {                if (e.getNumber() == Exception::ERR_ITEM_NOT_FOUND)                {                    // duff geometry data entry with 0 vertices                    OGRE_DELETE pMesh->sharedVertexData;                    pMesh->sharedVertexData = 0;                    // Skip this stream (pointer will have been returned to just after header)                    stream->skip(mCurrentstreamLen - MSTREAM_OVERHEAD_SIZE);                }                else                {                    throw;                }            }            break;        case M_SUBMESH://子mesh数据            readSubMesh(stream, pMesh, listener);            break;        case M_MESH_SKELETON_LINK://skeleton的链接信息            readSkeletonLink(stream, pMesh, listener);            break;        case M_MESH_BONE_ASSIGNMENT://骨骼信息            readMeshBoneAssignment(stream, pMesh);            break;        case M_MESH_LOD:            readMeshLodInfo(stream, pMesh);            break;        case M_MESH_BOUNDS://包围盒。读取并设置            readBoundsInfo(stream, pMesh);            break;        case M_SUBMESH_NAME_TABLE:            readSubMeshNameTable(stream, pMesh);            break;        case M_EDGE_LISTS:            readEdgeList(stream, pMesh);            break;        case M_POSES:            readPoses(stream, pMesh);            break;        case M_ANIMATIONS:            readAnimations(stream, pMesh);            break;        case M_TABLE_EXTREMES:            readExtremes(stream, pMesh);            break;        }        if (!stream->eof())        {            streamID = readChunk(stream);        }    }

可以看到在loadImpl这一步中,申请了好多内存用以缓存顶点信息、skeleton信息等所有mesh信息,所以内存飙升。但是如果加载过的mesh,在再创建entity时候就不会内存猛涨了。

(4)postLoadImpl
代码较简单,加载完之后就获取下mesh是否有edge信息,有的话用作以后基于edge的阴影效果。

// Prepare for shadow volumes?if (MeshManager::getSingleton().getPrepareAllMeshesForShadowVolumes())        {            if (mEdgeListsBuilt || mAutoBuildEdgeLists)            {                prepareForShadowVolume();            }            if (!mEdgeListsBuilt && mAutoBuildEdgeLists)            {                buildEdgeList();            }        }        // The loading process accesses lod usages directly, so        // transformation of user values must occur after loading is complete.        // Transform user lod values (starting at index 1, no need to transform base value)        for (MeshLodUsageList::iterator i = mMeshLodUsageList.begin(); i != mMeshLodUsageList.end(); ++i)            i->value = mLodStrategy->transformUserValue(i->userValue);

从加载过程看,ogre对于内存还是比较大方的,当然也是比较吝啬的。大方在在“虚加载”过程和资源初始化过程就把所有的文件与文件夹对应,先拿出来读取下,读取成功就算有,读取不成功就算没有,而且在初始化时把材质等已经创建好。吝啬在于mesh等不会提前一丁点给你创建,当然这样有个好处,对于单线程来说,这样很安全,渲染起来后就尽量不再新加载mesh。

终于ogre的初始化和场景创建完成。捣鼓下顺序root创建(各种manager也创建)->root初始化(渲染系统初始化、窗口创建)->资源虚加载(读取所有文件建立文件的archive关系)->资源初始化(脚本资源的解析)->场景创建(真正的资源加载)。当然最后一个场景创建中,本章并没有视口、相机的创建,留作渲染时再看吧。ogre有了这些东西,就可以进入渲染了。下面就开始看渲染的过程。
0 0
原创粉丝点击