public void EnforceMinimumDepth() { if (_nodeDepth < _parentTree.MinimumDepth) { if (this.HasChildren) { _isActive = false; _isSplit = true; ChildTopLeft.EnforceMinimumDepth(); ChildTopRight.EnforceMinimumDepth(); ChildBottomLeft.EnforceMinimumDepth(); ChildBottomRight.EnforceMinimumDepth(); } else { this.Activate(); _isSplit = false; } return; } if (_nodeDepth == _parentTree.MinimumDepth || (_nodeDepth < _parentTree.MinimumDepth && !this.HasChildren)) { this.Activate(); _isSplit = false; } }
/// <summary> /// Get a reference to the deepest node that contains a point. /// </summary> /// <param name="point">Vector3 representing the target point</param> /// <returns>Deepest quad node containing target point</returns> public QuadNode DeepestNodeWithPoint(Vector3 point) { //If the point isn't in this node, return null if (!Contains(point)) { return(null); } if (HasChildren) { if (ChildTopLeft.Contains(point)) { return(ChildTopLeft.DeepestNodeWithPoint(point)); } if (ChildTopRight.Contains(point)) { return(ChildTopRight.DeepestNodeWithPoint(point)); } if (ChildBottomLeft.Contains(point)) { return(ChildBottomLeft.DeepestNodeWithPoint(point)); } //It's contained in this node and not in the first 3 //children, so has to be in 4th child. No need to check. return(ChildBottomRight.DeepestNodeWithPoint(point)); } //No children, return this QuadNode return(this); }
/// <summary> /// Force the quad tree to split to the minimum depth /// </summary> internal void EnforceMinimumDepth() { if (_nodeDepth < _parentTree.MinimumDepth) { if (HasChildren) { _isActive = false; _isSplit = true; ChildTopLeft.EnforceMinimumDepth(); ChildTopRight.EnforceMinimumDepth(); ChildBottomLeft.EnforceMinimumDepth(); ChildBottomRight.EnforceMinimumDepth(); } else { Activate(); _isSplit = false; } return; } if (_nodeDepth == _parentTree.MinimumDepth) { Activate(); _isSplit = false; } }
/// <summary> /// Add this node to the terrain's batch. /// </summary> /// <param name="fullyContained">Whether this node is known to be fully contained within the clipping frustums, in which case it and its children do not need to check clipping against it.</param> /// <param name="viewPoint">The position that this node is being viewed from.</param> /// <param name="distance">Equal to the distance from the <paramref name="viewPoint"/> to the nearest point on this node. This is needed by parent nodes for sorting, so it is calculated there and then passed down.</param> public void Batch(bool fullyContained, ref Vector3d viewPoint, double distance) { if (!CheckClip(ref fullyContained)) { return; } double lodBlend = LodBlend(distance); if (lodBlend >= 1 && !IsLeaf) { TerrainTreeNode a = ChildTopLeft, b = ChildTopRight, c = ChildBottomLeft, d = ChildBottomRight; double ad = ChildTopLeft.DistanceTo(ref viewPoint); double bd = ChildTopRight.DistanceTo(ref viewPoint); double cd = ChildBottomLeft.DistanceTo(ref viewPoint); double dd = ChildBottomRight.DistanceTo(ref viewPoint); SortByDepth(ref ad, ref bd, ref cd, ref dd, ref a, ref b, ref c, ref d); a.Batch(fullyContained, ref viewPoint, ad); b.Batch(fullyContained, ref viewPoint, bd); c.Batch(fullyContained, ref viewPoint, cd); d.Batch(fullyContained, ref viewPoint, dd); return; } Terrain.AddInstanceArray(TexelCorner.X, TexelCorner.Y, Lod + lodBlend, TexelSize); }
/// <summary> /// Update the <see cref="Box"/> value on the basis of data read from a shader. /// </summary> /// <param name="dirty">The boundaries of the modified area in cells.</param> /// <param name="smallHeightData"></param> public void Clean(ref Box2i dirty, float[] smallHeightData) { if (dirty.Min.X > pBox.Max.X || dirty.Min.Y > pBox.Max.Z || dirty.Max.X <= pBox.Min.X || dirty.Max.Y <= pBox.Min.Z) { return; } if (IsLeaf) { var offset = (VertexCorner.X + VertexCorner.Y * (Terrain.BlockSize / 16)) * 2; double min = smallHeightData[offset + 0], max = smallHeightData[offset + 1]; pBox.Min.Y = min; pBox.Max.Y = max; } else { ChildTopLeft.Clean(ref dirty, smallHeightData); ChildTopRight.Clean(ref dirty, smallHeightData); ChildBottomLeft.Clean(ref dirty, smallHeightData); ChildBottomRight.Clean(ref dirty, smallHeightData); pBox.Min.Y = Math.Min(Math.Min(ChildTopLeft.pBox.Min.Y, ChildTopRight.pBox.Min.Y), Math.Min(ChildBottomLeft.pBox.Min.Y, ChildBottomRight.pBox.Min.Y)); pBox.Max.Y = Math.Max(Math.Max(ChildTopLeft.pBox.Max.Y, ChildTopRight.pBox.Max.Y), Math.Max(ChildBottomLeft.pBox.Max.Y, ChildBottomRight.pBox.Max.Y)); } }
internal void SetActiveVertices() { if (_parentTree.Cull && !IsInView) { return; } if (_isSplit && this.HasChildren) { ChildTopLeft.SetActiveVertices(); ChildTopRight.SetActiveVertices(); ChildBottomLeft.SetActiveVertices(); ChildBottomRight.SetActiveVertices(); return; } //Top Triangle(s) _parentTree.UpdateBuffer(VertexCenter.Index); _parentTree.UpdateBuffer(VertexTopLeft.Index); if (VertexTop.Activated) { _parentTree.UpdateBuffer(VertexTop.Index); _parentTree.UpdateBuffer(VertexCenter.Index); _parentTree.UpdateBuffer(VertexTop.Index); } _parentTree.UpdateBuffer(VertexTopRight.Index); //Right Triangle(s) _parentTree.UpdateBuffer(VertexCenter.Index); _parentTree.UpdateBuffer(VertexTopRight.Index); if (VertexRight.Activated) { _parentTree.UpdateBuffer(VertexRight.Index); _parentTree.UpdateBuffer(VertexCenter.Index); _parentTree.UpdateBuffer(VertexRight.Index); } _parentTree.UpdateBuffer(VertexBottomRight.Index); //Bottom Triangle(s) _parentTree.UpdateBuffer(VertexCenter.Index); _parentTree.UpdateBuffer(VertexBottomRight.Index); if (VertexBottom.Activated) { _parentTree.UpdateBuffer(VertexBottom.Index); _parentTree.UpdateBuffer(VertexCenter.Index); _parentTree.UpdateBuffer(VertexBottom.Index); } _parentTree.UpdateBuffer(VertexBottomLeft.Index); //Left Triangle(s) _parentTree.UpdateBuffer(VertexCenter.Index); _parentTree.UpdateBuffer(VertexBottomLeft.Index); if (VertexLeft.Activated) { _parentTree.UpdateBuffer(VertexLeft.Index); _parentTree.UpdateBuffer(VertexCenter.Index); _parentTree.UpdateBuffer(VertexLeft.Index); } _parentTree.UpdateBuffer(VertexTopLeft.Index); }
/// <summary> /// Update reference to neighboring quads /// </summary> private void AddNeighbors() { switch (NodeType) { case NodeType.TopLeft: //Top Left Corner //Top neighbor if (_parent.NeighborTop != null) { NeighborTop = _parent.NeighborTop.ChildBottomLeft; } //Right neighbor NeighborRight = _parent.ChildTopRight; //Bottom neighbor NeighborBottom = _parent.ChildBottomLeft; //Left neighbor if (_parent.NeighborLeft != null) { NeighborLeft = _parent.NeighborLeft.ChildTopRight; } break; case NodeType.TopRight: //Top Right Corner //Top neighbor if (_parent.NeighborTop != null) { NeighborTop = _parent.NeighborTop.ChildBottomRight; } //Right neighbor if (_parent.NeighborRight != null) { NeighborRight = _parent.NeighborRight.ChildTopLeft; } //Bottom neighbor NeighborBottom = _parent.ChildBottomRight; //Left neighbor NeighborLeft = _parent.ChildTopLeft; break; case NodeType.BottomLeft: //Bottom Left Corner //Top neighbor NeighborTop = _parent.ChildTopLeft; //Right neighbor NeighborRight = _parent.ChildBottomRight; //Bottom neighbor if (_parent.NeighborBottom != null) { NeighborBottom = _parent.NeighborBottom.ChildTopLeft; } //Left neighbor if (_parent.NeighborLeft != null) { NeighborLeft = _parent.NeighborLeft.ChildBottomRight; } break; case NodeType.BottomRight: //Bottom Right Corner //Top neighbor NeighborTop = _parent.ChildTopRight; //Right neighbor if (_parent.NeighborRight != null) { NeighborRight = _parent.NeighborRight.ChildBottomLeft; } //Bottom neighbor if (_parent.NeighborBottom != null) { NeighborBottom = _parent.NeighborBottom.ChildTopRight; } //Left neighbor NeighborLeft = _parent.ChildBottomLeft; break; } if (this.HasChildren) { ChildTopLeft.AddNeighbors(); ChildTopRight.AddNeighbors(); ChildBottomLeft.AddNeighbors(); ChildBottomRight.AddNeighbors(); } }
/// <summary> /// Merge split quad nodes /// </summary> public void Merge() { //Only perform the merge if there are children VertexTop.Activated = false; VertexLeft.Activated = false; VertexRight.Activated = false; VertexBottom.Activated = false; if (NodeType != NodeType.FullNode) { VertexTopLeft.Activated = false; VertexTopRight.Activated = false; VertexBottomLeft.Activated = false; VertexBottomRight.Activated = false; } _isActive = true; _isSplit = false; if (HasChildren) { if (ChildTopLeft.IsSplit) { ChildTopLeft.Merge(); ChildTopLeft.IsActive = false; } else { ChildTopLeft.VertexTop.Activated = false; ChildTopLeft.VertexLeft.Activated = false; ChildTopLeft.VertexRight.Activated = false; ChildTopLeft.VertexBottom.Activated = false; } if (ChildTopRight.IsSplit) { ChildTopRight.Merge(); ChildTopRight.IsActive = false; } else { ChildTopRight.VertexTop.Activated = false; ChildTopRight.VertexLeft.Activated = false; ChildTopRight.VertexRight.Activated = false; ChildTopRight.VertexBottom.Activated = false; } if (ChildBottomLeft.IsSplit) { ChildBottomLeft.Merge(); ChildBottomLeft.IsActive = false; } else { ChildBottomLeft.VertexTop.Activated = false; ChildBottomLeft.VertexLeft.Activated = false; ChildBottomLeft.VertexRight.Activated = false; ChildBottomLeft.VertexBottom.Activated = false; } if (ChildBottomRight.IsSplit) { ChildBottomRight.Merge(); ChildBottomRight.IsActive = false; } else { ChildBottomRight.VertexTop.Activated = false; ChildBottomRight.VertexLeft.Activated = false; ChildBottomRight.VertexRight.Activated = false; ChildBottomRight.VertexBottom.Activated = false; } } }
/// <summary> /// Split the node by activating vertices /// </summary> public void Split() { if (_parentTree.Cull && !IsInView) { return; } //Make sure parent node is split if (_parent != null && !_parent.IsSplit) { _parent.Split(); } if (CanSplit) { //Set active nodes if (HasChildren) { ChildTopLeft.Activate(); ChildTopRight.Activate(); ChildBottomLeft.Activate(); ChildBottomRight.Activate(); _isActive = false; } else { _isActive = true; } _isSplit = true; //Set active vertices VertexTop.Activated = true; VertexLeft.Activated = true; VertexRight.Activated = true; VertexBottom.Activated = true; } //Make sure neighbor parents are split EnsureNeighborParentSplit(NeighborTop); EnsureNeighborParentSplit(NeighborRight); EnsureNeighborParentSplit(NeighborBottom); EnsureNeighborParentSplit(NeighborLeft); //Make sure neighbor vertices are active if (NeighborTop != null) { NeighborTop.VertexBottom.Activated = true; } if (NeighborRight != null) { NeighborRight.VertexLeft.Activated = true; } if (NeighborBottom != null) { NeighborBottom.VertexTop.Activated = true; } if (NeighborLeft != null) { NeighborLeft.VertexRight.Activated = true; } }