Ogre PCZSceneManger学习笔记

Ogre PCZSceneManger学习笔记:


新加类:

(MovableObject)->PortalBase    视口(基类)
PortalBase->Portal        可见性判断
PortalBase->AntiPortal        遮挡判断
(SceneCtlAllocatedObject)->PCZone 分割区域(纯虚类)
PCZone->DefaultZone        默认实现
(SceneNode)->PCZSceneNode    PCZSceneManger的场景节点

场景创建方式:
Ogre::Root::createSceneManager("PCZSceneManager", "PCZSceneManager");
PCZSceneManager::createCamera();            //创建摄像机,创建完必须要attach到一个node上!创建灯光也要attach到一个node上
PCZSceneManager::createZone(const String& zoneType, const String& instanceName);        //创建Zone,最好带mesh做enclousre AABB,不然判断scenenode的归属时会有问题
     zoneType = "ZoneType_Default"  指向 DefaultZone
PCZSceneManager::createZoneFromFile(m_ZoneType, index, node, meshName);                //带mesh创建,不推荐,资源组不可选
DefaultZone::setEnclosureNode(node);        //直接设置包围节点,node里面要求东西,可以是个包围盒mesh,渲染时不会显示
     
PCZSceneManager::createPortal(const String& name, PortalBase::PORTAL_TYPE type = PortalBase::PORTAL_TYPE_QUAD);        创建portal
PCZSceneManager::createAntiPortal(const String& name, PortalBase::PORTAL_TYPE type = PortalBase::PORTAL_TYPE_QUAD);        创建AntiPortal
Portal::setNode(SceneNode* sn)            //设置节点绑定,这样portal可以跟着节点一起移动

PCZSceneManager::createSceneNode ( const String &name );
//把相应的sceneNode加入到Zone中,一个sceneNode只能有一个homeZone,但可以被多个PCZZone遍历(见mVisitorNodeList)
    PCZSceneManager::addPCZSceneNode(PCZSceneNode * sn, PCZone * homeZone);        
    {
        // set the home zone
        sn->setHomeZone(homeZone);            //如果sn原来的homeZone是另一个,则原来的homeZone会把sn从homeNodeList里删除
        // add the node
        homeZone->_addNode(sn);
    }
    或者 添加附加节点
    PCZSceneNode::addZoneToVisitingZonesMap(connectedZone);
  void DefaultZone::_addNode( PCZSceneNode * n )                                                
  {
        if (n->getHomeZone() == this)
        {
            // add a reference to this node in the "nodes at home in this zone" list
            mHomeNodeList.insert( n );
        }
        else
        {
            // add a reference to this node in the "nodes visiting this zone" list
            mVisitorNodeList.insert( n );
        }
  }
    
//PCZZone添加portal,一个portal只能有一个zone
PCZone::_addPortal(Portal * newPortal);    / _addAntiPortal(Portal * newPortal);         
void Portal::setTargetZone(PCZone* zone);            //设置对面的区域
void Portal::setTargetPortal(Portal* portal);    //设置对面区域相应的portal

