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, ¶ms));//参数为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有了这些东西,就可以进入渲染了。下面就开始看渲染的过程。
- ogre 引擎 框架追踪 第五章 资源加载之实加载
- ogre 引擎 框架追踪 第三章 资源加载之虚加载
- ogre 引擎 框架追踪 第四章 资源加载之资源组初始化
- ogre 引擎 框架追踪 第七章 渲染流程之compositor
- OGRE加载资源文件框架
- ogre 引擎 框架追踪 第二章 初始化
- ogre 引擎 框架追踪 第六章 渲染流程
- Ogre的资源加载策略
- Ogre资源加载流程概述
- ogre 引擎 框架追踪 第一章 root的创建
- libgdx游戏引擎(六)之资源异步加载
- unity 资源加载框架设计
- unity 资源加载框架设计
- iOS开发APP瘦身之PDF图片资源加载框架
- 3D引擎多线程:资源异步加载
- 3D引擎多线程:资源异步加载
- 第六章 OGRE中场景管理器、资源加载、manualObject的使用
- 在Ogre中加载自己的资源包
- iOS日历视图 FSCalendar的使用
- Spring实现AOP的4种方式
- C#上传图片源码
- 『詩解』八方捷报随春至,在前尽忠又立功的动物
- SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax
- ogre 引擎 框架追踪 第五章 资源加载之实加载
- Spring入门学习之Spring MVC(part 2)
- mutating关键字的使用
- NGINX+php+mysql centos6.5配置
- 二、node (Express) Ejs Angular 移动端开发
- H5获取向下一个页面传值并接收参数
- js扩展Date对象 日期格式化
- 每日一题(13): poj1836
- 半年了设计的功力大涨