/// <summary> /// Gives the current camera data to the traversal thread and updates the GameObjects. Called from the MainThread. As described in the Bachelor Thesis in chapter 3.1.3 "Main Thread" /// </summary> public void Update() { unityThread = Thread.CurrentThread; if (paused) { return; } //Set new Camera Data traversalThread.SetNextCameraData(camera.transform.position, camera.transform.forward, GeometryUtility.CalculateFrustumPlanes(camera), camera.pixelRect.height, camera.fieldOfView); //Update GameObjects Queue <Node> toRender; Queue <Node> toDelete; lock (locker) { toRender = this.toRender; toDelete = this.toDelete; this.toRender = null; this.toDelete = null; } if (toRender == null) { return; } while (toDelete.Count != 0) { Node n = toDelete.Dequeue(); lock (n) { if (n.HasGameObjects()) { n.RemoveGameObjects(config); cache.Insert(n); } } } while (toRender.Count != 0) { Node n = toRender.Dequeue(); lock (n) { if (n.HasPointsToRender() && (n.Parent == null || n.Parent.HasGameObjects())) { n.CreateGameObjects(config); } } } Monitor.Enter(toDeleteExternal); while (toDeleteExternal.Count != 0) { Node rootNode = toDeleteExternal.Dequeue(); rootNodes.Remove(rootNode); Queue <Node> toRemove = new Queue <Node>(); toRemove.Enqueue(rootNode); while (toRemove.Count != 0) { Node n = toRemove.Dequeue(); cache.Withdraw(n); if (n.HasGameObjects()) { n.RemoveGameObjects(config); } if (n.HasPointsToRender()) { n.ForgetPoints(); foreach (Node child in n) { toRemove.Enqueue(child); } } } } Monitor.Exit(toDeleteExternal); //Notify Traversal Thread lock (traversalThread) { Monitor.PulseAll(traversalThread); } }
private uint TraverseAndBuildRenderingQueue() { //Camera Data Vector3 cameraPosition; Vector3 camForward; Plane[] frustum; float screenHeight; float fieldOfView; PriorityQueue <double, Node> toProcess = new HeapPriorityQueue <double, Node>(); lock (locker) { if (this.frustum == null) { return(0); } cameraPosition = this.cameraPosition; camForward = this.camForward; frustum = this.frustum; screenHeight = this.screenHeight; fieldOfView = this.fieldOfView; } //Clearing Queues uint renderingpointcount = 0; uint maxnodestoload = nodesLoadedPerFrame; uint maxnodestorender = nodesGOsPerFrame; HashSet <Node> newVisibleNodes = new HashSet <Node>(); foreach (Node rootNode in rootNodes) { Vector3 center = rootNode.BoundingBox.GetBoundsObject().center; double distance = (center - cameraPosition).magnitude; double slope = Math.Tan(fieldOfView / 2 * Mathf.Deg2Rad); double projectedSize = (screenHeight / 2.0) * rootNode.BoundingBox.Radius() / (slope * distance); if (projectedSize > minNodeSize) { Vector3 camToNodeCenterDir = (center - cameraPosition).normalized; double angle = Math.Acos(camForward.x * camToNodeCenterDir.x + camForward.y * camToNodeCenterDir.y + camForward.z * camToNodeCenterDir.z); double angleWeight = Math.Abs(angle) + 1.0; //+1, to prevent divsion by zero double priority = projectedSize / angleWeight; toProcess.Enqueue(rootNode, priority); } else { DeleteNode(rootNode); } } while (!toProcess.IsEmpty() && running) { Node n = toProcess.Dequeue(); //Min Node Size was already checked //Is Node inside frustum? if (Util.InsideFrustum(n.BoundingBox, frustum)) { bool loadchildren = false; lock (n) { if (n.PointCount == -1) { if (maxnodestoload > 0) { loadingThread.ScheduleForLoading(n); --maxnodestoload; loadchildren = true; } } else if (renderingpointcount + n.PointCount <= pointBudget) { if (n.HasGameObjects()) { renderingpointcount += (uint)n.PointCount; visibleNodes.Remove(n); newVisibleNodes.Add(n); loadchildren = true; } else if (n.HasPointsToRender()) { //Might be in Cache -> Withdraw if (maxnodestorender > 0) { cache.Withdraw(n); renderingpointcount += (uint)n.PointCount; toRender.Enqueue(n); --maxnodestorender; newVisibleNodes.Add(n); loadchildren = true; } } else { if (maxnodestoload > 0) { loadingThread.ScheduleForLoading(n); --maxnodestoload; loadchildren = true; } } } else { maxnodestoload = 0; maxnodestorender = 0; if (n.HasGameObjects()) { visibleNodes.Remove(n); DeleteNode(n); } } } if (loadchildren) { foreach (Node child in n) { Vector3 center = child.BoundingBox.GetBoundsObject().center; double distance = (center - cameraPosition).magnitude; double slope = Math.Tan(fieldOfView / 2 * Mathf.Deg2Rad); double projectedSize = (screenHeight / 2.0) * child.BoundingBox.Radius() / (slope * distance); if (projectedSize > minNodeSize) { Vector3 camToNodeCenterDir = (center - cameraPosition).normalized; double angle = Math.Acos(camForward.x * camToNodeCenterDir.x + camForward.y * camToNodeCenterDir.y + camForward.z * camToNodeCenterDir.z); double angleWeight = Math.Abs(angle) + 1.0; //+1, to prevent divsion by zero double priority = projectedSize / angleWeight; toProcess.Enqueue(child, priority); } else { DeleteNode(child); } } } } else { //This node or its children might be visible DeleteNode(n); } } foreach (Node n in visibleNodes) { DeleteNode(n); } visibleNodes = newVisibleNodes; return(renderingpointcount); }