忽然想到之前退出的一个Ogre讨论超级群,想看看群里是否还有人分享Ogre相关技术资源(主要原因是前一段时间使用Ogre与HTC的Focus Vive进行了对接,期间遇到了很多技术难点,网络资料又是清一色的Unity相关内容,心想终于可以分享一些有价值的稀缺资料,顺便给自己在社区增加一点人气)。
可是万万没想到,当按下键盘的Enter键,弹出了一个入群提问:“Ogre中的Octree最大深度?”立刻懵逼。以前一直使用的是Ogre默认的SceneManager类,SceneType::ST_GENERIC。
只是知道Ogre的工程中有一个Plugin_OctreeSceneManager插件,也再网络资料中了解过四叉树适用与二维场景,八叉树适用于三维场景的说法,但是从来没有深入了解过。趁此机会可以仔细研究一下了。
刚看到问题时,稍微想了一下:八叉树就是一个树状结构,很明显叶子节点可以不断的细分啊?感觉不应该有什么最大深度的限制啊,于是就写了一个答案“无限深度”,等了许久没有通过验证,于是答案终究在代码里,于是打开VS开始追根问题的答案。看问题问Octree最大深度,于是就Alt+Shift+O,打开了OgreOctree.cpp。仔细查看该类确实就是树的数据结构,每个Octree包含八个子Octree的指针和一个parent的指针,确实对于树的深度没有什么限制。后来想这棵八叉树是用来管理场景节点的,那么限制可能会在SceneManager中后来真的在OctreeManager中发现了答案:
OctreeSceneManager::OctreeSceneManager(const String& name) : SceneManager(name)
{
AxisAlignedBox b( -10000, -10000, -10000, 10000, 10000, 10000 );
int depth = 8;
mOctree = 0;
init( b, depth );
}
OctreeManager构造函数会创建一个边长为20000,中心点在(0,0,0)的AxisAligneBox(轴对齐包围盒,就是边贴着坐标轴的矩形)。然后初始化了一个Octree mOctree,八叉树的根节点,然后会初始化一个mMaxDepth的成员变量,初始化为了8即所谓的最大深度值。
虽然答案找到了,但是还是引发了其他问题的思考:OctreeNode继承自SceneNode,并且由用户通过SceneManager创建,那么我们创建的OctreeNode是如何添加到Octree中的呢?
还是从代码中找答案:用户创建OctreeNode,然后将Entity附着在OctreeNode上。每一帧跟新时,调用更新场景图时,从根节点开始更新OctreeNode的包围盒,OctreeNode更新包围盒的函数中会调用static_cast < OctreeSceneManager * > ( mCreator ) -> _updateOctreeNode( this );将场景节点添加到指定的八叉树节点上(根据包围盒大小及位置):进行递归调用(从八叉树根节点开始递归检查应该落入哪个节点,递归终点是深度值大于8)。
函数调用流程如下:
void SceneManager::_updateSceneGraph(Camera* cam)
// 更新场景节点的额坐标变换矩阵
void SceneNode::_update(bool updateChildren, bool parentHasChanged)
// 更新节点的包围盒
void SceneNode::_updateBounds()
// 使用八叉树场景管理器更新场景场景节点位置(位于八叉树哪个节点中)
static_cast < OctreeSceneManager * > ( mCreator ) -> _updateOctreeNode( this );
// 从根节点开始递归调用来添加场景节点
// 递归条件:场景节点中心是否落在八叉树节点包围盒内部,且包围盒小于八叉树节点包围盒的四分之一,并且八叉树深度值小于8.
_addOctreeNode( onode, mOctree );
网友评论