int AllocateNode()
    {
        //return AABBTree.NullIndex;
        if (m_nextFreeNodeIndex == AABBTree.NullIndex)
        {
            DebugHelper.Assert(m_allocatedNodeCount == m_nodeCapacity);

            m_nodeCapacity += m_growthSize;
            for (int nodeIndex = m_allocatedNodeCount; nodeIndex < m_nodeCapacity; nodeIndex++)
            {
                AABBTreeNode node = new AABBTreeNode();
                m_nodes.Add(node);
                node.m_nextNodeIndex = nodeIndex + 1;
            }
            m_nodes[m_nodeCapacity - 1].m_nextNodeIndex = AABBTree.NullIndex;
            m_nextFreeNodeIndex = m_allocatedNodeCount;
        }

        {
            int          nodeIndex    = m_nextFreeNodeIndex;
            AABBTreeNode allocateNode = m_nodes[nodeIndex];
            //allocateNode.m_parentNodeIndex = AABBTree.NullIndex;
            m_nextFreeNodeIndex   = allocateNode.m_nextNodeIndex;
            m_allocatedNodeCount += 1;
            return(nodeIndex);
        }
    }
Exemplo n.º 2
0
 // Traverses an AABBTree from currentNode. Returns true if leaf is found, and
 // the triangles are returned in the triangles array. Otherwise, return false.
 public static bool GetTriangles(Vector3 point, AABBTreeNode currentNode, out int[] triangles)
 {
     triangles = null;
     // Check if point is within bounds.
     if (currentNode.bounds.Contains(point))
     {
         // If point within bounds, check if currentNode is leaf.
         if (currentNode.leftChild == null && currentNode.rightChild == null)
         {
             // If leaf, set triangles and return true.
             triangles = currentNode.triangles;
             return(true);
         }
         else
         {
             // If not leaf, continue recursion. Either point is in leftChild or rightChild.
             return(GetTriangles(point, currentNode.leftChild, out triangles) ||
                    GetTriangles(point, currentNode.rightChild, out triangles));
         }
     }
     else
     {
         // If not within bounds, return false.
         return(false);
     }
 }
    public List <IAABB> QueryOverlaps(IAABB obj)
    {
        List <IAABB> overlaps = new List <IAABB>();
        Stack <int>  stack    = new Stack <int>();
        AABB3d       testAabb = obj.GetAABBBounds();

        stack.Push(m_rootNodeIndex);
        while (stack.Count != 0)
        {
            int nodeIndex = stack.Pop();

            if (nodeIndex == NullIndex)
            {
                continue;
            }

            AABBTreeNode node = m_nodes[nodeIndex];
            if (node.m_bounds.Overlaps(testAabb))
            {
                if (node.IsLeaf() && node.m_object != obj)
                {
                    overlaps.Insert(0, node.m_object);
                }
                else
                {
                    stack.Push(node.m_leftNodeIndex);
                    stack.Push(node.m_rightNodeIndex);
                }
            }
        }

        return(overlaps);
    }
    void DeallocateNode(int nodeIndex)
    {
        AABBTreeNode deallocatedNode = m_nodes[nodeIndex];

        deallocatedNode.m_nextNodeIndex = m_nextFreeNodeIndex;
        m_nextFreeNodeIndex             = nodeIndex;
        m_allocatedNodeCount--;
    }
    public void InsertObject(IAABB obj)
    {
        int          nodeIndex = AllocateNode();
        AABBTreeNode node      = m_nodes[nodeIndex];

        node.m_bounds = obj.GetAABBBounds();
        node.m_object = obj;

        InsertLeaf(nodeIndex);
        m_objectNodeIndexMap[obj] = nodeIndex;
    }
