protected virtual IEnumerator LoadImage(string rootPath, GLTF.Schema.Image image, int imageID) { if (_assetCache.ImageCache[imageID] == null) { Texture2D texture = null; if (image.Uri != null) { var uri = image.Uri; Regex regex = new Regex(Base64StringInitializer); Match match = regex.Match(uri); if (match.Success) { var base64Data = uri.Substring(match.Length); var textureData = Convert.FromBase64String(base64Data); texture = new Texture2D(0, 0); texture.LoadImage(textureData); } else if (_loadType == LoadType.Uri) { var www = UnityWebRequest.Get(Path.Combine(rootPath, uri)); www.downloadHandler = new DownloadHandlerTexture(); yield return(www.Send()); // HACK to enable mipmaps :( var tempTexture = DownloadHandlerTexture.GetContent(www); if (tempTexture != null) { texture = new Texture2D(tempTexture.width, tempTexture.height, tempTexture.format, true); texture.SetPixels(tempTexture.GetPixels()); texture.Apply(true); } else { Debug.LogFormat("{0} {1}", www.responseCode, www.url); texture = new Texture2D(16, 16); } } else if (_loadType == LoadType.Stream) { var pathToLoad = Path.Combine(rootPath, uri); var file = File.OpenRead(pathToLoad); byte[] bufferData = new byte[file.Length]; file.Read(bufferData, 0, (int)file.Length); #if !WINDOWS_UWP file.Close(); #else file.Dispose(); #endif texture = new Texture2D(0, 0); texture.LoadImage(bufferData); } } else { texture = new Texture2D(0, 0); var bufferView = image.BufferView.Value; var buffer = bufferView.Buffer.Value; var data = new byte[bufferView.ByteLength]; var bufferContents = _assetCache.BufferCache[bufferView.Buffer.Id]; System.Buffer.BlockCopy(bufferContents, bufferView.ByteOffset, data, 0, data.Length); texture.LoadImage(data); } _assetCache.ImageCache[imageID] = texture; } }
/// <summary> /// Creates a scene based off loaded JSON. Includes loading in binary and image data to construct the meshes required. /// </summary> /// <param name="sceneIndex">The index of scene in gltf file to load</param> /// <param name="isMultithreaded">Whether to use a thread to do loading</param> /// <returns></returns> protected IEnumerator ImportScene(int sceneIndex = -1, bool isMultithreaded = false) { GLTF.Schema.Scene scene; if (sceneIndex >= 0 && sceneIndex < _root.Scenes.Count) { scene = _root.Scenes[sceneIndex]; } else { scene = _root.GetDefaultScene(); } if (scene == null) { throw new Exception("No default scene in gltf file."); } _assetCache = new AssetCache( _root.Images != null ? _root.Images.Count : 0, _root.Textures != null ? _root.Textures.Count : 0, _root.Materials != null ? _root.Materials.Count : 0, _root.Buffers != null ? _root.Buffers.Count : 0, _root.Meshes != null ? _root.Meshes.Count : 0 ); if (_lastLoadedScene == null) { if (_root.Buffers != null) { // todo add fuzzing to verify that buffers are before uri for (int i = 0; i < _root.Buffers.Count; ++i) { GLTF.Schema.Buffer buffer = _root.Buffers[i]; if (buffer.Uri != null) { yield return(LoadBuffer(_gltfDirectoryPath, buffer, i)); } else //null buffer uri indicates GLB buffer loading { byte[] glbBuffer; GLTFParser.ExtractBinaryChunk(_gltfData, i, out glbBuffer); _assetCache.BufferCache[i] = glbBuffer; } } } if (_root.Images != null) { for (int i = 0; i < _root.Images.Count; ++i) { GLTF.Schema.Image image = _root.Images[i]; yield return(LoadImage(_gltfDirectoryPath, image, i)); } } #if !WINDOWS_UWP // generate these in advance instead of as-needed if (isMultithreaded) { yield return(_asyncAction.RunOnWorkerThread(() => BuildAttributesForMeshes())); } #endif } var sceneObj = CreateScene(scene); if (_sceneParent != null) { sceneObj.transform.SetParent(_sceneParent, false); } // Experiment with fitting the scene into a prescribed size by accumulating // all of the scenes nodes bounding boxes and then scaling the root node // (I think this would be better as a mode to scale vertices but not for now..) var allRenderersInScene = sceneObj.GetComponentsInChildren <Renderer>(false); Bounds?box = null; foreach (var renderer in allRenderersInScene) { //CreateBox(sceneObj.transform, renderer.bounds); if (!box.HasValue) { box = new Bounds(renderer.bounds.center, renderer.bounds.size); } else { var val = box.Value; val.Encapsulate(renderer.bounds); box = val; } } //CreateBox(sceneObj.transform, box); // Now, for each individual mesh we can move the pivot to the bottom/centre // w.r.t the vertices. This way we can easily place models on a flat surface var allMeshesInScene = sceneObj.GetComponentsInChildren <MeshFilter>(false); foreach (var renderer in allMeshesInScene) { var bbox = renderer.mesh.bounds; // Calculate the distances we need to shift all of the vertices in // each direction to get them centred in x and z and have them sitting // at zero in the y-axis float adjustY = bbox.center.y; float adjustx = bbox.center.x; float adjustZ = bbox.center.z; //var verts = renderer.mesh.vertices; //for (int i = 0; i < verts.Length; i++) //{ // verts[i].x = verts[i].x - adjustx; // verts[i].y = verts[i].y - adjustY; // verts[i].z = verts[i].z - adjustZ; //} //renderer.mesh.vertices = verts; } Vector3 targetSize = Vector3.one / 4.0f; Vector3 sceneBoundsSize = box.Value.max - box.Value.min; float ratioX = targetSize.x / sceneBoundsSize.x; float ratioY = targetSize.y / sceneBoundsSize.y; float ratioZ = targetSize.z / sceneBoundsSize.z; float biggest = Math.Min(ratioZ, Math.Min(ratioX, ratioY)); //sceneObj.transform.localScale = sceneObj.transform.localScale * // (componentMax(targetSize) / componentMax(sceneBoundsSize)); //float f = componentMax(div(targetSize, sceneBoundsSize)); sceneObj.transform.localScale = sceneObj.transform.localScale * biggest; _lastLoadedScene = sceneObj; }