On 8/22/2019 at 12:22 PM, JoeJ said:
Minor, but worth to mention: You use recursion for both traversal and build, this way the programming language manages the stack for you. I started with this too, but it may be not the best way to learn it, and it is not the most efficient way either. Managing the stack yourself lets you see what happens better. Difference between breath first / depth first becomes more clear, caching is better, dynamic allocation can be avoided.
First of all sorry for taking so long to respond. Your last post was very dense and it took me a while to absorb all the information. I've been pouring over it for the last few days try to make sense of it and I hope that I managed to do that because almost everything here is new to me.
So starting with my most glaring problem, which was not sorting at every iteration, I've implemented that hopefully correctly this time.
The second thing I did was remove the root special case, and instead just generalized the function where it just takes any case.
Also rewrote some functions to be cleaner/clearer, removed the redundant float cast etc (minor things)
The major issue I had was rewriting the whole thing without using new operators and without letting the program manage the stack, this I'm still having issues with and I'm not even sure I'm doing it right. I've basically resorted to using the binary heap implementation I found online which stores the whole tree in an array (is that what you meant when you said use arrays for the trees?). So I've rewritten my generation code (hopefully correctly) using that implementation.The problem is that I'm now having some difficulties writing the traversal code, I was wondering if you can provide any sort of hint to get me going.
This is my new generation code:
struct _heap_node
{
//the bounding box of this volume
_bounding_box bounding_box;
//the list of bounding boxes of the triangles this volume encompasses
std::vector<_bounding_box_tri> triangleBoundingBoxList;
bool isEmpty = true;
};
std::vector<_heap_node> midpoint_split(std::vector<_bounding_box_tri>& completeBoundingBoxList, UINT unitsPerLeaf = 100)
{
//support 7 levels of the tree
//1st level after root is 2 nodes, 2nd level is 4 nodes, 3rd level is 8 nodes, 4th level is 16 nodes, 5th level is 32 nodes, 6th level is 64 nodes, 7th level is 128 nodes
//2 + 4 + 8 + 16 + 32 + 64 + 128 = 256
//256 + 2 (1st is empty and second is root) = 258
UINT totalNumberOfNodes = 258;
//initialize the binary heap
_heap_node emptyNode;
emptyNode.isEmpty = true;
std::vector<_heap_node> tree(totalNumberOfNodes, emptyNode);
//generate the root node
_heap_node rootNode;
//find the volume of all the triangles in the terrain
rootNode.bounding_box = FindBoundingBox(completeBoundingBoxList);
rootNode.triangleBoundingBoxList = completeBoundingBoxList;
rootNode.isEmpty = false;
//add the root to the tree at 1st index (since the 0th slot is always empty)
tree[1] = rootNode;
//start with index 1 because slot 0 is always empty
for (UINT i = 1; i < totalNumberOfNodes; i++)
{
//if the number of triangles in the list is less than the set amount don't divide futher
if (tree[i].triangleBoundingBoxList.size() <= unitsPerLeaf)
break;
//generate a left branch
_heap_node leftChild;
leftChild.isEmpty = false;
//split the list of triangles in half (0 to 1/2 list)
UINT parent_index = i;
UINT start_box_index = 0;
UINT end_box_index = UINT(tree[parent_index].triangleBoundingBoxList.size() / 2.0f + 0.5f);
//create a sublist of triangle bounding boxes that are contained in this split
std::vector<_bounding_box_tri>::const_iterator startIter = tree[parent_index].triangleBoundingBoxList.begin() + start_box_index;
std::vector<_bounding_box_tri>::const_iterator endIter = tree[parent_index].triangleBoundingBoxList.begin() + end_box_index;
std::vector<_bounding_box_tri> leftsideBoxList(startIter, endIter);
//sort the new list of boxes
char axis = FindLongestSide(leftChild.bounding_box);
OrganizeListByAxis(axis, leftsideBoxList);
//find the bounding box around that split half
leftChild.bounding_box = FindBoundingBox(leftsideBoxList);
//pass on the new bounding box list
leftChild.triangleBoundingBoxList = leftsideBoxList;
//assign child to the 2n node of the binary heap (which represents the left tree)
tree[2 * i] = leftChild;
//generate the right branch
_heap_node rightChild;
rightChild.isEmpty = false;
//assign the other half to the right branch (1/2 list + 1 to end)
parent_index = i;
start_box_index = end_box_index + 1; //start where left box has ended, just ofset by one
end_box_index = tree[parent_index].triangleBoundingBoxList.size(); //end at the end of the list
//create a sublist of bounding boxes to sort
std::vector<_bounding_box_tri>::const_iterator startIter = tree[parent_index].triangleBoundingBoxList.begin() + start_box_index;
std::vector<_bounding_box_tri>::const_iterator endIter = tree[parent_index].triangleBoundingBoxList.begin() + end_box_index;
std::vector<_bounding_box_tri> rightsideBoxList(startIter, endIter);
//sort the list on the longest axis
axis = FindLongestSide(rightChild.bounding_box);
OrganizeListByAxis(axis, rightsideBoxList);
//find the bounding box around that split half
rightChild.bounding_box = FindBoundingBox(rightsideBoxList);
//pass on the new bounding box list
rightChild.triangleBoundingBoxList = rightsideBoxList;
//assign child to the 2n + 1 node of the binary heap (which represents the right tree)
tree[2 * i + 1] = rightChild;
}
return tree;
}
And this is as far as I've gotten with my traversal code. Since you said that the bounding boxes will intersect, I'm not even sure how to find the bounding volumes of the point anymore, do I just have to search every node? Anyways, here how I start it:
std::vector<_bounding_box_tri> FindPointInTree(XMVECTOR point, std::vector<_heap_node> tree)
{
//begin iteration at 2nd element since 1st element (slot 0) is always empty
for (UINT i = 1; i < tree.size(); i++)
{
//check if the point is in the node at all
if (IsPointInBox(point, tree[i].bounding_box) == false)
break;
//check if the point belong in the left side of the tree
if (IsPointInBox(point, tree[2*i].bounding_box))
//what do I do here? Start a new loop and go into the 2*i tree?
//check if the point belong in the right side of the tree
if (IsPointInBox(point, tree[2 * i + 1].bounding_box))
//what do I do here? Start a new loop and go into the 2*i + 1 tree?
}
}
And thank you for all your help so far, this is has been really helpful for this issue and in general as these concepts (representing trees as arrays and using arrays instead of recursion) are new areas for me which I have not previously explored. So either way I've learned a bunch already, and ironing out the remainders to get the BVH to work would just be icing on the cake at this point.