private void BuildSubTree(GIM_BVH_DATA_ARRAY primitive_boxes, int startIndex, int endIndex) { int curIndex = m_num_nodes; m_num_nodes++; Debug.Assert((endIndex - startIndex) > 0); if ((endIndex - startIndex) <= MAX_INDICES_PER_NODE) { //We have a leaf node int count = endIndex - startIndex; int[] indices = new int[count]; AABB bounds = new AABB(); bounds.Invalidate(); for (int i = 0; i < count; i++) { indices[i] = primitive_boxes[startIndex + i].m_data; bounds.Merge(primitive_boxes.GetRawArray()[startIndex + i].m_bound); } SetNodeBound(curIndex, ref bounds); m_node_array[curIndex].SetDataIndices(indices); return; } //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'. //split axis int splitIndex = CalcSplittingAxis(primitive_boxes, startIndex, endIndex); splitIndex = SortAndCalcSplittingIndex( primitive_boxes, startIndex, endIndex, splitIndex //split axis ); //calc this node bounding box AABB node_bound = new AABB(); node_bound.Invalidate(); for (int i = startIndex; i < endIndex; i++) { node_bound.Merge(ref primitive_boxes.GetRawArray()[i].m_bound); } SetNodeBound(curIndex, ref node_bound); //build left branch BuildSubTree(primitive_boxes, startIndex, splitIndex); //build right branch BuildSubTree(primitive_boxes, splitIndex, endIndex); m_node_array.GetRawArray()[curIndex].SetEscapeIndex(m_num_nodes - curIndex); }
protected int CalcSplittingAxis(GIM_BVH_DATA_ARRAY primitive_boxes, int startIndex, int endIndex) { int i; IndexedVector3 means = IndexedVector3.Zero; IndexedVector3 variance = IndexedVector3.Zero; int numIndices = endIndex - startIndex; for (i = startIndex; i < endIndex; i++) { IndexedVector3 center = 0.5f * (primitive_boxes[i].m_bound.m_max + primitive_boxes[i].m_bound.m_min); means += center; } means *= (1.0f / (float)numIndices); for (i = startIndex; i < endIndex; i++) { IndexedVector3 center = 0.5f * (primitive_boxes[i].m_bound.m_max + primitive_boxes[i].m_bound.m_min); IndexedVector3 diff2 = center - means; diff2 = diff2 * diff2; variance += diff2; } variance *= (1.0f) / ((float)numIndices - 1); return(MathUtil.MaxAxis(ref variance)); }
protected int SortAndCalcSplittingIndex( GIM_BVH_DATA_ARRAY primitive_boxes, int startIndex, int endIndex, int splitAxis) { int i; int splitIndex = startIndex; int numIndices = endIndex - startIndex; // average of centers float splitValue = 0.0f; IndexedVector3 means = IndexedVector3.Zero; for (i = startIndex; i < endIndex; i++) { IndexedVector3 center = 0.5f * (primitive_boxes[i].m_bound.m_max + primitive_boxes[i].m_bound.m_min); means += center; } means *= (1.0f) / (float)numIndices; splitValue = means[splitAxis]; //sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'. for (i = startIndex; i < endIndex; i++) { IndexedVector3 center = 0.5f * (primitive_boxes[i].m_bound.m_max + primitive_boxes[i].m_bound.m_min); if (center[splitAxis] > splitValue) { //swap primitive_boxes.Swap(i, splitIndex); //swapLeafNodes(i,splitIndex); splitIndex++; } } //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex //otherwise the tree-building might fail due to stack-overflows in certain cases. //unbalanced1 is unsafe: it can cause stack overflows //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1))); //unbalanced2 should work too: always use center (perfect balanced trees) //bool unbalanced2 = true; //this should be safe too: int rangeBalancedIndices = numIndices / 3; bool unbalanced = ((splitIndex <= (startIndex + rangeBalancedIndices)) || (splitIndex >= (endIndex - 1 - rangeBalancedIndices))); if (unbalanced) { splitIndex = startIndex + (numIndices >> 1); } Debug.Assert(!((splitIndex == startIndex) || (splitIndex == (endIndex)))); return(splitIndex); }
//! prototype functions for box tree management //!@{ internal void BuildTree(GIM_BVH_DATA_ARRAY primitive_boxes) { CalcQuantization(primitive_boxes); // initialize node count to 0 m_num_nodes = 0; // allocate nodes m_node_array.Resize(primitive_boxes.Count * 2); BuildSubTree(primitive_boxes, 0, primitive_boxes.Count); }
//! prototype functions for box tree management //!@{ public void BuildTree(GIM_BVH_DATA_ARRAY primitive_boxes) { // initialize node count to 0 m_num_nodes = 0; // allocate nodes m_node_array.Capacity = (primitive_boxes.Count * 2); // check this- should be capacity or count?? BuildSubTree(primitive_boxes, 0, primitive_boxes.Count); }
//! this rebuild the entire set public void BuildSet() { //obtain primitive boxes GIM_BVH_DATA_ARRAY primitive_boxes = new GIM_BVH_DATA_ARRAY(); //primitive_boxes.resize(m_primitive_manager.get_primitive_count()); primitive_boxes.Capacity = m_primitive_manager.GetPrimitiveCount(); for (int i = 0; i < primitive_boxes.Count; i++) { m_primitive_manager.GetPrimitiveBox(i, out primitive_boxes.GetRawArray()[i].m_bound); primitive_boxes.GetRawArray()[i].m_data = i; } m_box_tree.BuildTree(primitive_boxes); }
protected void CalcQuantization(GIM_BVH_DATA_ARRAY primitive_boxes, float boundMargin) { //calc globa box AABB global_bound = new AABB(); global_bound.Invalidate(); int count = primitive_boxes.Count; for (int i = 0; i < count; i++) { global_bound.Merge(ref primitive_boxes.GetRawArray()[i].m_bound); } GImpactQuantization.CalcQuantizationParameters(out m_global_bound.m_min, out m_global_bound.m_max, out m_bvhQuantization, ref global_bound.m_min, ref global_bound.m_max, boundMargin); }
//! this rebuild the entire set public void BuildSet() { //obtain primitive boxes int listSize = m_primitive_manager.GetPrimitiveCount(); GIM_BVH_DATA_ARRAY primitive_boxes = new GIM_BVH_DATA_ARRAY(listSize); // forces boxes to be allocated primitive_boxes.Resize(listSize); GIM_BVH_DATA[] rawArray = primitive_boxes.GetRawArray(); for (int i = 0; i < listSize; i++) { m_primitive_manager.GetPrimitiveBox(i, out rawArray[i].m_bound); rawArray[i].m_data = i; } m_box_tree.BuildTree(primitive_boxes); }
protected void BuildSubTree(GIM_BVH_DATA_ARRAY primitive_boxes, int startIndex, int endIndex) { int curIndex = m_num_nodes; m_num_nodes++; Debug.Assert((endIndex - startIndex) > 0); if ((endIndex - startIndex) == 1) { //We have a leaf node SetNodeBound(curIndex, ref primitive_boxes.GetRawArray()[startIndex].m_bound); m_node_array[curIndex].SetDataIndex(primitive_boxes[startIndex].m_data); #if DEBUG if (BulletGlobals.g_streamWriter != null && BulletGlobals.debugGimpactBVH) { BulletGlobals.g_streamWriter.WriteLine("bst curIndex[{0}] dataIndex[{1}]", curIndex, primitive_boxes[startIndex].m_data); MathUtil.PrintVector3(BulletGlobals.g_streamWriter, "bst min", primitive_boxes[startIndex].m_bound.m_min); MathUtil.PrintVector3(BulletGlobals.g_streamWriter, "bst max", primitive_boxes[startIndex].m_bound.m_max); } #endif return; } //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'. //split axis int splitIndex = CalcSplittingAxis(primitive_boxes, startIndex, endIndex); splitIndex = SortAndCalcSplittingIndex( primitive_boxes, startIndex, endIndex, splitIndex //split axis ); //calc this node bounding box AABB node_bound = new AABB(); node_bound.Invalidate(); for (int i = startIndex; i < endIndex; i++) { node_bound.Merge(ref primitive_boxes.GetRawArray()[i].m_bound); } SetNodeBound(curIndex, ref node_bound); //build left branch BuildSubTree(primitive_boxes, startIndex, splitIndex); //build right branch BuildSubTree(primitive_boxes, splitIndex, endIndex); m_node_array.GetRawArray()[curIndex].SetEscapeIndex(m_num_nodes - curIndex); #if DEBUG if (BulletGlobals.g_streamWriter != null && BulletGlobals.debugGimpactBVH) { BulletGlobals.g_streamWriter.WriteLine("bst curIndex[{0}] escapeIndex[{1}]", curIndex, m_node_array.GetRawArray()[curIndex].GetEscapeIndex()); MathUtil.PrintVector3(BulletGlobals.g_streamWriter, "bst node min", node_bound.m_min); MathUtil.PrintVector3(BulletGlobals.g_streamWriter, "bst node max", node_bound.m_max); } #endif }
protected void CalcQuantization(GIM_BVH_DATA_ARRAY primitive_boxes) { CalcQuantization(primitive_boxes, 1.0f); }