Exemplo n.º 6
0
    private void ConstructAABBTree()
    {
        // Construct root node.
        rootNode           = new AABBTreeNode(terrainBounds);
        rootNode.triangles = terrainMesh.triangles;

        if (showDebugBoundsVis)
        {
            GameObject cube = Instantiate(debugBoundsVis, terrainBounds.center, Quaternion.identity, transform);
            cube.transform.localScale = terrainBounds.size;
        }

        rootNode.leftChild  = AABBTreeRecursion(rootNode, Direction.Left);
        rootNode.rightChild = AABBTreeRecursion(rootNode, Direction.Right);
    }
    void UpdateLeaf(int leafNodeIndex, AABB3d newAABB)
    {
        AABBTreeNode node = m_nodes[leafNodeIndex];

        // if the node contains the new aabb then we just leave things
        // TODO: when we add velocity this check should kick in as often an update will lie within the velocity fattened initial aabb
        // to support this we might need to differentiate between velocity fattened aabb and actual aabb
        if (node.m_bounds.Contains(newAABB))
        {
            return;
        }

        RemoveLeaf(leafNodeIndex);
        node.m_bounds = newAABB;
        InsertLeaf(leafNodeIndex);
    }
    void RemoveLeaf(int leafNodeIndex)
    {
        // if the leaf is the root then we can just clear the root pointer and return
        if (leafNodeIndex == m_rootNodeIndex)
        {
            m_rootNodeIndex = NullIndex;
            return;
        }

        AABBTreeNode leafNode             = m_nodes[leafNodeIndex];
        int          parentNodeIndex      = leafNode.m_parentNodeIndex;
        AABBTreeNode parentNode           = m_nodes[parentNodeIndex];
        int          grandParentNodeIndex = parentNode.m_parentNodeIndex;
        int          siblingNodeIndex     = parentNode.m_leftNodeIndex == leafNodeIndex ? parentNode.m_rightNodeIndex : parentNode.m_leftNodeIndex;

        DebugHelper.Assert(siblingNodeIndex != NullIndex); // we must have a sibling
        AABBTreeNode siblingNode = m_nodes[siblingNodeIndex];

        if (grandParentNodeIndex != NullIndex)
        {
            // if we have a grand parent (i.e. the parent is not the root) then destroy the parent and connect the sibling to the grandparent in its
            // place
            AABBTreeNode grandParentNode = m_nodes[grandParentNodeIndex];
            if (grandParentNode.m_leftNodeIndex == parentNodeIndex)
            {
                grandParentNode.m_leftNodeIndex = siblingNodeIndex;
            }
            else
            {
                grandParentNode.m_rightNodeIndex = siblingNodeIndex;
            }
            siblingNode.m_parentNodeIndex = grandParentNodeIndex;
            DeallocateNode(parentNodeIndex);


            FixUpwardsTree(grandParentNodeIndex);
        }
        else
        {
            // if we have no grandparent then the parent is the root and so our sibling becomes the root and has it's parent removed
            m_rootNodeIndex = siblingNodeIndex;
            siblingNode.m_parentNodeIndex = NullIndex;
            DeallocateNode(parentNodeIndex);
        }

        leafNode.m_parentNodeIndex = NullIndex;
    }
    void FixUpwardsTree(int treeNodeIndex)
    {
        while (treeNodeIndex != NullIndex)
        {
            AABBTreeNode treeNode = m_nodes[treeNodeIndex];

            // every node should be a parent
            DebugHelper.Assert(treeNode.m_leftNodeIndex != NullIndex && treeNode.m_rightNodeIndex != NullIndex);

            // fix height and area
            AABBTreeNode leftNode  = m_nodes[treeNode.m_leftNodeIndex];
            AABBTreeNode rightNode = m_nodes[treeNode.m_rightNodeIndex];
            treeNode.m_bounds = leftNode.m_bounds.Merge(rightNode.m_bounds);

            treeNodeIndex = treeNode.m_parentNodeIndex;
        }
    }
    public AABBTree(int initialSize)
    {
        m_rootNodeIndex      = AABBTree.NullIndex;
        m_allocatedNodeCount = 0;
        m_nextFreeNodeIndex  = 0;
        m_nodeCapacity       = initialSize;
        m_growthSize         = initialSize;

        //m_nodes.Capacity = initialSize;
        for (int nodeIndex = 0; nodeIndex < initialSize; ++nodeIndex)
        {
            // AABBTreeNode node = m_nodes[nodeIndex];
            //node.m_nextNodeIndex = nodeIndex + 1;
            AABBTreeNode node = new AABBTreeNode();
            m_nodes.Add(node);
            node.m_nextNodeIndex = nodeIndex + 1;
        }
        m_nodes[initialSize - 1].m_nextNodeIndex = AABBTree.NullIndex;
    }
