• OGRE 八叉树


    void OctreeSceneManager::_addOctreeNode( OctreeNode * n, Octree *octant, int depth )
    {

     // Skip if octree has been destroyed (shutdown conditions)
     if (!mOctree)
      return;

     const AxisAlignedBox& bx = n -> _getWorldAABB();


        //if the octree is twice as big as the scene node,
        //we will add it to a child.
        if ( ( depth < mMaxDepth ) && octant -> _isTwiceSize( bx ) )//深度从0开始递归,octree根结点是n包围盒的两倍
        {
            int x, y, z;
            octant -> _getChildIndexes( bx, &x, &y, &z );//octant有八个空间,或者说是坐标系的八个象限,bx

            if ( octant -> mChildren[ x ][ y ][ z ] == 0 )//如果此空间或者说此象限是空的
            {
                octant -> mChildren[ x ][ y ][ z ] = OGRE_NEW Octree( octant );//生成一个新的子树
                const Vector3& octantMin = octant -> mBox.getMinimum();
                const Vector3& octantMax = octant -> mBox.getMaximum();//当前子树的最大,最小点
                Vector3 min, max;

                if ( x == 0 )
                {
                    min.x = octantMin.x;
                    max.x = ( octantMin.x + octantMax.x ) / 2;
                }

                else
                {
                    min.x = ( octantMin.x + octantMax.x ) / 2;
                    max.x = octantMax.x;
                }

                if ( y == 0 )
                {
                    min.y = octantMin.y;
                    max.y = ( octantMin.y + octantMax.y ) / 2;
                }

                else
                {
                    min.y = ( octantMin.y + octantMax.y ) / 2;
                    max.y = octantMax.y;
                }

                if ( z == 0 )
                {
                    min.z = octantMin.z;
                    max.z = ( octantMin.z + octantMax.z ) / 2;
                }

                else
                {min.z = ( octantMin.z + octantMax.z ) / 2;
                    max.z = octantMax.z;
                }//根据n所在的象限的位置,计算包围盒

                octant -> mChildren[ x ][ y ][ z ] -> mBox.setExtents( min, max );
                octant -> mChildren[ x ][ y ][ z ] -> mHalfSize = ( max - min ) / 2;
            }

               _addOctreeNode( n, octant -> mChildren[ x ][ y ][ z ], ++depth );//如果当前子树的包围盒

               大于包围盒的两倍,则继续遍历查找

        }

        else
        {
            octant -> _addNode( n );//至到父包围的半径小于子包围盒的两倍,则挂在当前结点上
        }
    }

    void _findNodes( const Ray &t, std::list < SceneNode * > &list, SceneNode *exclude, bool full, Octree *octant )
    {

     if ( !full )
     {
      AxisAlignedBox obox;
      octant -> _getCullBounds( &obox );//返回两倍的包围盒,用于剪裁

      Intersection isect = intersect( t, obox );

      if ( isect == OUTSIDE )//如果不想交,则返回
       return ;

      full = ( isect == INSIDE );//如果在扩张后的包围盒内部,但不相交,则full = true,否则full = false
     }

     while ( it != octant -> mNodes.end() )//向下遍历
     {
      OctreeNode * on = ( *it );

      if ( on != exclude )                            //排除exclude节点
      {
       if ( full )                                          //在扩张后的包围盒内部                  
       {
        list.push_back( on );
       }

       else                                               //如果不在扩张后的包围盒内部,则和原始包围盒重新求交
       {
        Intersection nsect = intersect( t, on -> _getWorldAABB() );

      ++it;
     }

     Octree* child;//重新向下遍历

     if ( (child=octant -> mChildren[ 1 ][ 0 ][ 0 ]) != 0 )
      _findNodes( t, list, exclude, full, child );

     if ( (child=octant -> mChildren[ 0 ][ 1 ][ 0 ]) != 0 )
      _findNodes( t, list, exclude, full, child );

     if ( (child=octant -> mChildren[ 1 ][ 1 ][ 0 ]) != 0 )
      _findNodes( t, list, exclude, full, child );

     if ( (child=octant -> mChildren[ 0 ][ 0 ][ 1 ]) != 0 )
      _findNodes( t, list, exclude, full, child );

     if ( (child=octant -> mChildren[ 1 ][ 0 ][ 1 ]) != 0 )
      _findNodes( t, list, exclude, full, child );

     if ( (child=octant -> mChildren[ 0 ][ 1 ][ 1 ]) != 0 )
      _findNodes( t, list, exclude, full, child );

     if ( (child=octant -> mChildren[ 1 ][ 1 ][ 1 ]) != 0 )
      _findNodes( t, list, exclude, full, child );

    }

    注:其他类型求交,只是换了intersector函数

    void OctreeSceneManager::_updateOctreeNode( OctreeNode * onode )
    {
        const AxisAlignedBox& box = onode -> _getWorldAABB();

        if ( box.isNull() )
            return ;

     // Skip if octree has been destroyed (shutdown conditions)
     if (!mOctree)//根结点已经破坏
      return;

        if ( onode -> getOctant() == 0 )//没有挂到节点上
        {
            //if outside the octree, force into the root node.
            if ( ! onode -> _isIn( mOctree -> mBox ) )//onode不在父节点的包围盒内,在直接挂在父节点
                mOctree->_addNode( onode );
            else
                _addOctreeNode( onode, mOctree );   //否则遍历,挂在合适的节点下

     return ;
        }

        if ( ! onode -> _isIn( onode -> getOctant() -> mBox ) )//onode不再父节点的包围盒
        {
            _removeOctreeNode( onode );

            //if outside the octree, force into the root node.
            if ( ! onode -> _isIn( mOctree -> mBox ) )              //不在根节点包围盒内,则直接挂在根结点
                mOctree->_addNode( onode );
            else
                _addOctreeNode( onode, mOctree );
        }
    }

    void OctreeSceneManager::resize( const AxisAlignedBox &box )
    {
        std::list < SceneNode * > nodes;
        std::list < SceneNode * > ::iterator it;

        _findNodes( mOctree->mBox, nodes, 0, true, mOctree );//在包围盒box内部的nodes

        OGRE_DELETE mOctree;

        mOctree = OGRE_NEW Octree( 0 );                                //生成新的根节点
        mOctree->mBox = box;

     const Vector3 min = box.getMinimum();
     const Vector3 max = box.getMaximum();
     mOctree->mHalfSize = ( max - min ) * 0.5f;   

        it = nodes.begin();

        while ( it != nodes.end() )
        {
            OctreeNode * on = static_cast < OctreeNode * > ( *it );    //重新挂在新的根节点下
            on -> setOctant( 0 );
            _updateOctreeNode( on );
            ++it;
        }

    }

  • 相关阅读:
    前天去游泳了
    Microsoft今天开了中文的MSDN了,以后查资料有时要快了点吧
    Visual Studio .NET已检测到指定的WEB服务运行的不是ASP.NET 1.1版
    sqlserver 2005 利用游标解决标量值函数主键自增id批量导入数据问题
    nvarchar查询条件中不用加单引号''吗?
    使用标量值函数作为主键自增值的时候,动软代码生成器的插入方法需要去掉主键的参数。
    c#里的'0','1'对应sqlserver2005中的False,True
    三元运算符绑定缩略内容
    循环插入数据存储过程
    01|02|03| ====> (01,02,03)用于in id数组这种查询方式
  • 原文地址:https://www.cnblogs.com/lizhengjin/p/1847298.html
Copyright © 2020-2023  润新知