渲染:
renderScene()
{
    void _updateSceneGraph( Camera * cam )
    {
        // First do the standard scene graph update
        SceneManager::_updateSceneGraph( cam );
        
        // check for portal zone-related changes (portals intersecting other portals)
        _updatePortalZoneData();                            //检测portal是否有更新,判断portal::needUpdate(),portal在重新setCorner(int index, const Vector3& point)会更新
        
        // mark nodes dirty base on portals that changed.
        _dirtyNodeByMovingPortals();                    //如果有portal变动,则标记里面所有的scenNode.setMoved(true)
        
        // update all scene nodes
        _updatePCZSceneNodes();                                //更新里面所有的scenNode,由上面引起
        {
            for each sceneNode:
                void PCZSceneManager::_updatePCZSceneNode( PCZSceneNode * pczsn )
                {
                // Skip if root Zone has been destroyed (shutdown conditions)
                if (!mDefaultZone)
                    return;
        
                    // Skip if the node is the sceneroot node
                    if (pczsn == getRootSceneNode())
                        return;
            
                    // clear all references to visiting zones
                    pczsn->clearNodeFromVisitedZones();                            //清除其他Zone里面visited标记
            
                    // Find the current home zone of the node associated with the pczsn entry.
                    //判断sceneNode是否还在原 homeZone里面,如果不在的话就重新寻找合适的homeZone
                    //注意:节点不要掉进DefaultZone,因为DefaultZone没有portal,所以永远出不去
                    _updateHomeZone( pczsn, false );                                
                    {
                        //807行
                        if (!pczsn->isAnchored())                //对于一般的节点是false,enclouse的节点初始化的是true
                    }
            
                    /* The following function does the following:
                    * 1) Check all portals in the home zone - if the node is touching the portal
                    *    then add the node to the connected zone as a visitor
                    * 2) Recurse into visited zones in case the node spans several zones
                    */
                    // (recursively) check each portal of home zone to see if the node is touching
                    if (pczsn->getHomeZone() &&
                            pczsn->allowedToVisit() == true)
                    {
                        pczsn->getHomeZone()->_checkNodeAgainstPortals(pczsn, 0);        //向邻近的zone添加VisitedNode标记(一般在sceneNode横跨portal的时候发生)
                    }
            
                    // update zone-specific data for the node for any zones that require it
                    pczsn->updateZoneData();
            }
        }
        
        // calculate zones affected by each light
        _calcZonesAffectedByLights(cam);            //更新光源
        
        // clear update flags at end so user triggered updated are
        // not cleared prematurely
        _clearAllZonesPortalUpdateFlag();
    }
    
    .....
    
    void _findVisibleObjects(Camera* cam, VisibleObjectsBoundsInfo* visibleBounds, bool onlyShadowCasters)
    {
        //为compositor优化的步骤参考1190行
        
        //摄像机剔除(核心)
        PCZone* cameraHomeZone = ((PCZSceneNode*)(cam->getParentSceneNode()))->getHomeZone();
        cameraHomeZone->findVisibleNodes((PCZCamera*)cam,
                                          mVisible,
                                          getRenderQueue(),
                                          visibleBounds,
                                          onlyShadowCasters,
                                          mDisplayNodes,
                                          mShowBoundingBoxes);
    }
}

//判断当前节点是否在本地Zone里面
PCZSceneManager::_updateHomeZone( PCZSceneNode * pczsn, bool allowBackTouches )    
{
        if (!mDefaultZone)
            return;

        PCZone * startzone;
        PCZone * newHomeZone;

        // start with current home zone of the node
        startzone = pczsn->getHomeZone();

        if (startzone)                                //如果当前sceneNode有 homeZone
        {
            if (!pczsn->isAnchored())                //一般节点
            {
                newHomeZone = startzone->updateNodeHomeZone(pczsn, false);            //此函数基于portal计算,如果没有portal的话,始终是自己
            }
            else                                                //包围盒
            {
                newHomeZone = startzone;
            }

            if (newHomeZone != startzone)
            {
                // add the node to the home zone
                newHomeZone->_addNode(pczsn);
            }
        }
        //当前没有homeZone,造成这个原因一般为 人为设置sceneNode的homeZone
        else                                
        {
            // the node hasn't had it's home zone set yet, so do our best to
            // find the home zone using volume testing.  
            Vector3 nodeCenter = pczsn->_getDerivedPosition();
            //查找最合适的zone,如果没有找到,则默认为defaultZone(此zone默认是不带pportal的),
            //就是说一旦设为defaultZone则再也出不去了,也不会显示(除非摄像机也在defaultZone)
            PCZone * bestZone = findZoneForPoint(nodeCenter);                    
            // set the best zone as the node's home zone
            pczsn->setHomeZone(bestZone);
            // add the node to the zone
            bestZone->_addNode(pczsn);
        }

        return;
}
结论:
在加载场景后分配一般sceneNode时,一定要避免放在defaultZone里面,scenNode在移动是不用担心位置跑到外面去;
摄像机节点初始也要设置在有效Zone里面,位置要对,且创建好后就setMoved(true)或者setHomeZone(a valid zone);

PCZSceneNode::createChildSceneNode(const Vector3& translate, const Quaternion& rotate)  创建的子节点会和父节点放在同一个Zone里面