Exemplo n.º 11
0
    private AABBTreeNode AABBTreeRecursion(AABBTreeNode parent, Direction childDirection)
    {
        // If left child, get the first half of the parent's triangles.
        // If right child, get the second half of the parent's triangles.
        int triangleStartIndex = (childDirection == Direction.Left) ? 0 : parent.triangles.Length / 2;

        // Get the correct triangles.
        int[] currentTriangles = new int[parent.triangles.Length / 2];
        Array.Copy(parent.triangles, triangleStartIndex, currentTriangles, 0, currentTriangles.Length);

        // Construct bounds from triangles.
        Vector3[] terrainVertices = terrainMesh.vertices;
        Vector3   min             = terrainVertices[currentTriangles[0]];
        Vector3   max             = terrainVertices[currentTriangles[currentTriangles.Length - 1]];

        // Correct height of the bounds.
        min = new Vector3(min.x, minY, min.z);
        max = new Vector3(max.x, maxY, max.z);
        Vector3 center        = Vector3.Lerp(min, max, 0.5f);
        Bounds  currentBounds = new Bounds(center, Vector3.zero);

        currentBounds.Encapsulate(min);
        currentBounds.Encapsulate(max);

        // Create new node.
        AABBTreeNode currentNode = new AABBTreeNode(currentBounds);

        currentNode.triangles = currentTriangles;

        if (showDebugBoundsVis)
        {
            GameObject cube = Instantiate(debugBoundsVis, center, Quaternion.identity, transform);
            cube.transform.localScale = currentBounds.size;
        }

        // If node should not be leaf, set children, otherwise leave them null.
        if (currentTriangles.Length / 3 > leafNumTriangles)
        {
            currentNode.leftChild  = AABBTreeRecursion(currentNode, Direction.Left);
            currentNode.rightChild = AABBTreeRecursion(currentNode, Direction.Right);
        }
        return(currentNode);
    }
