octree stackoverflow

Started by
16 comments, last by belfegor 11 years, 4 months ago
I could not find good tutorial about octrees so tried to make one on my own.
I have a lot of non-moving/static objects in my scene so i thought i could speed up culling with octree instead with camera frustum-bbox check with all of these. Can you spot what am i doing wrong?

octree.h

class OcTree
{
private:
std::shared_ptr<OcTree> child[8];
sp_StaticMeshSceneNode sNode; // shared_ptr
bool leaf;
bounding_box3d bbox;
SceneManager* pSmgr;
enum OctreeParts
{
TOP_FRONT_LEFT = 0,
TOP_FRONT_RIGHT = 1,
TOP_BACK_LEFT = 2,
TOP_BACK_RIGHT = 3,
BOTTOM_FRONT_LEFT = 4,
BOTTOM_FRONT_RIGHT = 5,
BOTTOM_BACK_LEFT = 6,
BOTTOM_BACK_RIGHT = 7
};
public:
OcTree(SceneManager* _smgr, const bounding_box3d& _bbox);
void create(std::shared_ptr<OcTree> _tree);
bounding_box3d subdivide(std::shared_ptr<OcTree> _parent, int witchPart);
void cullChildren(std::shared_ptr<OcTree> _root);

static std::size_t levelCnt;
};


octree.cpp

std::size_t OcTree::levelCnt = 0;
OcTree::OcTree(SceneManager* _smgr, const bounding_box3d& _bbox)
{
bbox = _bbox;
pSmgr = _smgr;
for(std::size_t i = 0; i < 8; ++i)
{
child = nullptr;
}
leaf = false;
sNode = nullptr;
}
void OcTree::create(std::shared_ptr<OcTree> _tree)
{
++levelCnt;
std::size_t cnt = 0;
const auto& nodes = pSmgr->getNodes();
for(std::size_t i = 0; i < nodes.size(); ++i)
{
bool result = _tree->bbox.intersects(nodes->getBBox());
if(result)
{
sNode = nodes;
++cnt;
}
}
if(cnt <= 1)
{
_tree->leaf = true;
return;
}
else
{
sNode = nullptr;
for(std::size_t i = 0; i < 8; ++i)
{
child = std::shared_ptr<OcTree>(new OcTree(pSmgr, subdivide(_tree, i)));
create(child);
}
}
}
bounding_box3d OcTree::subdivide(std::shared_ptr<OcTree> _parent, int witchPart)
{
bounding_box3d outBB;
float3 ext = _parent->bbox.getExtent() * 0.5f; // (max - min) / 2
float3 cen = _parent->bbox.getCenter(); // (min + max) / 2
switch(witchPart)
{
case TOP_FRONT_LEFT:
{
float3 min = cen - float3(ext.x, 0.0f, 0.0f);
float3 max = cen + float3(0.0f, ext.y, ext.z);
outBB = oma::bounding_box3d(min, max);
}break;
case TOP_FRONT_RIGHT:
{
float3 min = cen;
float3 max = cen + float3(ext.x, ext.y, ext.z);
outBB = bounding_box3d(min, max);
}break;
case TOP_BACK_LEFT:
{
float3 min = cen - float3(ext.x, 0.0f, ext.z);
float3 max = cen + float3(0.0f, ext.y, 0.0f);
outBB = bounding_box3d(min, max);
}break;
case TOP_BACK_RIGHT:
{
float3 min = cen - float3(0.0f, 0.0f, ext.z);
float3 max = cen + float3(ext.x, ext.y, 0.0f);
outBB = bounding_box3d(min, max);
}break;
case BOTTOM_FRONT_LEFT:
{
float3 min = cen - float3(ext.x, ext.y, 0.0f);
float3 max = cen + float3(0.0f, 0.0f, ext.z);
outBB = bounding_box3d(min, max);
}break;
case BOTTOM_FRONT_RIGHT:
{
float3 min = cen - float3(0.0f, ext.y, 0.0f);
float3 max = cen + float3(ext.x, 0.0f, ext.z);
outBB = bounding_box3d(min, max);
}break;
case BOTTOM_BACK_LEFT:
{
float3 min = cen - float3(ext.x, ext.y, ext.z);
float3 max = cen;
outBB = bounding_box3d(min, max);
}break;
case BOTTOM_BACK_RIGHT:
{
float3 min = cen - float3(0.0f, ext.y, ext.z);
float3 max = cen + float3(ext.x, 0.0f, 0.0f);
outBB = bounding_box3d(min, max);
}break;
default:
{
assert(false);
}break;
};
return outBB;
}
void OcTree::cullChildren(std::shared_ptr<OcTree> _root)
{
if(nullptr == _root)
return;
sp_Camera cam = pSmgr->getPlayerCamera();
if(cam->getFrustum().isBoxInFrustum(_root->bbox))
{
if(_root->leaf)
{
if(nullptr != _root->sNode)
_root->sNode->visible = true;
}
else
{
for(std::size_t i = 0; i < 8; ++i)
{
cullChildren(_root->child);
}
}
}
}


