private void CreateNewNeighbourSuperVoxelTree(Node neighbourNode, NeighbourSide side) { var myBounds = GetBounds(); var neighbourBounds = neighbourNode.GetBounds(); Assert.AreEqual(neighbourBounds.extents, myBounds.extents); var myItem = GetItem(); var myVoxelTree = myItem; if (myVoxelTree == null) { return; } var neighbourVoxelTree = new VoxelTree(neighbourBounds.center, neighbourBounds.size, false); var originalGameObject = myVoxelTree.GetGameObject(); Assert.IsNotNull(originalGameObject, "Original game object should not be null!"); var newGameObject = new GameObject(side + " neighbour for " + originalGameObject.name); newGameObject.transform.SetParent(originalGameObject.transform, false); neighbourVoxelTree.SetOwnerNode(neighbourNode); neighbourVoxelTree.SetGameObject(newGameObject); neighbourVoxelTree.CopyPropertiesFrom(myVoxelTree); neighbourNode.SetItem(neighbourVoxelTree); }
private static OctreeChildCoords[] GetChildCoordsOfSide(NeighbourSide side) { OctreeChildCoords[] childCoords; switch (side) { case NeighbourSide.Above: childCoords = AboveCoords; break; case NeighbourSide.Below: childCoords = BelowCoords; break; case NeighbourSide.Right: childCoords = RightCoords; break; case NeighbourSide.Left: childCoords = LeftCoords; break; case NeighbourSide.Back: childCoords = BackCoords; break; case NeighbourSide.Forward: childCoords = ForwardCoords; break; default: throw new ArgumentOutOfRangeException("side", side, null); } return childCoords; }
private void CreateFacesForSideInternal(ICollection<OctreeRenderFace> faces, NeighbourSide side, Bounds currentBounds, Coords coords, int meshIndex, bool parentPartial = false) { AssertNotDeleted(); var sidestate = GetSideState(coords, side); switch (sidestate) { case SideState.FullButTransparent: if (!hasItem || !IsTransparent()) { AddFaceToList(faces, side, currentBounds, meshIndex); } break; case SideState.Empty: AddFaceToList(faces, side, currentBounds, meshIndex); break; case SideState.PartialButTransparent: if (IsTransparent()) { AddPartialFaces(faces, side, currentBounds, coords, meshIndex, parentPartial); } else { AddFaceToList(faces, side, currentBounds, meshIndex); } break; case SideState.Partial: AddPartialFaces(faces, side, currentBounds, coords, meshIndex, parentPartial); break; case SideState.Full: break; default: throw new ArgumentOutOfRangeException(); } }
private static ChildIndex GetWantedIndexInParent(NeighbourSide sideToGrowTowards) { switch (sideToGrowTowards) { case NeighbourSide.Above: case NeighbourSide.Right: case NeighbourSide.Forward: return(ChildIndex.LeftBelowBack); case NeighbourSide.Left: return(ChildIndex.RightBelowBack); case NeighbourSide.Back: return(ChildIndex.LeftBelowForward); case NeighbourSide.Below: return(ChildIndex.LeftAboveBack); case NeighbourSide.Invalid: throw new ArgumentOutOfRangeException("sideToGrowTowards", sideToGrowTowards, null); default: throw new ArgumentOutOfRangeException("sideToGrowTowards", sideToGrowTowards, null); } }
public static NeighbourSide GetOpposite(NeighbourSide side) { switch (side) { case NeighbourSide.Above: return(NeighbourSide.Below); case NeighbourSide.Below: return(NeighbourSide.Above); case NeighbourSide.Right: return(NeighbourSide.Left); case NeighbourSide.Left: return(NeighbourSide.Right); case NeighbourSide.Back: return(NeighbourSide.Forward); case NeighbourSide.Forward: return(NeighbourSide.Back); default: throw new ArgumentOutOfRangeException("side", side, null); } }
private SuperVoxelTree ExpandRootAndReturnTree(NeighbourSide side, bool isReadOnly) { if (!GetRoot().CreateParentTowardsSide(side, isReadOnly)) { return(null); } return(ocTree); }
public RayIntersectionResult(bool hit) { this.hit = hit; node = null; _coords = new Coords(); entryDistance = 0; position = new Vector3(); normal = new Vector3(); neighbourSide = NeighbourSide.Invalid; tree = null; }
private VoxelTree GetOrCreateNeighbour(NeighbourSide side, bool readOnly) { var ownerNeighbour = _ownerNode.GetOrCreateNeighbour(side, readOnly); if (ownerNeighbour == null) { return(null); } return(ownerNeighbour.GetItem()); }
public Node GetOrCreateNeighbour(NeighbourSide side, bool readOnly) { if (!CreateParentTowardsSide(side, readOnly)) { return(null); } // //// var neighbourCoords = //// VoxelTree.GetNeighbourCoords(new Coords(new[] {OctreeChildCoords.FromIndex(_indexInParent)}), side); // //// if (neighbourCoords == null) { // // uh oh, gotta go further // // cases: // length 0: not gonna happen. // not at edge, if parent was null, we get neighbour Coords result. // at edge: ?? var neighbourCoordsInfinite = GetNeighbourCoordsInfinite(ocTree, GetCoords(), side, ExpandRootAndReturnTree); if (neighbourCoordsInfinite == null) { throw new Exception("Neighbour coords are null!"); } else { var neighbourCoordsResult = neighbourCoordsInfinite.Value; var neighbourCoords = neighbourCoordsResult.coordsResult; var root = GetRoot(); var neighbour = root.GetChildAtCoords(neighbourCoords); if (neighbour == null) { if (readOnly) { return(null); } neighbour = root.AddRecursive(neighbourCoords, false); CreateNewNeighbourSuperVoxelTree(neighbour, side); } return(neighbour); } }
public RayIntersectionResult(IOctree tree, INode node, Coords coords, float entryDistance, Vector3 position, Vector3 normal, NeighbourSide neighbourSide) { hit = true; this.tree = tree; this.node = node; _coords = coords; this.entryDistance = entryDistance; this.position = position; this.normal = normal; this.neighbourSide = neighbourSide; }
private static bool IsBetweenSameWords(string[] words, int index, NeighbourSide side) { if (side == NeighbourSide.Right) { return(false); } var neighbourIndex = index - 2; if (neighbourIndex < 0) { return(false); } return(words[index] == words[neighbourIndex]); }
protected Bounds GetNeighbourBounds(NeighbourSide side) { var rootBounds = GetRoot().GetBounds(); var center = rootBounds.center; var size = rootBounds.size; switch (side) { case NeighbourSide.Above: center += Vector3.up * size.y; break; case NeighbourSide.Below: center += Vector3.down * size.y; break; case NeighbourSide.Right: center += Vector3.right * size.x; break; case NeighbourSide.Left: center += Vector3.left * size.x; break; case NeighbourSide.Back: center += Vector3.back * size.z; break; case NeighbourSide.Forward: center += Vector3.forward * size.z; break; case NeighbourSide.Invalid: break; default: throw new ArgumentOutOfRangeException("side", side, null); } var neighbourBounds = new Bounds(center, size); return(neighbourBounds); }
private void AddPartialFaces(ICollection<OctreeRenderFace> faces, NeighbourSide side, Bounds currentBounds, Coords coords, int meshIndex, bool parentPartial) { if (IsTransparent() && !parentPartial) { var childCoords = GetChildCoordsOfSide(side); // ReSharper disable once ForCanBeConvertedToForeach for (var i = 0; i < childCoords.Length; i++) { var childCoord = childCoords[i]; var childBounds = GetChildBoundsInternal(currentBounds, childCoord.ToIndex()); var childAbsCoords = new Coords(coords, childCoord); // var _coords = new Coords(); CreateFacesForSideInternal(faces, side, childBounds, childAbsCoords, meshIndex); } } else { AddFaceToList(faces, side, currentBounds, meshIndex); } }
public Bounds GetNeighbourBoundsForChild(Coords coords, NeighbourSide neighbourSide) { var childBounds = GetRoot().GetChildBounds(coords); Vector3 sideDirection; switch (neighbourSide) { case NeighbourSide.Above: sideDirection = Vector3.up; break; case NeighbourSide.Below: sideDirection = Vector3.down; break; case NeighbourSide.Right: sideDirection = Vector3.right; break; case NeighbourSide.Left: sideDirection = Vector3.left; break; case NeighbourSide.Back: sideDirection = Vector3.back; break; case NeighbourSide.Forward: sideDirection = Vector3.forward; break; case NeighbourSide.Invalid: throw new ArgumentOutOfRangeException("neighbourSide", neighbourSide, null); default: throw new ArgumentOutOfRangeException("neighbourSide", neighbourSide, null); } return(new Bounds(childBounds.center + Vector3.Scale(sideDirection, childBounds.size), childBounds.size)); }
private bool CreateParentTowardsSide(NeighbourSide side, bool readOnly) { if (parent == null) { // we're the root if (readOnly) { return(false); } var wantedIndexInParent = GetWantedIndexInParent(side); parent = new Node(CreateParentBounds(wantedIndexInParent), ocTree); ocTree.SetRoot(parent); indexInParent = wantedIndexInParent; parent.ReplaceChild(wantedIndexInParent, this); } return(true); }
private bool SideSolid(NeighbourSide side) { return _sideSolidCount != null && _sideSolidCount[side] > 0; }
private static bool NeedSkip(string[] words, int index, NeighbourSide side) { var neighbourIndex = side == NeighbourSide.Left ? index - 1 : index + 1; return(NeedSkip(words, index, neighbourIndex) || IsBetweenSameWords(words, index, side)); }
protected static void GetNeighbourSides(ChildIndex childIndex, out NeighbourSide verticalSide, out NeighbourSide horizontalSide, out NeighbourSide depthSide) { switch (childIndex) { case ChildIndex.Invalid: // self verticalSide = NeighbourSide.Invalid; horizontalSide = NeighbourSide.Invalid; depthSide = NeighbourSide.Invalid; break; case ChildIndex.LeftBelowBack: verticalSide = NeighbourSide.Below; depthSide = NeighbourSide.Back; horizontalSide = NeighbourSide.Left; break; case ChildIndex.RightBelowBack: verticalSide = NeighbourSide.Below; depthSide = NeighbourSide.Back; horizontalSide = NeighbourSide.Right; break; case ChildIndex.LeftAboveBack: verticalSide = NeighbourSide.Above; depthSide = NeighbourSide.Back; horizontalSide = NeighbourSide.Left; break; case ChildIndex.RightAboveBack: verticalSide = NeighbourSide.Above; depthSide = NeighbourSide.Back; horizontalSide = NeighbourSide.Right; break; case ChildIndex.LeftBelowForward: verticalSide = NeighbourSide.Below; depthSide = NeighbourSide.Forward; horizontalSide = NeighbourSide.Left; break; case ChildIndex.RightBelowForward: verticalSide = NeighbourSide.Below; depthSide = NeighbourSide.Forward; horizontalSide = NeighbourSide.Right; break; case ChildIndex.LeftAboveForward: verticalSide = NeighbourSide.Above; depthSide = NeighbourSide.Forward; horizontalSide = NeighbourSide.Left; break; case ChildIndex.RightAboveForward: verticalSide = NeighbourSide.Above; depthSide = NeighbourSide.Forward; horizontalSide = NeighbourSide.Right; break; default: throw new ArgumentOutOfRangeException("childIndex", childIndex, null); } }
private SideState GetSideState(Coords coords, NeighbourSide side) { AssertNotDeleted(); var neighbourCoordsInfinite = GetTree().GetNeighbourCoordsInfinite(coords, side, true); //out of the boundaries if (neighbourCoordsInfinite == null) { return SideState.Empty; } else { var neighbourCoordsResult = neighbourCoordsInfinite.Value; #if USE_ALL_NODES OctreeNode<T> neighbourNode; if (_allNodes.TryGetValue(neighbourCoords.GetHashCode(), out neighbourNode)) { if (neighbourNode.IsLeafNode()) { return neighbourNode.HasItem() ? SideState.Full : SideState.Empty; } // not null and not leaf, so the neighbour node must be partial SideState sideState; if (neighbourNode.SideSolid(GetOpposite(side))) { // if the opposite side of current node is solid, then this is a partial node. sideState = SideState.Partial; } else { sideState = SideState.Empty; } return sideState; } // that child doesn't exist //let's check the parents while (neighbourCoords.Length > 0) { // get the next parent neighbourCoords = neighbourCoords.GetParentCoords(); //does the next parent exist? if (!_allNodes.TryGetValue(neighbourCoords.GetHashCode(), out neighbourNode)) { continue; } if (neighbourNode.IsDeleted()) { continue; } // is the parent a leaf? if (neighbourNode.IsLeafNode()) { return neighbourNode.HasItem() ? SideState.Full : SideState.Empty; } // is not a leaf so cannot have an item break; } return SideState.Empty; #else // if (neighbourCoords.GetTree() == null) { // return SideState.Empty; // } var currentNode = (VoxelNode) neighbourCoordsResult.tree.GetRoot(); // neighbourCoords.GetTree().GetRoot(); // follow the children until you get to the node foreach (var coord in neighbourCoordsResult.coordsResult) { if (currentNode == null) { return SideState.Empty; } if (currentNode.IsLeafNode()) { if (currentNode.HasItem()) { if (currentNode.IsTransparent()) { return SideState.FullButTransparent; } return SideState.Full; } else { return SideState.Empty; } } currentNode = currentNode.GetChild(coord.ToIndex()); } //last currentNode is the actual node at the neighbour Coords if (currentNode == null) { return SideState.Empty; } if (currentNode.IsLeafNode()) { if (currentNode.HasItem()) { if (currentNode.IsTransparent()) { return SideState.FullButTransparent; } return SideState.Full; } else { return SideState.Empty; } } // not null and not leaf, so it must be partial // try to recursively get all nodes on this side SideState sideState; if (currentNode.SideSolid(GetOpposite(side))) { if (currentNode.SideTransparent(side)) { sideState = SideState.PartialButTransparent; } else { // if the opposite side of current node is solid, then this is a partial node. sideState = SideState.Partial; } } else { sideState = SideState.Empty; } return sideState; } #endif }
public IEnumerable<VoxelNode> GetAllSolidNeighbours(NeighbourSide side) { var neighbourCoordsInfinite = GetTree().GetNeighbourCoordsInfinite(GetCoords(), side, true); //out of the map! if (neighbourCoordsInfinite == null) { return null; } else { var neighbourCoordsResult = neighbourCoordsInfinite.Value; #if USE_ALL_NODES OctreeNode<T> neighbourNode; if (_allNodes.TryGetValue(neighbourCoords.GetHashCode(), out neighbourNode)) { if (neighbourNode.IsSolid()) { return new HashSet<OctreeNode<T>> {neighbourNode}; } return neighbourNode._sideSolidChildren[GetOpposite(side)]; } // that child doesn't exist //let's check the parents while (neighbourCoords.Length > 0) { // get the next parent neighbourCoords = neighbourCoords.GetParentCoords(); //does the next parent exist? if (!_allNodes.TryGetValue(neighbourCoords.GetHashCode(), out neighbourNode)) { continue; } // is the parent a leaf? if (neighbourNode.IsSolid()) { return new HashSet<OctreeNode<T>> {neighbourNode}; } // is not a leaf so cannot have an item break; } return null; #else // if (neighbourCoords.GetTree() == null) { // return null; // } var currentNeighbourNode = (VoxelNode) neighbourCoordsResult.tree.GetRoot(); foreach (var coord in neighbourCoordsResult.coordsResult) { if (currentNeighbourNode == null || currentNeighbourNode.IsDeleted()) { return null; } if (currentNeighbourNode.IsSolid()) { return new HashSet<VoxelNode> {currentNeighbourNode}; } currentNeighbourNode = currentNeighbourNode.GetChild(coord.ToIndex()); } // last currentNode is the actual node at the neighbour Coords if (currentNeighbourNode == null || currentNeighbourNode.IsDeleted()) { return null; } if (currentNeighbourNode.IsSolid()) { return new HashSet<VoxelNode> {currentNeighbourNode}; } return currentNeighbourNode._sideSolidChildren[GetOpposite(side)]; } #endif }
private void CreateFacesForSideInternal(NeighbourSide side, int meshIndex, ICollection<OctreeRenderFace> faces) { CreateFacesForSideInternal(faces, side, bounds, GetCoords(), meshIndex); }
private static void AddFaceToList(ICollection<OctreeRenderFace> faces, NeighbourSide side, Bounds bounds, int meshIndex) { var face = new OctreeRenderFace(meshIndex); var min = bounds.min; var max = bounds.max; Vector3 n; switch (side) { case NeighbourSide.Above: face.vertices[0] = new Vector3(min.x, max.y, min.z); face.vertices[1] = new Vector3(min.x, max.y, max.z); face.vertices[2] = max; face.vertices[3] = new Vector3(max.x, max.y, min.z); n = Vector3.up; face.uvs[0] = new Vector2(min.x, min.z); face.uvs[1] = new Vector2(min.x, max.z); face.uvs[2] = new Vector2(max.x, max.z); face.uvs[3] = new Vector2(max.x, min.z); break; case NeighbourSide.Below: face.vertices[0] = new Vector3(min.x, min.y, max.z); face.vertices[1] = min; face.vertices[2] = new Vector3(max.x, min.y, min.z); face.vertices[3] = new Vector3(max.x, min.y, max.z); n = Vector3.down; face.uvs[0] = new Vector2(min.x, max.z); face.uvs[1] = new Vector2(min.x, min.z); face.uvs[2] = new Vector2(max.x, min.z); face.uvs[3] = new Vector2(max.x, max.z); break; case NeighbourSide.Left: face.vertices[0] = new Vector3(min.x, min.y, max.z); face.vertices[1] = new Vector3(min.x, max.y, max.z); face.vertices[2] = new Vector3(min.x, max.y, min.z); face.vertices[3] = min; n = Vector3.left; face.uvs[0] = new Vector2(max.z, min.y); face.uvs[1] = new Vector2(max.z, max.y); face.uvs[2] = new Vector2(min.z, max.y); face.uvs[3] = new Vector2(min.z, min.y); break; case NeighbourSide.Right: face.vertices[0] = new Vector3(max.x, min.y, min.z); face.vertices[1] = new Vector3(max.x, max.y, min.z); face.vertices[2] = max; face.vertices[3] = new Vector3(max.x, min.y, max.z); n = Vector3.right; face.uvs[0] = new Vector2(min.z, min.y); face.uvs[1] = new Vector2(min.z, max.y); face.uvs[2] = new Vector2(max.z, max.y); face.uvs[3] = new Vector2(max.z, min.y); break; case NeighbourSide.Forward: face.vertices[0] = new Vector3(max.x, min.y, max.z); face.vertices[1] = max; face.vertices[2] = new Vector3(min.x, max.y, max.z); face.vertices[3] = new Vector3(min.x, min.y, max.z); n = Vector3.forward; face.uvs[0] = new Vector2(max.x, min.y); face.uvs[1] = new Vector2(max.x, max.y); face.uvs[2] = new Vector2(min.x, max.y); face.uvs[3] = new Vector2(min.x, min.y); break; case NeighbourSide.Back: face.vertices[0] = min; face.vertices[1] = new Vector3(min.x, max.y, min.z); face.vertices[2] = new Vector3(max.x, max.y, min.z); face.vertices[3] = new Vector3(max.x, min.y, min.z); n = Vector3.back; face.uvs[0] = new Vector2(min.x, min.y); face.uvs[1] = new Vector2(min.x, max.y); face.uvs[2] = new Vector2(max.x, max.y); face.uvs[3] = new Vector2(max.x, min.y); break; default: throw new ArgumentOutOfRangeException("side", side, null); } face.normal = n; faces.Add(face); }
public static Coords?GetNeighbourCoords(Coords coords, NeighbourSide side) { // var voxelTree = GetTree(); var coordsLength = coords.Length; if (coordsLength <= 0) { // get the neighbour tree? return(null); } var newCoords = new OctreeChildCoords[coordsLength]; var hasLastCoords = false; var lastCoordX = 0; var lastCoordY = 0; var lastCoordZ = 0; for (var i = coordsLength - 1; i >= 0; --i) { var coord = coords.GetCoord(i); var currentX = coord.x; var currentY = coord.y; var currentZ = coord.z; if (hasLastCoords) { //let's check the lower _coords, if it's out of that bounds then we need to modify ourselves! var lastCoordUpdated = UpdateLastCoord( ref lastCoordX, ref currentX, ref lastCoordY, ref currentY, ref lastCoordZ, ref currentZ); if (lastCoordUpdated) { newCoords[i + 1] = new OctreeChildCoords(lastCoordX, lastCoordY, lastCoordZ); } } else { //final _coords! //update _coords from the side switch (side) { case NeighbourSide.Above: currentY += 1; break; case NeighbourSide.Below: currentY -= 1; break; case NeighbourSide.Right: currentX += 1; break; case NeighbourSide.Left: currentX -= 1; break; case NeighbourSide.Back: currentZ -= 1; break; case NeighbourSide.Forward: currentZ += 1; break; default: throw new ArgumentOutOfRangeException("side", side, null); } } var newCoord = new OctreeChildCoords(currentX, currentY, currentZ); newCoords[i] = newCoord; lastCoordX = currentX; lastCoordY = currentY; lastCoordZ = currentZ; hasLastCoords = true; } // we're at the end now if (hasLastCoords && (lastCoordX < 0 || lastCoordX > 1 || lastCoordY < 0 || lastCoordY > 1 || lastCoordZ < 0 || lastCoordZ > 1)) { return(null); } return(new Coords(newCoords)); }
protected static NeighbourCoordsResult?GetNeighbourCoordsInfinite(TTree tree, Coords coords, NeighbourSide side, Func <NeighbourSide, bool, TTree> getOrCreateNeighbour, bool readOnly = false) { var coordsLength = coords.Length; if (coordsLength == 0) { var neighbourTree = getOrCreateNeighbour(side, readOnly); if (neighbourTree == null) { return(null); } // get the neighbour tree? return(new NeighbourCoordsResult(false, coords, neighbourTree)); } var newCoords = new OctreeChildCoords[coordsLength]; var hasLastCoords = false; var lastCoordX = 0; var lastCoordY = 0; var lastCoordZ = 0; for (var i = coordsLength - 1; i >= 0; --i) { var coord = coords.GetCoord(i); var currentX = coord.x; var currentY = coord.y; var currentZ = coord.z; if (hasLastCoords) { //let's check the lower _coords, if it's out of that bounds then we need to modify ourselves! var lastCoordUpdated = UpdateLastCoord( ref lastCoordX, ref currentX, ref lastCoordY, ref currentY, ref lastCoordZ, ref currentZ); if (lastCoordUpdated) { newCoords[i + 1] = new OctreeChildCoords(lastCoordX, lastCoordY, lastCoordZ); } } else { //final _coords! //update _coords from the side switch (side) { case NeighbourSide.Above: currentY += 1; break; case NeighbourSide.Below: currentY -= 1; break; case NeighbourSide.Right: currentX += 1; break; case NeighbourSide.Left: currentX -= 1; break; case NeighbourSide.Back: currentZ -= 1; break; case NeighbourSide.Forward: currentZ += 1; break; default: throw new ArgumentOutOfRangeException("side", side, null); } } var newCoord = new OctreeChildCoords(currentX, currentY, currentZ); newCoords[i] = newCoord; lastCoordX = currentX; lastCoordY = currentY; lastCoordZ = currentZ; hasLastCoords = true; } // we're at the end now if (hasLastCoords && (lastCoordX < 0 || lastCoordX > 1 || lastCoordY < 0 || lastCoordY > 1 || lastCoordZ < 0 || lastCoordZ > 1)) { //invalid _coords, out of bounds, pick neighbour voxelTree var neighbourTree = getOrCreateNeighbour(side, readOnly); if (neighbourTree == null) { return(null); } var currentX = lastCoordX; var currentY = lastCoordY; var currentZ = lastCoordZ; UpdateLastCoord(ref lastCoordX, ref currentX, ref lastCoordY, ref currentY, ref lastCoordZ, ref currentZ); newCoords[0] = new OctreeChildCoords(lastCoordX, lastCoordY, lastCoordZ); return(new NeighbourCoordsResult(false, new Coords(newCoords), neighbourTree)); } return(new NeighbourCoordsResult(true, new Coords(newCoords), tree)); }
private bool SideTransparent(NeighbourSide side) { return _sideTransparentCount != null && _sideTransparentCount[side] > 0; }
public NeighbourCoordsResult?GetNeighbourCoordsInfinite(Coords coords, NeighbourSide side, bool readOnly = false) { return(GetNeighbourCoordsInfinite(this, coords, side, GetOrCreateNeighbour, readOnly)); }