startzone->updateNodeHomeZone(pczsn, false)机制
{
            // default to newHomeZone being the current home zone
        PCZone * newHomeZone = pczsn->getHomeZone();

        // Check all portals of the start zone for crossings!
        Portal* portal;
        PortalList::iterator pi, piend;
        piend = mPortals.end();
        for (pi = mPortals.begin(); pi != piend; pi++)
        {
            portal = *pi;

            Portal::PortalIntersectResult pir = portal->intersects(pczsn);
            switch (pir)
            {
            default:
            case Portal::NO_INTERSECT: // node does not intersect portal - do nothing
            case Portal::INTERSECT_NO_CROSS:// node intersects but does not cross portal - do nothing                //中心点没有穿过portal,即使中心点在portal外面也判定不相交
                break;
            case Portal::INTERSECT_BACK_NO_CROSS:// node intersects but on the back of the portal
                if (allowBackTouches)                    //默认是false,即中心点轨迹没有穿过portal,但是包围盒有跟portal相交
                {
                    // node is on wrong side of the portal - fix if we're allowing backside touches
                    if (portal->getTargetZone() != this &&
                        portal->getTargetZone() != pczsn->getHomeZone())
                    {
                        // set the home zone of the node to the target zone of the portal
                        pczsn->setHomeZone(portal->getTargetZone());
                        // continue checking for portal crossings in the new zone
                        newHomeZone = portal->getTargetZone()->updateNodeHomeZone(pczsn, false);
                    }
                }
                break;
            case Portal::INTERSECT_CROSS:        //中心点轨迹穿过portal
                // node intersects and crosses the portal - recurse into that zone as new home zone
                if (portal->getTargetZone() != this &&
                    portal->getTargetZone() != pczsn->getHomeZone())
                {
                    // set the home zone of the node to the target zone of the portal
                    pczsn->setHomeZone(portal->getTargetZone());
                    // continue checking for portal crossings in the new zone
                    newHomeZone = portal->getTargetZone()->updateNodeHomeZone(pczsn, true);
                }
                break;
            }
        }

        // return the new home zone
        return newHomeZone;
}

PortalBase::intersects(PCZSceneNode* pczsn)  //判断sceneNode是否与portal相交,用的是前一帧和当前帧的轨迹检测的方法 再综合包围盒判断,见上面的注释

自动判断会引发一些问题,对于比较大的静态物体区域可能会跨过若干个相邻或者不相邻的zone的包围盒,但是我们更倾向其属于一个特定的zone,其他的zone虽然
包围盒有交叉,但是实际上在里面看不到,此时的sceneNode在创建时就需要用sceneManger::createSceneNode(),不要挂到root下面,手动_updateBounds()和PCZSceneManager::addPCZSceneNode

其他静态物体,放入场景中要么挂到root下面自动归位zone(小物体推荐),要么用上述方法手动放置到一个合适的zone里面(大物体推荐),切忌不要放到不合适的zone里面
动态物体的移动,需要在portal和zone规定的范围内移动,如果不从portal里面走的话,即使已经走出zone的范围,系统仍然判断在其zone内

疑点:
1)Portal::setNode() 作者说必须的,但本人认为不一定要,直接设置corner也能用
2)更新sceneNode,怎么判断PCZSceneNode.isMoved() 代码里面没有对怎么判断, Node::setPosition和setOrientaion()等变换函数不可派生,
只有_getDerivedScale,
_getDerivedPosition,
_getDerivedOrientation,
convertWorldToLocalPosition,
convertLocalToWorldPosition,
convertWorldToLocalOrientation
convertLocalToWorldOrientation
里面调用了 _updateFromParent 里面有setMoved(true)
其他变换后 需要手东设置并且要savePrePosition
====解决,rootSceneNode->_update()会每帧调用(scenemanger::updateScenGraphic()),里面会自动更新移动的子节点的_update() 里面会调用_updateFromParent和_updateBounds();
_updateBounds()也会触发_updateFromParent() 并setMoved(true);
所以节点都必须有rootNode->createChild产生
rootNode->createChild也会触发childNode的needUpdate(),会在后面scenemanger::updateScenGraphic()自动_update()
用sceneManger::createSceneNode()并且没有挂到root下面就不会自动更新

3)sceneManager::getRootSceneNode()默认属于NULL的Zone? ====解决,Yes
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值