Then i create octree:


bounding_box3d ocBB(float3(-8.1028748f, -10.665000f, -147.71899f), float3(270.58899f, 18.529583f, 98.760002f));
ocTree = std::shared_ptr<OcTree>(new OcTree(this, ocBB));
ocTree->create(ocTree); // stack overflow


Stack overflow is in create method.

Thank you for your time.
Advertisement
Stack overflow means you have too many recursive functions (among other unrelated things).
You need to check the depth at which you stop generating nodes within the octree. Usually 8 nodes deep, including the head node, is the maximum depth for an octree.

A quick glance at your code shows no sign that you ever terminate the creation of the octree. You just keep creating more and more nodes infinitely deep until it overflows the stack. levelCnt is being incremented but never used.
Additionally, it is “used” incorrectly. The depth of the tree must be passed as a parameter to the function that recursively creates nodes.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Yes, he tries to stop the recursion. create will only create child nodes if the number of intersections (however they may be definied by bbox.intersects) is greater than 1.

But I still guess the abort criterion is wrong. If there are overlapping scene nodes, "create" will never reach its stop criterion.

Does it work if you use an empty scene graph or make sure there are only scene nodes that are far enough apart?

But passing the current depth recursively to create and adding a condition for this depth to be below a configurable value around line 27 of octree.cpp should solve the problem.

A quick glance at your code shows no sign that you ever terminate the creation of the octree.
[/quote]
But i thought it will stop when there is a 1 or none of scene objects bbox intersecting with current octree bbox?

if(cnt <= 1)
{
_tree->leaf = true;
return;
}


I don't quite understand what should i do different?

But I still guess the abort criterion is wrong. If there are overlapping scene nodes, "create" will never reach its stop criterion.[/quote]
I don't know how to overcome that.


Does it work if you use an empty scene graph or make sure there are only scene nodes that are far enough apart?
[/quote]

Do you mean i should group nodes to have its own bbox?

How to correctly builld octree for static objects given my example above?

Thank you for your time.
Jim Adams book has a good octree sample. Might as well check it
You will overcome this problem by adding a check for the level of your current node. Quick example (please put it together with the rest of your code yourself):

[source lang="c++"]void create(std::shared_ptr<OcTree> _tree, int level) {
... all the rest, test for intersections and stuff ...
if(cnt <= 1 || level > max_level) {
... all the stuff you do in your original code, except that you may have a list of nodes instead of only one ...
} else {
.... create(..., level + 1) ...
}
}[/source]

Hope this is understandable, don't really have the time to go more in depth at the moment.

Hope this is understandable, don't really have the time to go more in depth at the moment.


Octree puns...So funny!

[size="3"]Halfway down the trail to Hell...
It got rid of overflow but i am doing something wrong in my create function (at least i suspect the problem is there) because i got only few objects displayed compared to what i can see with camera. Please help me further if you find time, thanks.

I can't think of right logic for this:

const std::size_t max_level = 5; // everything above 5 is to slow

void OcTree::create(std::shared_ptr<OcTree> _tree, std::size_t curr_level)
{

std::size_t cnt = 0;
const auto&amp; nodes = pSmgr->getNodes();
for(std::size_t i = 0; i < nodes.size(); ++i)
{
bool result = _tree->bbox.intersects(nodes->getBBox());
if(result)
{
_tree->vNode.push_back(nodes); // vNodes is vector of objects
++cnt;
}
}
if(cnt <= 1 || curr_level > max_level)
{
_tree->leaf = true;
return;
}
else
{
_tree->vNode.clear();
for(std::size_t i = 0; i < 8; ++i)
{
child = std::shared_ptr<OcTree>(new OcTree(_tree->pSmgr, subdivide(_tree, i)));
create(child, curr_level + 1);
}
}
}


If you need more info please tell.

Jim Adams book has a good octree sample. Might as well check it


What is the name of the book?
Hi there,
I can't read your code - too much stl :/
But i remember the pitfalls with octrees, so that might be helpful, if you don't know it:

The problem is: What to do with an object that is split by one or more grid planes?
Put it in each node and draw it multiple times?
Put it in one node and missing to draw it whaen the node is clipped? (guessing thats your problem)

Solution: Put each object to the node, where this condition is true:
objects bounding box center is inside node
AND the largest dimenson from the objects bounding box <= the dimenson of the node.
AND the largest dimenson from the objects bounding box > half the dimenson of the node.

... this results in large objects at the top levels, and small objects at the bottom levels of the tree.

While clipping extrude the nodes by one half of its dimension at each side (so it has 4 times its volume).
This is the volume that surely covers all objects.

I guess that is called 'loose octree', but i'm not sure.

This topic is closed to new replies.

Advertisement