Exemplo n.º 12
0
        public static object Serialize_AABBTreeNode(object _obj, System.Type type, OverloadLevelConvertSerializer serializer)
        {
            AABBTreeNode obj = (AABBTreeNode)_obj;

            if (serializer.IsWriting)
            {
                serializer.SerializeOut_object(obj.Bounds);
                serializer.SerializeOut_int32(obj.MinChildIndex);
                serializer.SerializeOut_int32(obj.MaxChildIndex);
                serializer.SerializeOut_int32(obj.SegmentIndex);
            }
            else
            {
                obj.Bounds        = (AABB)serializer.SerializeIn_object(typeof(AABB));
                obj.MinChildIndex = serializer.SerializeIn_int32();
                obj.MaxChildIndex = serializer.SerializeIn_int32();
                obj.SegmentIndex  = serializer.SerializeIn_int32();
            }
            return(obj);
        }
    void InsertLeaf(int leafNodeIndex)
    {
        // make sure we're inserting a new leaf
        DebugHelper.Assert(m_nodes[leafNodeIndex].m_parentNodeIndex == NullIndex);
        DebugHelper.Assert(m_nodes[leafNodeIndex].m_leftNodeIndex == NullIndex);
        DebugHelper.Assert(m_nodes[leafNodeIndex].m_rightNodeIndex == NullIndex);

        // if the tree is empty then we make the root the leaf
        if (m_rootNodeIndex == NullIndex)
        {
            m_rootNodeIndex = leafNodeIndex;
            return;
        }

        // search for the best place to put the new leaf in the tree
        // we use surface area and depth as search heuristics
        int          treeNodeIndex = m_rootNodeIndex;
        AABBTreeNode leafNode      = m_nodes[leafNodeIndex];

        while (!m_nodes[treeNodeIndex].IsLeaf())
        {
            // because of the test in the while loop above we know we are never a leaf inside it
            AABBTreeNode treeNode       = m_nodes[treeNodeIndex];
            int          leftNodeIndex  = treeNode.m_leftNodeIndex;
            int          rightNodeIndex = treeNode.m_rightNodeIndex;
            AABBTreeNode leftNode       = m_nodes[leftNodeIndex];
            AABBTreeNode rightNode      = m_nodes[rightNodeIndex];

            AABB3d combinedAabb = treeNode.m_bounds.Merge(leafNode.m_bounds);

            FloatL newParentNodeCost   = 2.0f * combinedAabb.CalculateSurfaceArea();
            FloatL minimumPushDownCost = 2.0f * (combinedAabb.CalculateSurfaceArea() - treeNode.m_bounds.CalculateSurfaceArea());

            // use the costs to figure out whether to create a new parent here or descend
            FloatL costLeft;
            FloatL costRight;
            if (leftNode.IsLeaf())
            {
                costLeft = leafNode.m_bounds.Merge(leftNode.m_bounds).CalculateSurfaceArea() + minimumPushDownCost;
            }
            else
            {
                AABB3d newLeftAabb = leafNode.m_bounds.Merge(leftNode.m_bounds);
                costLeft = (newLeftAabb.CalculateSurfaceArea() - leftNode.m_bounds.CalculateSurfaceArea()) + minimumPushDownCost;
            }
            if (rightNode.IsLeaf())
            {
                costRight = leafNode.m_bounds.Merge(rightNode.m_bounds).CalculateSurfaceArea() + minimumPushDownCost;
            }
            else
            {
                AABB3d newRightAabb = leafNode.m_bounds.Merge(rightNode.m_bounds);
                costRight = (newRightAabb.CalculateSurfaceArea() - rightNode.m_bounds.CalculateSurfaceArea()) + minimumPushDownCost;
            }

            // if the cost of creating a new parent node here is less than descending in either direction then
            // we know we need to create a new parent node, errrr, here and attach the leaf to that
            if (newParentNodeCost < costLeft && newParentNodeCost < costRight)
            {
                break;
            }

            // otherwise descend in the cheapest direction
            if (costLeft < costRight)
            {
                treeNodeIndex = leftNodeIndex;
            }
            else
            {
                treeNodeIndex = rightNodeIndex;
            }
        }

        // the leafs sibling is going to be the node we found above and we are going to create a new
        // parent node and attach the leaf and this item
        int          leafSiblingIndex = treeNodeIndex;
        AABBTreeNode leafSibling      = m_nodes[leafSiblingIndex];
        int          oldParentIndex   = leafSibling.m_parentNodeIndex;
        int          newParentIndex   = AllocateNode();
        AABBTreeNode newParent        = m_nodes[newParentIndex];

        newParent.m_parentNodeIndex   = oldParentIndex;
        newParent.m_bounds            = leafNode.m_bounds.Merge(leafSibling.m_bounds); // the new parents aabb is the leaf aabb combined with it's siblings aabb
        newParent.m_leftNodeIndex     = leafSiblingIndex;
        newParent.m_rightNodeIndex    = leafNodeIndex;
        leafNode.m_parentNodeIndex    = newParentIndex;
        leafSibling.m_parentNodeIndex = newParentIndex;

        if (oldParentIndex == NullIndex)
        {
            // the old parent was the root and so this is now the root
            m_rootNodeIndex = newParentIndex;
        }
        else
        {
            // the old parent was not the root and so we need to patch the left or right index to
            // point to the new node
            AABBTreeNode oldParent = m_nodes[oldParentIndex];
            if (oldParent.m_leftNodeIndex == leafSiblingIndex)
            {
                oldParent.m_leftNodeIndex = newParentIndex;
            }
            else
            {
                oldParent.m_rightNodeIndex = newParentIndex;
            }
        }

        // finally we need to walk back up the tree fixing heights and areas
        treeNodeIndex = leafNode.m_parentNodeIndex;
        FixUpwardsTree(treeNodeIndex);
    }