/// <summary> /// Constructor for the bounds octree. /// </summary> /// <param name="initialWorldSize">Size of the sides of the initial node, in metres. The octree will never shrink smaller than this.</param> /// <param name="initialWorldPos">Position of the centre of the initial node.</param> /// <param name="minNodeSize">Nodes will stop splitting if the new nodes would be smaller than this (metres).</param> /// <param name="loosenessVal">Clamped between 1 and 2. Values > 1 let nodes overlap.</param> public BoundsOctree(float initialWorldSize, Vector3d initialWorldPos, float minNodeSize, float loosenessVal) { if (minNodeSize > initialWorldSize) { //Debug.LogWarning("Minimum node size must be at least as big as the initial world size. Was: " + minNodeSize + " Adjusted to: " + initialWorldSize); minNodeSize = initialWorldSize; } Count = 0; initialSize = initialWorldSize; minSize = minNodeSize; //looseness = Mathf.Clamp(loosenessVal, 1.0f, 2.0f); looseness = looseness.Clamp(1.0f, 2.0f); rootNode = new BoundsOctreeNode <T>(initialSize, minSize, loosenessVal, initialWorldPos); }
/// <summary> /// Splits the octree into eight children. /// </summary> void Split() { float quarter = BaseLength / 4f; float newLength = BaseLength / 2; children = new BoundsOctreeNode <T> [8]; children[0] = new BoundsOctreeNode <T>(newLength, minSize, looseness, Center + new Vector3d(-quarter, quarter, -quarter)); children[1] = new BoundsOctreeNode <T>(newLength, minSize, looseness, Center + new Vector3d(quarter, quarter, -quarter)); children[2] = new BoundsOctreeNode <T>(newLength, minSize, looseness, Center + new Vector3d(-quarter, quarter, quarter)); children[3] = new BoundsOctreeNode <T>(newLength, minSize, looseness, Center + new Vector3d(quarter, quarter, quarter)); children[4] = new BoundsOctreeNode <T>(newLength, minSize, looseness, Center + new Vector3d(-quarter, -quarter, -quarter)); children[5] = new BoundsOctreeNode <T>(newLength, minSize, looseness, Center + new Vector3d(quarter, -quarter, -quarter)); children[6] = new BoundsOctreeNode <T>(newLength, minSize, looseness, Center + new Vector3d(-quarter, -quarter, quarter)); children[7] = new BoundsOctreeNode <T>(newLength, minSize, looseness, Center + new Vector3d(quarter, -quarter, quarter)); }
/// <summary> /// Merge all children into this node - the opposite of Split. /// Note: We only have to check one level down since a merge will never happen if the children already have children, /// since THAT won't happen unless there are already too many objects to merge. /// </summary> void Merge() { // Note: We know children != null or we wouldn't be merging for (int i = 0; i < 8; i++) { BoundsOctreeNode <T> curChild = children[i]; int numObjects = curChild.objects.Count; for (int j = numObjects - 1; j >= 0; j--) { OctreeObject curObj = curChild.objects[j]; objects.Add(curObj); } } // Remove the child nodes (and the objects in them - they've been added elsewhere now) children = null; }
/// <summary> /// Grow the octree to fit in all objects. /// </summary> /// <param name="direction">Direction to grow.</param> void Grow(Vector3d direction) { int xDirection = direction.X >= 0 ? 1 : -1; int yDirection = direction.Y >= 0 ? 1 : -1; int zDirection = direction.Z >= 0 ? 1 : -1; BoundsOctreeNode <T> oldRoot = rootNode; float half = rootNode.BaseLength / 2; float newLength = rootNode.BaseLength * 2; Vector3d newCenter = rootNode.Center + new Vector3d(xDirection * half, yDirection * half, zDirection * half); // Create a new, bigger octree root node rootNode = new BoundsOctreeNode <T>(newLength, minSize, looseness, newCenter); if (oldRoot.HasAnyObjects()) { // Create 7 new octree children to go with the old root as children of the new root int rootPos = GetRootPosIndex(xDirection, yDirection, zDirection); BoundsOctreeNode <T>[] children = new BoundsOctreeNode <T> [8]; for (int i = 0; i < 8; i++) { if (i == rootPos) { children[i] = oldRoot; } else { xDirection = i % 2 == 0 ? -1 : 1; yDirection = i > 3 ? -1 : 1; zDirection = (i < 2 || (i > 3 && i < 6)) ? -1 : 1; children[i] = new BoundsOctreeNode <T>(rootNode.BaseLength, minSize, looseness, newCenter + new Vector3d(xDirection * half, yDirection * half, zDirection * half)); } } // Attach the new children to the new root node rootNode.SetChildren(children); } }
/// <summary> /// Shrink the octree if possible, else leave it the same. /// </summary> void Shrink() { rootNode = rootNode.ShrinkIfPossible(initialSize); }