public Unity3DTile(Unity3DTileset tileset, string basePath, Schema.Tile tile, Unity3DTile parent)
        {
            this.hashCode   = (int)UnityEngine.Random.Range(0, int.MaxValue);
            this.Tileset    = tileset;
            this.tile       = tile;
            this.FrameState = new TileFrameState();
            if (tile.Content != null)
            {
                this.Id = Path.GetFileNameWithoutExtension(tile.Content.GetUri());
            }
            if (parent != null)
            {
                parent.Children.Add(this);
                this.Depth = parent.Depth + 1;
            }

            // TODO: Consider using a double percision Matrix library for doing 3d tiles root transform calculations
            // Set the local transform for this tile, default to identity matrix
            this.transform = this.tile.UnityTransform();
            var parentTransform = (parent != null) ? parent.computedTransform : tileset.GetRootTransform();

            this.computedTransform = parentTransform * this.transform;

            this.BoundingVolume = CreateBoundingVolume(tile.BoundingVolume, this.computedTransform);

            // TODO: Add 2D bounding volumes

            if (tile.Content != null && tile.Content.BoundingVolume.IsDefined())
            {
                // Non-leaf tiles may have a content bounding-volume, which is a tight-fit bounding volume
                // around only the features in the tile.  This box is useful for culling for rendering,
                // but not for culling for traversing the tree since it does not guarantee spatial coherence, i.e.,
                // since it only bounds features in the tile, not the entire tile, children may be
                // outside of this box.
                this.ContentBoundingVolume = CreateBoundingVolume(tile.Content.BoundingVolume, this.computedTransform);
            }
            else
            {
                // Default to tile bounding volume
                this.ContentBoundingVolume = CreateBoundingVolume(tile.BoundingVolume, this.computedTransform);
            }
            // TODO: Add viewer request volume support
            //if(tile.ViewerRequestVolume != null && tile.ViewerRequestVolume.IsDefined())
            //{
            //    this.viewerRequestVolume = CreateBoundingVolume(tile.ViewerRequestVolume, transform);
            //}

            if (!tile.Refine.HasValue)
            {
                tile.Refine = (parent == null) ? Schema.TileRefine.REPLACE : parent.tile.Refine.Value;
            }

            this.Parent = parent;

            if (this.HasEmptyContent)
            {
                this.ContentState = Unity3DTileContentState.READY;
            }
            else
            {
                ContentState    = Unity3DTileContentState.UNLOADED;
                this.ContentUrl = UrlUtils.JoinUrls(basePath, tile.Content.GetUri());
            }

            this.HasRenderableContent = false;
            this.HasTilesetContent    = false;
        }
        /// <summary>
        /// Lower priority will be loaded sooner
        /// </summary>
        /// <param name="priority"></param>
        public void RequestContent(float priority)
        {
            if (this.Tileset.RequestManager.Full())
            {
                return;
            }
            if (this.HasEmptyContent)
            {
                return;
            }
            if (this.ContentState == Unity3DTileContentState.UNLOADED ||
                this.ContentState == Unity3DTileContentState.EXPIRED)
            {
                this.ContentState = Unity3DTileContentState.LOADING;

                Promise <bool> finished = new Promise <bool>();
                finished.Then((success) =>
                {
                    this.Tileset.Statistics.NetworkError       = !success;
                    this.Tileset.Statistics.RequestsThisFrame += 1;
                    if (success)
                    {
                        this.ContentState = Unity3DTileContentState.PROCESSING;
                        this.Content.SetShadowMode(this.Tileset.TilesetOptions.ShadowCastingMode, this.Tileset.TilesetOptions.RecieveShadows);
                        this.Tileset.Statistics.LoadedContentCount += 1;
                        this.Tileset.Statistics.TotalTilesLoaded   += 1;
                        // Track tile in cache as soon as it has downloaded content, but still queue it for processing
                        CacheRequestStatus status = this.Tileset.LRUContent.Add(this);
                        if (status == CacheRequestStatus.ADDED)
                        {
                            this.Tileset.ProcessingQueue.Enqueue(this);
                        }
                        else
                        {
                            UnloadContent();
                        }
                    }
                    else
                    {
                        UnloadContent();
                    }
                });

                Promise started = new Promise();
                started.Then(() =>
                {
                    GameObject go              = new GameObject(Id);
                    go.transform.parent        = this.Tileset.Behaviour.transform;
                    go.transform.localPosition = new Vector3(this.computedTransform.m03, this.computedTransform.m13, this.computedTransform.m23);
                    go.transform.localRotation = this.computedTransform.rotation;
                    go.transform.localScale    = this.computedTransform.lossyScale;
                    go.layer = this.Tileset.Behaviour.gameObject.layer;
                    go.SetActive(false);
                    var info     = go.AddComponent <TileInfo>();
                    info.Tile    = this;
                    this.Content = new Unity3DTileContent(go);

                    if (ContentType == Unity3DTileContentType.B3DM)
                    {
                        B3DMComponent b3dmCo = go.AddComponent <B3DMComponent>();
                        b3dmCo.Url           = this.ContentUrl;
                        b3dmCo.Multithreaded = this.Tileset.TilesetOptions.GLTFMultithreadedLoad;
                        b3dmCo.MaximumLod    = this.Tileset.TilesetOptions.GLTFMaximumLOD;
                        if (!string.IsNullOrEmpty(this.Tileset.TilesetOptions.ShaderOverride))
                        {
                            b3dmCo.ShaderOverride = Shader.Find(this.Tileset.TilesetOptions.ShaderOverride);
                        }
                        b3dmCo.AddColliders    = false;
                        b3dmCo.DownloadOnStart = false;
                        this.Tileset.Behaviour.StartCoroutine(b3dmCo.Download(finished));
                    }
                    else if (ContentType == Unity3DTileContentType.PNTS)
                    {
                        PNTSComponent pntsCo   = go.AddComponent <PNTSComponent>();
                        pntsCo.Url             = UrlUtils.RemoveQuery(this.ContentUrl);
                        pntsCo.ShaderOverride  = Shader.Find("Point Cloud/Point");
                        pntsCo.DownloadOnStart = false;
                        this.Tileset.Behaviour.StartCoroutine(pntsCo.Download(finished));
                    }
                });
                Request request = new Request(this, priority, started, finished);
                this.Tileset.RequestManager.EnqueRequest(request);
            }
        }
