//Recursively search the tree and for each leaf node at the bottom depth populate it's //SDF structure by raycasting to all Scene Geometry and find the closest Surface Point void PopulateTree(Octree.OctreeNode node) { if (!node.IsLeaf()) { var subNodes = node.Nodes; foreach (var subNode in subNodes) { PopulateTree(subNode); } } else { if (node.IsLowestNode()) { //find the closest Surface Point to this Mesh //Unity 5.7 has Physics.ClosestPoint(Vec3 p) //This is my version of it //Vector3 surfacePoint_old = ClosesPointOnCollider(node.Position); Vector3 surfacePoint = ClosesPointOnColliders(node.Position); if (surfacePoint == node.Position) { node.InsideMesh = true; } else { node.InsideMesh = false; node.SDF.mPoint = surfacePoint; node.SDF.mDistance = (surfacePoint - node.Position).magnitude; } } } }
//===================================================================================================================== //This initializes this Octree //===================================================================================================================== void Build_Octree() { RayDirs = PointsOnSphere.GetPoints((float)RayDirections); //First step all Scene geometry send their Meshes to the Octree class if (Octree.All_OBBs == null) { Octree.All_OBBs = new List <Octree.OBB>(); } if (Unpacked_Tree == null) { Unpacked_Tree = new List <TreeNode>(); } //send all scene Geometry(AABBs) to the Octree class StreamGeometry(); //Create a new Octree only ONCE this is not a dynamic scene!!!! OCTREE = new Octree(transform.position, VoxelSize, TreeDepth); Octree.OctreeNode root = OCTREE.GetRootNode(); //Now for each Leaf node at the bottom of the Tree populate it //ie. Find the closest Surface geometry to it and populate its SDF structure PopulateTree(root); //Structure the Octree into a single list of tree nodes UnpackTree(root); //Finaly Step: Store the UnpackedOctree into a linear Array(ComputeBuffer) PackTree(); Initialized = true; }
/// <summary> /// Renders node gizmos /// </summary> private void OnDrawGizmos() { if (!renderGizmos) { return; } foreach (GameObject g in gameObjectPoints) { Vector3 coordinate = octree.GetRoot().FindCoordinateOnOctree(g.transform.position - globalOffset); Octree.OctreeNode oc = octree.GetRoot().GetNodeAtCoordinate(coordinate); int distance = Distance(lastCoordinatePosition, coordinate); if (distance == 0) { Gizmos.color = new Color(1, 0, 0, 1f); } else if (distance == 1) { Gizmos.color = new Color(0, 1, 0, 1f); } else { Gizmos.color = new Color(0, 0, 1, 1f); } Gizmos.DrawWireCube(oc.Position + globalOffset, new Vector3(octree.smallestTile, octree.smallestTile, octree.smallestTile)); } //Gizmos.DrawWireCube(origin, max - min); }
//Linearly search the Unpacked Tree to find this nodes index int FindIndex(Octree.OctreeNode node, ref List <TreeNode> tree) { int index = -1; for (index = 0; index < tree.Count; ++index) { if (tree[index].mNode == node) { return(index); } } return(-1); }
//recursively go through the Octree and convert them into a simple structure void UnpackTree(Octree.OctreeNode node) { TreeNode current = new TreeNode(); var subNodes = node.Nodes; //set this up current.mParent = node.Parent; current.mNode = node; int i = 0; if (subNodes != null) { current.mChildren = new Octree.OctreeNode[8]; foreach (var subNode in subNodes) { current.mChildren[i] = subNode; ++i; } } else { current.mChildren = null; } //assign this node to our array only if It's not inside a mesh if (!current.mNode.InsideMesh) { Unpacked_Tree.Add(current); } //if this Node has children recurse if (!node.IsLeaf()) { foreach (var subNode in subNodes) { UnpackTree(subNode); } } }
//Final step Get the Unpacked tree and then pack it into a linear Buffer void PackTree() { //the unpacked Tree is recursively built so we have to turn it into a linear list here before we copy it with proper //indexing into the final LinearList below List <TreeNode> LinearUnpackedTree = new List <TreeNode>(); for (int i = 0; i < Unpacked_Tree.Count - 1; ++i) //ignore last node some reason the recursion f***s up when adding an extra garbage node { LinearUnpackedTree.Add(Unpacked_Tree[i]); } Unpacked_Tree.Clear(); //Go through the unpacked tree and build it linearly List <SDF_Node> LinearList = new List <SDF_Node>(); for (int i = 0; i < LinearUnpackedTree.Count; ++i) { SDF_Node current = new SDF_Node(); Octree.OctreeNode node = LinearUnpackedTree[i].mNode; Vector3 p = node.Position; float s = node.SDF.mSize; current.Min.x = p.x - s; current.Min.y = p.y - s; current.Min.z = p.z - s; current.Max.x = p.x + s; current.Max.y = p.y + s; current.Max.z = p.z + s; current.index = i; current.SurfacePoint = node.SDF.mPoint; if (LinearUnpackedTree[i].mChildren != null) { current.c0 = FindIndex(LinearUnpackedTree[i].mChildren[0], ref LinearUnpackedTree); current.c1 = FindIndex(LinearUnpackedTree[i].mChildren[1], ref LinearUnpackedTree); current.c2 = FindIndex(LinearUnpackedTree[i].mChildren[2], ref LinearUnpackedTree); current.c3 = FindIndex(LinearUnpackedTree[i].mChildren[3], ref LinearUnpackedTree); current.c4 = FindIndex(LinearUnpackedTree[i].mChildren[4], ref LinearUnpackedTree); current.c5 = FindIndex(LinearUnpackedTree[i].mChildren[5], ref LinearUnpackedTree); current.c6 = FindIndex(LinearUnpackedTree[i].mChildren[6], ref LinearUnpackedTree); current.c7 = FindIndex(LinearUnpackedTree[i].mChildren[7], ref LinearUnpackedTree); } else { current.c0 = -1; current.c1 = -1; current.c2 = -1; current.c3 = -1; current.c4 = -1; current.c5 = -1; current.c6 = -1; current.c7 = -1; } LinearList.Add(current); } //used to set a ComputeBuffer later on nodeArray = LinearList.ToArray(); }