查看: 2878|回复: 10

场景的切换

[复制链接]

该用户从未签到

发表于 2009-6-22 16:06:50 | 显示全部楼层 |阅读模式
用开关节点添加两个场景节点,场景的切换是在节点回调中实现的,如果两个场景中分别只有一个小节点(譬如,程序自带的牛模型节点等)场景的切换时正常的,如果场景比较复杂点,场景的切换就会出错,好像是内存中的信息不够,对于这种情况大家有什么解决方案,谢谢了。

该用户从未签到

发表于 2009-6-22 19:38:43 | 显示全部楼层
您这里场景节点是什么?Switch节点跟场景复杂程度通常没有关系,不知是不是您的其他代码有问题所致

该用户从未签到

 楼主| 发表于 2009-6-23 08:41:38 | 显示全部楼层
switch的两个节点都是组节点,一个组节点有两个子节点,其中一个是读取google地图的节点,另外一个组节有六个子节点,其中一个分页数据库的地球。

该用户从未签到

 楼主| 发表于 2009-6-23 09:10:40 | 显示全部楼层
经查找是分页数据库的原因,当在系统正在加载分页数据库的时候,突然切换就会导致出错,对于这种情况有没有解决方案?

该用户从未签到

发表于 2009-6-23 16:40:25 | 显示全部楼层
我似乎没有见过这类情况。也许您可以设置父节点为DYNAMIC再看一下

该用户从未签到

发表于 2009-6-24 20:01:54 | 显示全部楼层
借贵宝地问一个相关的问题:
DatabasePager在updateSceneGraph中从场景移除过期节点和向场景添加已加载节点,而updateSceneGraph是在updateTraversal中即在仿真循环线程中调用的。
然而,如果是在DrawThreadPerContext等多线程模型下工作,那么场景的筛选和绘制可能是在相机线程和图形环境线程中进行的。
但updateSceneGraph在移除节点和向场景添加节点时,并没有相应的线程同步操作。
请问,这样是否会带来线程冲突?系统是怎么解决或考虑的?

该用户从未签到

发表于 2009-6-24 22:13:39 | 显示全部楼层
osg有严格的线程同步保证,updateSceneGraph中也有大量的同步和互斥锁操作,一般可以放心

该用户从未签到

发表于 2009-6-25 09:37:30 | 显示全部楼层
以下为osg2.8版本的代码,向场景合并新加载的节点
void DatabasePager::addLoadedDataToSceneGraph(const osg::FrameStamp &frameStamp)
{
    double timeStamp = frameStamp.getReferenceTime();
    int frameNumber = frameStamp.getFrameNumber();
    osg::Timer_t before = osg::Timer::instance()->tick();
    RequestQueue::RequestList localFileLoadedList;
    // get the data for the _dataToCompileList, leaving it empty via a std::vector<>.swap.
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeList->_requestMutex); //这里是与分页数据库线程的同步!
        localFileLoadedList.swap(_dataToMergeList->_requestList);
    }
        
    osg::Timer_t mid = osg::Timer::instance()->tick();
    // add the loaded data into the scene graph.
    for(RequestQueue::RequestList::iterator itr=localFileLoadedList.begin();   // 这个循环中真正把加载的节点合并入场景,似乎没有任何同步的代码,怎样保证与渲染线程的同步呢?
        itr!=localFileLoadedList.end();
        ++itr)
    {
        DatabaseRequest* databaseRequest = itr->get();
        // osg::notify(osg::NOTICE)<<"Merging "<<_frameNumber-(*itr)->_frameNumberLastRequest<<std::endl;
        
        if (osgDB::Registry::instance()->getSharedStateManager())
            osgDB::Registry::instance()->getSharedStateManager()->share(databaseRequest->_loadedModel.get());
        
        registerPagedLODs(databaseRequest->_loadedModel.get(), frameStamp.getFrameNumber());
        
        osg::ref_ptr<osg::Group> group = databaseRequest->_groupForAddingLoadedSubgraph.get();
        if (group.valid())
        {
            osg:agedLOD* plod = dynamic_cast<osg::PagedLOD*>(group.get());
            if (plod)
            {
                plod->setTimeStamp(plod->getNumChildren(), timeStamp);
                plod->setFrameNumber(plod->getNumChildren(), frameNumber);
                plod->getDatabaseRequest(plod->getNumChildren()) = 0;
            }
            else
            {
                osg::ProxyNode* proxyNode = dynamic_cast<osg::ProxyNode*>(group.get());
                if (proxyNode)
                {
                    proxyNode->getDatabaseRequest(proxyNode->getNumChildren()) = 0;
                }
            }
            group->addChild(databaseRequest->_loadedModel.get());  // 这里调用addChild把节点加入场景
            // osg::notify(osg::NOTICE)<<"merged subgraph"<<databaseRequest->_fileName<<" after "<<databaseRequest->_numOfRequests<<" requests and time="<<(timeStamp-databaseRequest->_timestampFirstRequest)*1000.0<<std::endl;
            double timeToMerge = timeStamp-databaseRequest->_timestampFirstRequest;
            if (timeToMerge<_minimumTimeToMergeTile) _minimumTimeToMergeTile = timeToMerge;
            if (timeToMerge>_maximumTimeToMergeTile) _maximumTimeToMergeTile = timeToMerge;
            _totalTimeToMergeTiles += timeToMerge;
            ++_numTilesMerges;
        }
               
        // reset the loadedModel pointer
        databaseRequest->_loadedModel = 0;
        // osg::notify(osg::NOTICE)<<"curr = "<<timeToMerge<<" min "<<getMinimumTimeToMergeTile()*1000.0<<" max = "<<getMaximumTimeToMergeTile()*1000.0<<" average = "<<getAverageTimToMergeTiles()*1000.0<<std::endl;
    }
    osg::Timer_t last = osg::Timer::instance()->tick();
    osg::notify(osg:EBUG_INFO)<<"Done DatabasePager::addLoadedDataToSceneGraph"<<
        osg::Timer::instance()->delta_m(before,mid)<<"ms,\t"<<
        osg::Timer::instance()->delta_m(mid,last)<<"ms"<<
        "  objects"<<localFileLoadedList.size()<<std::endl<<std::endl;
   
}

该用户从未签到

发表于 2009-6-25 10:43:22 | 显示全部楼层
osg在渲染时实际上已经不再使用场景树,而是换而使用渲染树(RenderStage,RenderLeaf)来完成OpenGL状态的切换和几何体的绘制。因此这个时候addChild是安全的,不会被使用到。

而场景树向渲染树的转换是在Cull过程中完成的;osg的各种线程模型都限制了更新过程与上一帧的裁减过程的交叠,因此它也是安全的。

该用户从未签到

发表于 2009-6-25 13:17:04 | 显示全部楼层
请问是渲染遍历(ViewerBase::renderingTraversals())中的这两个操作完成与多线程的筛选和绘制同步的吗?
if (_startRenderingBarrier.valid()) _startRenderingBarrier->block();
……
if (_endRenderingDispatchBarrier.valid()) _endRenderingDispatchBarrier->block();

那么,如果我要动态修改场景(向场景添加一个节点),是否在仿真循环中renderingTraversals以外的任意位置来做都可以呢?

[ 本帖最后由 indif 于 2009-6-25 13:19 编辑 ]

该用户从未签到

发表于 2009-6-25 14:14:37 | 显示全部楼层
这两行仅仅保证了CullDrawThreadPerContext线程模型下的同步,对于其他的情形则有其他的保证方式,可以参看《最长的一帧》,不过这段过程太过复杂,没那么容易阐述清楚
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表