Example #3
0
        public static IEnumerator Load(IndexMode mode, string tileUrl, Action <Unity3DTileIndex> success,
                                       Action <IndexMode, string, string> fail)
        {
            if (mode == IndexMode.Default || mode == IndexMode.None)
            {
                success(null);
                yield break;
            }

            string url  = UrlUtils.ReplaceDataProtocol(tileUrl);
            string dir  = UrlUtils.GetBaseUri(tileUrl);
            string file = UrlUtils.GetLastPathSegment(tileUrl);

            var filesToTry = new Queue <string>();

            if (mode == IndexMode.ExternalPNG)
            {
                filesToTry.Enqueue(UrlUtils.StripUrlExtension(file) + "_index.png");
                filesToTry.Enqueue(UrlUtils.ChangeUrlExtension(file, ".png"));
            }
            else if (mode == IndexMode.ExternalPPM)
            {
                filesToTry.Enqueue(UrlUtils.StripUrlExtension(file) + "_index.ppm");
                filesToTry.Enqueue(UrlUtils.ChangeUrlExtension(file, ".ppm"));
            }
            else if (mode == IndexMode.ExternalPPMZ)
            {
                filesToTry.Enqueue(UrlUtils.StripUrlExtension(file) + "_index.ppmz");
                filesToTry.Enqueue(UrlUtils.ChangeUrlExtension(file, ".ppmz"));
            }
            else
            {
                filesToTry.Enqueue(file);
            }

            Stream    stream    = null;
            Exception exception = null;
            string    ext       = null;

            while (stream == null && filesToTry.Count > 0)
            {
                exception = null;
                IEnumerator enumerator = null;
                ILoader     loader     = null;
                try
                {
                    file   = filesToTry.Dequeue();
                    ext    = UrlUtils.GetUrlExtension(file).ToLower();
                    loader = AbstractWebRequestLoader.CreateDefaultRequestLoader(dir);
                    if (ext == ".b3dm")
                    {
                        loader = new B3DMLoader(loader);
                    }
                    //yield return loader.LoadStream(file); //works but can't catch exceptions
                    enumerator = loader.LoadStream(file);
                }
                catch (Exception ex)
                {
                    exception = ex;
                }
                while (exception == null)
                {
                    try
                    {
                        if (!enumerator.MoveNext())
                        {
                            break;
                        }
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                        break;
                    }
                    yield return(enumerator.Current);
                }

                if (exception == null && loader.LoadedStream != null && loader.LoadedStream.Length > 0)
                {
                    stream = loader.LoadedStream;
                    stream.Seek(0, SeekOrigin.Begin);
                }
            }

            if (stream == null || stream.Length == 0)
            {
                fail(mode, tileUrl, "download failed" + (exception != null ? (" " + exception.Message) : ""));
                yield break;
            }

            try
            {
                if (ext == ".b3dm" || ext == ".glb")
                {
                    success(LoadFromGLB(stream));
                }
                else if (ext == ".gltf")
                {
                    success(LoadFromGLTF(stream));
                }
                else if (ext == ".png")
                {
                    success(LoadFromPNG(stream));
                }
                else if (ext == ".ppm" || ext == ".ppmz")
                {
                    success(LoadFromPPM(stream, compressed: ext == ".ppmz"));
                }
                else
                {
                    fail(mode, tileUrl, "unhandled file type: " + ext);
                }
            }
            catch (Exception ex)
            {
                fail(mode, tileUrl, "failed to parse " + file + ": " + ex.Message + "\n" + ex.StackTrace);
            }
        }