/// <summary>
        /// After calling this method all tiles within a camera frustum will be marked as being in the frustum set and as being used starting at the root and stopping when:
        /// 1) A tile is found that has a screen space error less than or equal to our target SSE
        /// 2) MaxDepth is reached (Optional)
        /// Tiles with no content are ignored (i.e. we recurse to the nearest complete set of descendents with content)
        ///
        /// If the LoadSiblings criteria is enabled we add additional tiles to the used set. Specificlly, if a tile is in the Frustum set, we gurantee that all of its siblings
        /// are marked as used.  If the siblings have empty conetent, we mark the first set of decendents that have content as used.  This is useful for tree traversals where
        /// we want to load content or do computation on tiles that are outside the users current view but results in a slower traversal.
        ///
        /// After this method is run, only tiles that are in the used set are considered by the rest of the traversal algorithm for this frame.  Unused tiles may be subject to being unloaded.
        /// </summary>
        /// <param name="tile"></param>
        /// <param name="planes"></param>
        /// <returns></returns>
        bool DetermineFrustumSet(Unity3DTile tile, Plane[] planes, SSECalculator sse, Vector3 cameraPosInTilesetFrame,
                                 Vector3 cameraFwdInTilesetFrame, PlaneClipMask mask)
        {
            // Reset frame state if needed
            tile.FrameState.Reset(this.frameCount);
            // Check to see if we are in the fustrum
            mask = tile.BoundingVolume.IntersectPlanes(planes, mask);
            if (mask.Intersection == IntersectionType.OUTSIDE)
            {
                return(false);
            }
            // We are in frustum and at a rendereable level of detail, mark as used and as visible
            tile.MarkUsed();  //  mark content as used in LRUContent so it won't be unloaded
            tile.FrameState.InFrustumSet             = true;
            this.tileset.Statistics.FrustumSetCount += 1;
            // Skip screen space error check if this node has empty content,
            // we need to keep recursing until we find a node with content regardless of error
            if (!tile.HasEmptyContent)
            {
                // Check to see if this tile meets the on screen error level of detail requirement
                float distance = tile.BoundingVolume.MinDistanceTo(cameraPosInTilesetFrame);
                // We take the min in case multiple cameras, reset dist to max float on frame reset
                tile.FrameState.DistanceToCamera = Mathf.Min(distance, tile.FrameState.DistanceToCamera);
                tile.FrameState.ScreenSpaceError = sse.PixelError(tile.GeometricError, distance);

                Ray   cameraRay      = new Ray(cameraPosInTilesetFrame, cameraFwdInTilesetFrame);
                float distToAxis     = tile.BoundingVolume.CenterDistanceTo(cameraRay);
                float pixelsToCamCtr = sse.ProjectDistanceOnTileToScreen(distToAxis, distance);
                tile.FrameState.PixelsToCameraCenter = Mathf.Min(pixelsToCamCtr, tile.FrameState.PixelsToCameraCenter);

                //prune traversal when we hit a tile that meets SSE
                if (tile.FrameState.ScreenSpaceError <= tileset.TilesetOptions.MaximumScreenSpaceError)
                {
                    return(true);
                }
            }
            if (tileset.TilesetOptions.MaxDepth > 0 && tile.Depth >= tileset.TilesetOptions.MaxDepth)
            {
                return(true);
            }
            // Recurse on children
            bool anyChildUsed = false;

            for (int i = 0; i < tile.Children.Count; i++)
            {
                bool r = DetermineFrustumSet(tile.Children[i], planes, sse, cameraPosInTilesetFrame,
                                             cameraFwdInTilesetFrame, mask);
                anyChildUsed = anyChildUsed || r;
            }
            // If any children are in the workingset, mark all of them as being used (siblings/atomic split criteria).
            if (anyChildUsed && this.tileset.TilesetOptions.LoadSiblings)
            {
                for (int i = 0; i < tile.Children.Count; i++)
                {
                    MarkUsedRecursively(tile.Children[i]);
                }
            }
            return(true);
        }
        public void Run()
        {
            if (!tileset.TilesetOptions.Show)
            {
                ToggleTiles(tileset.Root);
                return;
            }

            SSECalculator sse = new SSECalculator(tileset);

            foreach (Camera cam in sceneOptions.ClippingCameras)
            {
                if (cam == null)
                {
                    continue;
                }

                // All of our bounding boxes and tiles are using tileset coordinate frame so lets get our frustrum
                // planes in tileset frame.  This way we only need to transform our planes, not every bounding box we
                // need to check against
                Matrix4x4 cameraMatrix =
                    cam.projectionMatrix * cam.worldToCameraMatrix * tileset.Behaviour.transform.localToWorldMatrix;
                Plane[] planes = GeometryUtility.CalculateFrustumPlanes(cameraMatrix);

                sse.Configure(cam);
                Vector3 cameraPositionInTileset =
                    tileset.Behaviour.transform.InverseTransformPoint(cam.transform.position);
                Vector3 cameraForwardInTileset =
                    tileset.Behaviour.transform.InverseTransformDirection(cam.transform.forward);

                DetermineFrustumSet(tileset.Root, planes, sse, cameraPositionInTileset, cameraForwardInTileset,
                                    PlaneClipMask.GetDefaultMask());
            }

            foreach (var ft in ForceTiles)
            {
                for (var tile = ft; tile != null; tile = tile.Parent)
                {
                    if (!tile.FrameState.IsUsedThisFrame)
                    {
                        tile.FrameState.Reset();
                        tile.MarkUsed();
                        tile.FrameState.InFrustumSet = true;
                        tileset.Statistics.FrustumSet++;
                    }
                }
            }

            MarkUsedSetLeaves(tileset.Root);

            AssignPrioritiesRecursively(tileset.Root);

            SkipTraversal(tileset.Root);

            ToggleTiles(tileset.Root);

            //RequestManager.Process() and UnloadUnusedContent()
            //are called once for all tilesets at end of AbstractTilesetBehaviour.LateUpdate()
        }
