针对文章:http://www.brandonpelfrey.com/blog/coding-a-simple-octree/
及其github:https://github.com/brandonpelfrey/SimpleOctree/ 中的代码剖析总结:
1.空间模型思想:
一个大的正方体或者长方体,只需要记录中心点向量和半边长向量,用这两个向量加减即得到8个子空间;
8个子空间中的每个空间又作为一个空间记录中心点向量和半边长,继续对它的子空间进行划分为8个子空间,继续下去。
其中空间内的物体或点,如果当前空间体不存在子空间那么存放,如果存在子空间那么下方到子空间中,所以根据物体点产生
子空间,需要处理当前空间中的物体(若当前是叶子空间)和新加入的物体,都要将他们放置到新生成的子空间中(即叶子空间)。
2.递归的思想:
1)理解压栈的过程,只有调用点关联,也就是函数的参数和返回值关联,其它代码变量都因为拷贝了一份而作用域无效的了。
2)理解终止条件多样性,可以if也可以for/while,那些是终止条件,那些不是终止条件,终止条件一定要在递归前面。
3)理解出栈的过程,因为到达终止条件了,调用点出栈那么函数可以像正常函数一样继续执行函数体内它没有执行的部分。
4) 递归函数的复杂结构,例如执行左子树递归,判断,又执行右子树递归,实现前序,中序,后序遍历的情形,都是由1)2)3)来解释的。
3.巧妙的八叉树子空间编号,便于通过位运算查找当前的变换:
left_bottom_front: 000
left_bottom_back: 001
left_top_front: 010
left_top_back: 011
right_bottom_front: 100
right_bottom_back: 101
right_top_front: 110
right_top_back: 111
例如代码:
int getOctantContainingPoint(const Vec3& point) const {
int oct = 0;
if(point.x >= origin.x) oct |= 4;
if(point.y >= origin.y) oct |= 2;
if(point.z >= origin.z) oct |= 1;
return oct;
}
for(int i=0; i<8; ++i) {
// Compute new bounding box for this child
Vec3 newOrigin = origin;
newOrigin.x += halfDimension.x * (i&4 ? .5f : -.5f);
newOrigin.y += halfDimension.y * (i&2 ? .5f : -.5f);
newOrigin.z += halfDimension.z * (i&1 ? .5f : -.5f);
children[i] = new Octree(newOrigin, halfDimension*.5f);
}