private void RemovePatch(PlanetNode currentNode) { Vector3 mid = (currentNode.min + currentNode.max) / 2; activePatches.Remove(mid); SystemCore.GameObjectManager.RemoveObject(currentNode); }
internal PlanetNode DetermineHitNode(Ray ray) { List <PlanetNode> hitNodes = new List <PlanetNode>(); foreach (var activePatch in activePatches.Values) { BoundingSphere sphere = activePatch.boundingSphere; if (ray.Intersects(sphere).HasValue) { hitNodes.Add(activePatch); } } PlanetNode closest = null; float closestDistance = float.MaxValue; foreach (PlanetNode n in hitNodes) { float distanceToNode = (n.boundingSphere.Center - ray.Position).Length(); if (distanceToNode < closestDistance) { closest = n; closestDistance = distanceToNode; } } return(closest); }
private void AddPatch(PlanetNode finishedNode) { SystemCore.GameObjectManager.AddAndInitialiseGameObject(finishedNode); Vector3 mid = (finishedNode.min + finishedNode.max) / 2; activePatches.Add(mid, finishedNode); nodesBeingBuilt.Remove(mid); }
public static void Enqueue(PlanetNode nodeToBuild) { if (!finishedNodes.ContainsKey(nodeToBuild.Planet.Name)) { finishedNodes.Add(nodeToBuild.Planet.Name, new ConcurrentQueue <PlanetNode>()); } nodesAwaitingBuilding.Enqueue(nodeToBuild); }
public List <Connection> GetConnections(PlanetNode node) { if (nodeDictionary.ContainsKey(node.GetKeyPoint())) { return(GetConnections(nodeDictionary[node.GetKeyPoint()])); } return(new List <Connection>()); }
public static bool GetBuiltNodes(string planetName, out PlanetNode finishedNode) { if (finishedNodes.ContainsKey(planetName)) { return(finishedNodes[planetName].TryDequeue(out finishedNode)); } finishedNode = null; return(false); }
public List <Connection> ThreadSafeGetConnections(PlanetNode node) { lock (connectionBuffer) { lock (nodeDictionaryBuffer) { if (!nodeDictionaryBuffer.ContainsKey(node.GetKeyPoint())) { return(null); } var key = nodeDictionaryBuffer[node.GetKeyPoint()]; if (!connectionBuffer.ContainsKey(key)) { return(null); } return(connectionBuffer[key]); } } }
private void AddNodeIfNotPresent(Vector3 normal, float step, int depth, Vector3 min, Vector3 max) { //don't build if already under way. Vector3 mid = (min + max) / 2; if (nodesBeingBuilt.ContainsKey(mid)) { return; } if (activePatches.ContainsKey(mid)) { PlanetNode node = activePatches[mid]; node.remove = false; return; } var patchBeingBuilt = new PatchMinMax(min, max); nodesBeingBuilt.Add(mid, patchBeingBuilt); PlanetBuilder.Enqueue(testEffect, module, this, depth, min, max, step, normal, radius); }
private void CalculatePatchLOD(Vector3 normal, float step, int depth, Vector3 min, Vector3 max) { //recurse down through the tree. For each node on the way down, we decide if it should split or not. //if it should, calculate the split and move down. Remove the node if it's currently visible. if (ShouldSplit(min, max, radius, depth)) { Vector3 se, sw, mid1, mid2, nw, ne, midBottom, midRight, midLeft, midTop; PlanetNode.CalculatePatchBoundaries(normal, step, min, max, out se, out sw, out mid1, out mid2, out nw, out ne, out midBottom, out midRight, out midLeft, out midTop); CalculatePatchLOD(normal, step / 2, depth + 1, se, mid1); CalculatePatchLOD(normal, step / 2, depth + 1, mid2, nw); CalculatePatchLOD(normal, step / 2, depth + 1, midBottom, midLeft); CalculatePatchLOD(normal, step / 2, depth + 1, midRight, midTop); } else { if (depth <= maxDepth) { AddNodeIfNotPresent(normal, step, depth, min, max); } } }
private void RenderConnections(PlanetNode node) { List <NeighbourTracker.Connection> connections = neighbourTracker.GetConnections(node); Color nodeQuadrantColor = Color.Red; if (neighbourTracker.nodeDictionary.ContainsKey(node.GetKeyPoint())) { NeighbourTrackerNode trackerNode = neighbourTracker.nodeDictionary[node.GetKeyPoint()]; if (trackerNode.quadrant == NeighbourTrackerNode.Quadrant.ne) { nodeQuadrantColor = Color.White; } if (trackerNode.quadrant == NeighbourTrackerNode.Quadrant.nw) { nodeQuadrantColor = Color.Green; } if (trackerNode.quadrant == NeighbourTrackerNode.Quadrant.se) { nodeQuadrantColor = Color.Pink; } if (trackerNode.quadrant == NeighbourTrackerNode.Quadrant.sw) { nodeQuadrantColor = Color.Yellow; } DebugShapeRenderer.AddBoundingSphere(new BoundingSphere(node.GetSurfaceMidPoint(), 100f / trackerNode.depth), nodeQuadrantColor); } foreach (NeighbourTracker.Connection conn in connections) { DebugShapeRenderer.AddLine(node.GetSurfaceMidPoint(), Vector3.Transform(Vector3.Normalize(conn.node.keyPoint) * radius, Transform.AbsoluteTransform), Color.Blue); } }
public static void Enqueue(Effect effect, IModule module, Planet rootObject, int depth, Vector3 min, Vector3 max, float step, Vector3 normal, float sphereSize) { var node = new PlanetNode(effect, module, rootObject, depth, min, max, step, normal, sphereSize); Enqueue(node); }
public List <NeighbourTracker.Connection> GetNeighbours(PlanetNode node) { return(neighbourTracker.ThreadSafeGetConnections(node)); }
public void Update(GameTime gameTime) { Vector3 planetCenter = Transform.AbsoluteTransform.Translation; Vector3 toCenterOfPlanet = Transform.AbsoluteTransform.Translation - SystemCore.ActiveCamera.Position; float distanceToCenterOfPlanet = toCenterOfPlanet.Length(); float surfaceDistance = distanceToCenterOfPlanet - radius; if (HasAtmosphere) { atmosphere.Update(sunDirection, SystemCore.ActiveCamera.Position, distanceToCenterOfPlanet); atmosphericScatteringHelper.Update(distanceToCenterOfPlanet, sunDirection, SystemCore.ActiveCamera.Position - Transform.AbsoluteTransform.Translation); } float farPlaneMultiplier = MonoMathHelper.MapFloatRange(radius, radius * 2, 0.3f, 1f, surfaceDistance); GenerateCustomProjectionMatrix(distanceToCenterOfPlanet * farPlaneMultiplier); var frustrum = new BoundingFrustum(SystemCore.ActiveCamera.View * customProjection); int activeCount = 0; foreach (PlanetNode node in activePatches.Values) { node.Update(); //all nodes are flagged for removal every frame. //The LOD calculation will unflag if nodes should be kept. node.remove = true; if (!frustrum.Intersects(node.boundingSphere)) { node.Disable(); } else { if (SystemWarGlobalSettings.RenderQuadtreeConnectivity) { RenderConnections(node); } node.Enable(); activeCount++; } } if (SystemWarGlobalSettings.RepairSeams) { CalculateConnectivity(); } for (int i = 0; i < rootNodes.Count; i++) { PlanetNode root = rootNodes[i]; CalculatePatchLOD(root.normal, root.step, root.depth, root.min, root.max); } //removes nodes that have not had their flags refreshed by the LOD pass RemoveStaleNodes(); int patchCountPerFrame = 10; for (int i = 0; i < patchCountPerFrame; i++) { PlanetNode finishedNode; if (PlanetBuilder.GetBuiltNodes(Name, out finishedNode)) { AddPatch(finishedNode); } } }
private void CalculateConnectivity() { ReinitialiseTracker(); // have to go through the tree in a breadth first fashion, building connectivity. Queue <PatchMinMax> nodesToCheck = new Queue <PatchMinMax>(); foreach (PlanetNode rootNode in rootNodes) { nodesToCheck.Enqueue(new PatchMinMax(rootNode.min, rootNode.max, rootNode.depth, rootNode.normal, rootNode.step, neighbourTracker.nodeDictionary[(rootNode.min + rootNode.max) / 2].side)); } while (nodesToCheck.Count > 0) { PatchMinMax next = nodesToCheck.Dequeue(); if (ShouldSplit(next.Min, next.Max, radius, next.depth)) { Vector3 se, sw, mid1, mid2, nw, ne, midBottom, midRight, midLeft, midTop; PlanetNode.CalculatePatchBoundaries(next.normal, next.step, next.Min, next.Max, out se, out sw, out mid1, out mid2, out nw, out ne, out midBottom, out midRight, out midLeft, out midTop); //remove this node in the neighbour tracker, generate and connect children NeighbourTrackerNode southEast = new NeighbourTrackerNode(next.depth + 1, se, mid1, next.step / 2, next.normal); southEast.quadrant = NeighbourTrackerNode.Quadrant.se; southEast.side = next.side; PatchMinMax sePatchMinMax = new PatchMinMax(se, mid1, next.depth + 1, next.normal, next.step / 2, next.side); nodesToCheck.Enqueue(sePatchMinMax); NeighbourTrackerNode northWest = new NeighbourTrackerNode(next.depth + 1, mid2, nw, next.step / 2, next.normal); northWest.quadrant = NeighbourTrackerNode.Quadrant.nw; northWest.side = next.side; PatchMinMax nwPatchMinMax = new PatchMinMax(mid2, nw, next.depth + 1, next.normal, next.step / 2, next.side); nodesToCheck.Enqueue(nwPatchMinMax); NeighbourTrackerNode southWest = new NeighbourTrackerNode(next.depth + 1, midBottom, midLeft, next.step / 2, next.normal); southWest.quadrant = NeighbourTrackerNode.Quadrant.sw; southWest.side = next.side; PatchMinMax swPatchMinMax = new PatchMinMax(midBottom, midLeft, next.depth + 1, next.normal, next.step / 2, next.side); nodesToCheck.Enqueue(swPatchMinMax); NeighbourTrackerNode northEast = new NeighbourTrackerNode(next.depth + 1, midRight, midTop, next.step / 2, next.normal); northEast.quadrant = NeighbourTrackerNode.Quadrant.ne; northEast.side = next.side; PatchMinMax nePatchMinMax = new PatchMinMax(midRight, midTop, next.depth + 1, next.normal, next.step / 2, next.side); nodesToCheck.Enqueue(nePatchMinMax); //if (next.side == NeighbourTrackerNode.CubeSide.right || next.side == NeighbourTrackerNode.CubeSide.back) //{ // southEast.quadrant = NeighbourTrackerNode.Quadrant.sw; // northEast.quadrant = NeighbourTrackerNode.Quadrant.nw; // southWest.quadrant = NeighbourTrackerNode.Quadrant.se; // northWest.quadrant = NeighbourTrackerNode.Quadrant.ne; //} neighbourTracker.ReplaceNodeWithChildren(neighbourTracker.nodeDictionary[(next.Min + next.Max) / 2], northWest, southWest, southEast, northEast); } } neighbourTracker.CopyConnectionDataToThreadSafeBuffer(); }
private void Initialise() { activePatches = new Dictionary <Vector3, PlanetNode>(); rootNodes = new List <PlanetNode>(); float vectorSpacing = 1f; float cubeVerts = 21; float sphereSize = radius; //top PlanetNode top = new PlanetNode(testEffect, module, this, 1, new Vector3(-cubeVerts / 2, cubeVerts / 2 - 1, -cubeVerts / 2), new Vector3(cubeVerts / 2, cubeVerts / 2 - 1, cubeVerts / 2), vectorSpacing, Vector3.Up, sphereSize); top.BuildGeometry(); AddPatch(top); rootNodes.Add(top); topNode = new NeighbourTrackerNode(1, top.min, top.max, vectorSpacing, Vector3.Up); topNode.side = NeighbourTrackerNode.CubeSide.top; ////bottom PlanetNode bottom = new PlanetNode(testEffect, module, this, 1, new Vector3(-cubeVerts / 2, -cubeVerts / 2, -cubeVerts / 2), new Vector3(cubeVerts / 2, -cubeVerts / 2, cubeVerts / 2), vectorSpacing, Vector3.Down, sphereSize); bottom.BuildGeometry(); AddPatch(bottom); rootNodes.Add(bottom); bottomNode = new NeighbourTrackerNode(1, bottom.min, bottom.max, vectorSpacing, Vector3.Down); bottomNode.side = NeighbourTrackerNode.CubeSide.bottom; ////forward PlanetNode forward = new PlanetNode(testEffect, module, this, 1, new Vector3(-cubeVerts / 2, -cubeVerts / 2, -cubeVerts / 2), new Vector3(cubeVerts / 2, cubeVerts / 2, cubeVerts / 2), vectorSpacing, Vector3.Forward, sphereSize); forward.BuildGeometry(); AddPatch(forward); rootNodes.Add(forward); forwardNode = new NeighbourTrackerNode(1, forward.min, forward.max, vectorSpacing, Vector3.Forward); forwardNode.side = NeighbourTrackerNode.CubeSide.front; ////backward PlanetNode backward = new PlanetNode(testEffect, module, this, 1, new Vector3(-cubeVerts / 2, -cubeVerts / 2, cubeVerts / 2 - 1), new Vector3(cubeVerts / 2, cubeVerts / 2, cubeVerts / 2 - 1), vectorSpacing, Vector3.Backward, sphereSize); backward.BuildGeometry(); AddPatch(backward); rootNodes.Add(backward); backwardNode = new NeighbourTrackerNode(1, backward.min, backward.max, vectorSpacing, Vector3.Backward); backwardNode.side = NeighbourTrackerNode.CubeSide.back; //right PlanetNode right = new PlanetNode(testEffect, module, this, 1, new Vector3(-cubeVerts / 2, -cubeVerts / 2, -cubeVerts / 2), new Vector3(-cubeVerts / 2, cubeVerts / 2, cubeVerts / 2), vectorSpacing, Vector3.Right, sphereSize); right.BuildGeometry(); AddPatch(right); rootNodes.Add(right); rightNode = new NeighbourTrackerNode(1, right.min, right.max, vectorSpacing, Vector3.Right); rightNode.side = NeighbourTrackerNode.CubeSide.right; //left PlanetNode left = new PlanetNode(testEffect, module, this, 1, new Vector3(cubeVerts / 2 - 1, -cubeVerts / 2, -cubeVerts / 2), new Vector3(cubeVerts / 2 - 1, cubeVerts / 2, cubeVerts / 2), vectorSpacing, Vector3.Left, sphereSize); left.BuildGeometry(); AddPatch(left); rootNodes.Add(left); leftNode = new NeighbourTrackerNode(1, left.min, left.max, vectorSpacing, Vector3.Left); leftNode.side = NeighbourTrackerNode.CubeSide.left; ReinitialiseTracker(); }