Esempio n. 3
0
        public PlaneClipMask IntersectPlanes(Plane[] planes, PlaneClipMask mask)
        {
            if (mask.Intersection != IntersectionType.INTERSECTING)
            {
                return(mask);
            }

            for (var i = 0; i < planes.Length; ++i)
            {
                if (mask.Intersecting(i))
                {
                    IntersectionType value = this.IntersectPlane(planes[i]);
                    mask.Set(i, value);
                    if (value == IntersectionType.OUTSIDE)
                    {
                        break;
                    }
                }
            }
            return(mask);
        }
Esempio n. 4
0
 public PlaneClipMask IntersectPlanes(Plane[] planes)
 {
     return(IntersectPlanes(planes, PlaneClipMask.GetDefaultMask()));
 }
        public void Run()
        {
            frameCount++;
            tileset.LRUContent.MarkAllUnused();
            // Move any tiles with downloaded content to the ready state
            for (int i = 0; i < this.tileset.Options.MaximumTilesToProcessPerFrame && this.tileset.ProcessingQueue.Count != 0; i++)
            {
                var tile = this.tileset.ProcessingQueue.Dequeue();
                tile.Process();
            }

            SSECalculator sse = new SSECalculator(this.tileset);

            foreach (Camera cam in tileset.Options.ClippingCameras)
            {
                if (cam == null)
                {
                    continue;
                }
                // All of our bounding boxes and tiles are using tileset coordinate frame so lets get our frustrum planes
                // in tileset frame.  This way we only need to transform our planes, not every bounding box we need to check against
                Matrix4x4 cameraMatrix = cam.projectionMatrix * cam.worldToCameraMatrix * tileset.Behaviour.transform.localToWorldMatrix;
                Plane[]   planes       = GeometryUtility.CalculateFrustumPlanes(cameraMatrix);

                sse.Configure(cam);
                Vector3 cameraPositionInTilesetFrame = tileset.Behaviour.transform.InverseTransformPoint(cam.transform.position);
                DetermineFrustumSet(tileset.Root, planes, sse, cameraPositionInTilesetFrame, PlaneClipMask.GetDefaultMask());
            }
            MarkUsedSetLeaves(tileset.Root);
            SkipTraversal(tileset.Root);
            UnloadUnusedContent();
            ToggleTiles(tileset.Root);
            this.tileset.RequestManager.Process();
        }
Esempio n. 6
0
        public void Run()
        {
            frameCount++;
            if (!tileset.TilesetOptions.Show)
            {
                ToggleTiles(tileset.Root);
                return;
            }
            SSECalculator sse = new SSECalculator(this.tileset);

            foreach (Camera cam in sceneOptions.ClippingCameras)
            {
                if (cam == null)
                {
                    continue;
                }
                // All of our bounding boxes and tiles are using tileset coordinate frame so lets get our frustrum planes
                // in tileset frame.  This way we only need to transform our planes, not every bounding box we need to check against
                Matrix4x4 cameraMatrix = cam.projectionMatrix * cam.worldToCameraMatrix * tileset.Behaviour.transform.localToWorldMatrix;
                Plane[]   planes       = GeometryUtility.CalculateFrustumPlanes(cameraMatrix);

                sse.Configure(cam);
                Vector3 cameraPositionInTilesetFrame = tileset.Behaviour.transform.InverseTransformPoint(cam.transform.position);
                DetermineFrustumSet(tileset.Root, planes, sse, cameraPositionInTilesetFrame, PlaneClipMask.GetDefaultMask());
            }
            MarkUsedSetLeaves(tileset.Root);
            SkipTraversal(tileset.Root);
            ToggleTiles(tileset.Root);
            //this.tileset.RequestManager.Process();
            //UnloadUnusedContent called once for all tilesets at end of AbstractTilesetBehaviour.LateUpdate()
        }