Beispiel #1
0
        GameObject LoadGltf(List <string> warnings)
        {
            // This is intended to be identical to using GltfModelBuilder, except synchronous.
            GameObject go;
            bool       fromPoly      = (m_Location.GetLocationType() == Location.Type.PolyAssetId);
            string     localPath     = m_Location.AbsolutePath;
            string     assetLocation = Path.GetDirectoryName(localPath);
            // Synchronous, so don't use slow image loading
            var loader = new TiltBrushUriLoader(localPath, assetLocation, loadImages: false);

            try
            {
                ImportGltf.GltfImportResult result = ImportGltf.Import(
                    localPath, loader,
                    new ImportMaterialCollector(assetLocation, uniqueSeed: localPath),
                    fromPoly ? kPolyGltfImportOptions : kGltfImportOptions);
                go = result.root;
                m_ImportMaterialCollector = (ImportMaterialCollector)result.materialCollector;
            }
            catch (Exception ex)
            {
                m_LoadError   = new LoadError("Invalid data", ex.Message);
                go            = null;
                m_AllowExport = false;
                Debug.LogException(ex);
            }

            m_AllowExport = (go != null);
            return(go);
        }
Beispiel #2
0
        public override void OnImportAsset(AssetImportContext ctx)
        {
            IUriLoader loader = new BufferedStreamLoader(
                ctx.assetPath, Path.GetDirectoryName(ctx.assetPath));

            ImportGltf.GltfImportResult result = ImportGltf.Import(
                ctx.assetPath, loader, null, kOptions);

            // The "identifier" param passed here is supposed to be:
            // - Unique to this asset
            // - Deterministic (if possible)
            foreach (var obj in result.textures)
            {
                if (!AssetDatabase.Contains(obj))
                {
                    ctx.AddObjectToAsset("Texture/" + obj.name, obj);
                }
            }
            foreach (var obj in result.materials)
            {
                ctx.AddObjectToAsset("Material/" + obj.name, obj);
            }
            foreach (var obj in result.meshes)
            {
                ctx.AddObjectToAsset("Mesh/" + obj.name, obj);
            }
            string objectName = Path.GetFileNameWithoutExtension(ctx.assetPath);

            result.root.name = objectName;
            ctx.AddObjectToAsset("ROOT", result.root);
            ctx.SetMainObject(result.root);
        }
Beispiel #3
0
            protected override GameObject DoUnityThreadWork(IDisposable state__,
                                                            out IEnumerable <Null> meshEnumerable,
                                                            out ImportMaterialCollector
                                                            importMaterialCollector)
            {
                meshEnumerable          = null;
                importMaterialCollector = null;
                GameObject rootObject = null;

                using (IDisposable state_ = state__)
                {
                    var state = state_ as ImportGltf.ImportState;
                    if (state != null)
                    {
                        string assetLocation = Path.GetDirectoryName(m_localPath);
                        // EndImport doesn't try to use the loadImages functionality of UriLoader anyway.
                        // It knows it's on the main thread, so chooses to use Unity's fast loading.
                        var loader = new TiltBrushUriLoader(m_localPath, assetLocation, loadImages: false);
                        ImportGltf.GltfImportResult result =
                            ImportGltf.EndImport(
                                state, loader,
                                new ImportMaterialCollector(assetLocation, uniqueSeed: m_localPath),
                                out meshEnumerable);

                        if (result != null)
                        {
                            rootObject = result.root;
                            importMaterialCollector = (ImportMaterialCollector)result.materialCollector;
                        }
                    }
                }
                IsValid = (rootObject != null);
                return(rootObject);
            }
        // Save like so:
        // PtAsset (references GameObject)
        //   Meshes, Textures, Materials
        // GameObject
        //   References sub-asset meshes in PtAsset
        //
        // Does not currently handle replacement
        static void SaveAsSeparateWithMeshesInAsset(
            ImportGltf.GltfImportResult result, string assetPath, string prefabPath)
        {
            Directory.CreateDirectory(Path.GetDirectoryName(assetPath));
            Directory.CreateDirectory(Path.GetDirectoryName(prefabPath));

            GameObject prefabToReplace = null; {
                PtAsset assetToReplace = AssetDatabase.LoadAssetAtPath <PtAsset>(assetPath);
                if (assetToReplace != null)
                {
                    if (assetToReplace.assetPrefab == null)
                    {
                        Debug.LogErrorFormat("Couldn't find prefab for asset {0}.", assetToReplace);
                        return;
                    }
                    prefabToReplace = assetToReplace.assetPrefab;
                }
            }

            PtAsset ptAsset = ScriptableObject.CreateInstance <PtAsset>();

            ptAsset.title = "bogus title";
            // Must make ptAsset a real asset before adding objects to it
            AssetDatabase.CreateAsset(ptAsset, assetPath);
            // Should make meshes real assets before saving them into a prefab
            AddResultsToAsset(result, ptAsset);
            AssetDatabase.ImportAsset(assetPath);

            // Create prefab after meshes are safely ensconced as assets
            result.root.AddComponent <PtAssetObject>().asset = ptAsset;

            GameObject newPrefab = null;

            if (prefabToReplace != null)
            {
                // Replace the existing prefab with our new object, without breaking prefab connections.
                // There's nothing but prefab in the asset so we don't need to worry about clearing
                // anything else out.
                newPrefab = PrefabUtility.ReplacePrefab(
                    result.root, prefabToReplace, ReplacePrefabOptions.ReplaceNameBased);
            }
            else
            {
                if (File.Exists(prefabPath))
                {
                    // Could probably handle this like the case above; replace it.
                    Debug.LogErrorFormat("Unexpected: overwriting a prefab {0}", prefabPath);
                }
                else
                {
                    newPrefab = PrefabUtility.CreatePrefab(prefabPath, result.root);
                }
            }

            ptAsset.assetPrefab = newPrefab;
            EditorUtility.SetDirty(ptAsset);

            // Maybe not needed?
            AssetDatabase.Refresh();
        }
Beispiel #5
0
/*
 * public override void OnImportAsset(AssetImportContext ctx) {
 *  IUriLoader loader = new BufferedStreamLoader(
 *      ctx.assetPath, Path.GetDirectoryName(ctx.assetPath));
 *
 *  ImportGltf.GltfImportResult result = ImportGltf.Import(
 *      ctx.assetPath, loader, null, kOptions);
 *
 *  // The "identifier" param passed here is supposed to be:
 *  // - Unique to this asset
 *  // - Deterministic (if possible)
 *  foreach (var obj in result.textures) {
 *    if (! AssetDatabase.Contains(obj)) {
 *      ctx.AddObjectToAsset("Texture/" + obj.name, obj);
 *    }
 *  }
 *  foreach (var obj in result.materials) {
 *    ctx.AddObjectToAsset("Material/" + obj.name, obj);
 *  }
 *  foreach (var obj in result.meshes) {
 *    ctx.AddObjectToAsset("Mesh/" + obj.name, obj);
 *  }
 *  string objectName = Path.GetFileNameWithoutExtension(ctx.assetPath);
 *  result.root.name = objectName;
 *  ctx.AddObjectToAsset("ROOT", result.root);
 *  ctx.SetMainObject(result.root);
 * }
 */


        public static GameObject ImportTiltBrushAsset(string path)
        {
            IUriLoader loader = new BufferedStreamLoader(
                path, Path.GetDirectoryName(path));//Directory.GetParent(path).ToString());


            ImportGltf.GltfImportResult result = ImportGltf.Import(
                path, loader, null, kOptions);

            return(result.root);
        }
        public static void TestSaveAsSinglePrefab()
        {
            IUriLoader binLoader = new BufferedStreamLoader(Path.GetDirectoryName(Path.Combine(RepoRoot, kMoto)));

            ImportGltf.GltfImportResult result = null;
            using (TextReader reader = new StreamReader(Path.Combine(RepoRoot, kMoto))) {
                result = ImportGltf.Import(GltfSchemaVersion.GLTF1, reader, binLoader, PolyImportOptions.Default());
            }
            string prefabPath = "Assets/Poly/TestData/single_p.prefab";

            SaveAsSinglePrefab(result, prefabPath);
            GameObject.DestroyImmediate(result.root);
        }
        public static void TestSaveAsSeparateWithMeshesInAsset()
        {
            IUriLoader binLoader = new BufferedStreamLoader(Path.GetDirectoryName(Path.Combine(RepoRoot, kAllBrush10)));

            ImportGltf.GltfImportResult result = null;
            using (TextReader reader = new StreamReader(Path.Combine(RepoRoot, kAllBrush10))) {
                result = ImportGltf.Import(GltfSchemaVersion.GLTF1, reader, binLoader, PolyImportOptions.Default());
            }
            string assetPath  = "Assets/Poly/TestData/separate_a.asset";
            string prefabPath = "Assets/Poly/TestData/separate_p.prefab";

            SaveAsSeparateWithMeshesInAsset(result, assetPath, prefabPath);
            GameObject.DestroyImmediate(result.root);
        }
 static void AddResultsToAsset(ImportGltf.GltfImportResult result, UnityEngine.Object asset)
 {
     foreach (var texture in result.textures)
     {
         AssetDatabase.AddObjectToAsset(texture, asset);
     }
     foreach (var mesh in result.meshes)
     {
         AssetDatabase.AddObjectToAsset(mesh, asset);
     }
     foreach (var material in result.materials)
     {
         AssetDatabase.AddObjectToAsset(material, asset);
     }
 }
Beispiel #9
0
        public void Update()
        {
            // We process at most one import result per frame, to avoid doing too much work
            // in the main thread.
            ImportOperation operation;

            lock (finishedOperationsLock)
            {
                if (finishedOperations.Count == 0)
                {
                    return;
                }
                operation = finishedOperations.Dequeue();
            }

            if (!operation.status.ok)
            {
                // Import failed.
                operation.callback(operation.status, root: null, meshCreator: null);
                return;
            }

            try
            {
                IEnumerable meshCreator;
                ImportGltf.GltfImportResult result = ImportGltf.EndImport(operation.importState,
                                                                          operation.loader, out meshCreator);

                if (!operation.options.clientThrottledMainThread)
                {
                    // If we're not in throttled mode, create all the meshes immediately by exhausting
                    // the meshCreator enumeration. Otherwise, it's the caller's responsibility to
                    // do this.
                    foreach (var unused in meshCreator) /* empty */ } {
                    meshCreator = null;
            }
            // Success.
            operation.callback(PolyStatus.Success(), result.root, meshCreator);
        }
        catch (Exception ex)
        {
            // Import failed.
            Debug.LogException(ex);
            operation.callback(PolyStatus.Error("Failed to convert import to Unity objects.", ex),
                               root: null, meshCreator: null);
        }
    }
        // Save like so:
        // GameObject
        //   Meshes, Textures, Materials
        //   Sub-objects reference sibling meshes
        //   PtAsset references the top-level prefab
        //
        // When replacing an existing prefab:
        // - scene objects that reference the prefab get properly updated
        // - Unless explicitly destroyed, old meshes stick around in the prefab and are
        //   not replaced (so the prefab has many meshes with duplicate names)
        // - Scene objects that reference mesh sub-assets keep referencing the same mesh
        //   (if they are left around) or get dangling mesh references (if they are destroyed)
        //   There is no known way to replace the existing meshes by name or otherwise,
        //   unless we implement it manually (eg by mutating the mesh sub-assets)
        //
        static void SaveAsSinglePrefab(
            ImportGltf.GltfImportResult result, string prefabPath)
        {
            Directory.CreateDirectory(Path.GetDirectoryName(prefabPath));

            PtAsset ptAsset = ScriptableObject.CreateInstance <PtAsset>();

            ptAsset.name = Path.GetFileName(prefabPath).Replace(".prefab", "");

            GameObject oldPrefab = AssetDatabase.LoadAssetAtPath <GameObject>(prefabPath);
            GameObject prefab    = null;

            if (oldPrefab == null)
            {
                // Chicken and egg problem: the Meshes aren't assets yet, so refs to them will dangle
                prefab = PrefabUtility.CreatePrefab(prefabPath, result.root);
                AddResultsToAsset(result, prefab);
                // This fixes up the dangling refs
                prefab = PrefabUtility.ReplacePrefab(result.root, prefab);
            }
            else
            {
                // ReplacePrefab only removes the GameObjects from the asset.
                // Clear out all non-prefab junk (ie, meshes), because otherwise it piles up.
                // The main difference between LoadAllAssetRepresentations and LoadAllAssets
                // is that the former returns MonoBehaviours and the latter does not.
                foreach (var obj in AssetDatabase.LoadAllAssetRepresentationsAtPath(prefabPath))
                {
                    if (!(obj is GameObject))
                    {
                        Object.DestroyImmediate(obj, allowDestroyingAssets: true);
                    }
                }
                AddResultsToAsset(result, oldPrefab);
                prefab = PrefabUtility.ReplacePrefab(
                    result.root, oldPrefab, ReplacePrefabOptions.ReplaceNameBased);
            }
            AssetDatabase.AddObjectToAsset(ptAsset, prefab);
            ptAsset.assetPrefab = prefab;
            EditorUtility.SetDirty(ptAsset);
            AssetDatabase.ImportAsset(prefabPath);
        }
Beispiel #11
0
        /// <summary>
        /// Executes the given import request, producing a PtAsset and a prefab.
        /// </summary>
        /// <param name="request">The request to perform.</param>
        private static void ExecuteImportRequest(ImportRequest request)
        {
            PtDebug.LogFormat("Executing import request: {0}", request);

            string gltfFullPath   = PtUtils.ToAbsolutePath(request.gltfLocalPath);
            string assetLocalPath = request.ptAssetLocalPath;
            string assetFullPath  = PtUtils.ToAbsolutePath(assetLocalPath);

            PtAsset assetToReplace = AssetDatabase.LoadAssetAtPath <PtAsset>(assetLocalPath);

            GameObject prefabToReplace = null;

            if (assetToReplace != null)
            {
                if (assetToReplace.assetPrefab == null)
                {
                    Debug.LogErrorFormat("Couldn't find prefab for asset {0}.", assetToReplace);
                    PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_FAILED, "Prefab not found");
                    return;
                }
                prefabToReplace = assetToReplace.assetPrefab;
            }

            // Determine if file is glTF2 or glTF1.
            bool isGltf2 = Path.GetExtension(request.gltfLocalPath) == ".gltf2";

            // First, import the GLTF and build a GameObject from it.
            EditorUtility.DisplayProgressBar(PROGRESS_BAR_TITLE, PROGRESS_BAR_TEXT, 0.5f);
            // Use a SanitizedPath stream loader because any format file we have downloaded and saved to disk we
            // have replaced the original relative path string with the MD5 string hash. This custom stream loader
            // will always convert uris passed to it to this hash value, and read them from there.
            IUriLoader binLoader = new HashedPathBufferedStreamLoader(Path.GetDirectoryName(gltfFullPath));

            ImportGltf.GltfImportResult result = null;
            using (TextReader reader = new StreamReader(gltfFullPath)) {
                result = ImportGltf.Import(isGltf2 ? GltfSchemaVersion.GLTF2 : GltfSchemaVersion.GLTF1,
                                           reader, binLoader, request.options.baseOptions);
            }
            EditorUtility.ClearProgressBar();
            string baseName = PtUtils.GetPtAssetBaseName(request.polyAsset);

            result.root.name = baseName;

            // Create the asset (delete it first if it exists).
            if (File.Exists(assetFullPath))
            {
                AssetDatabase.DeleteAsset(assetLocalPath);

                // If we are replacing an existing asset, we should rename the replacement to the new name,
                // since the name reflects the identity of the asset. So if the user is importing the asset
                // dog_a381b3g to replace what was previously cat_v81938.asset, the replacement file should
                // be named dog_a381b3g.asset, not cat_v81938.asset.
                assetLocalPath = PtUtils.GetDefaultPtAssetPath(request.polyAsset);
                assetFullPath  = PtUtils.ToAbsolutePath(assetLocalPath);
            }
            Directory.CreateDirectory(Path.GetDirectoryName(assetFullPath));

            // Create the new PtAsset and fill it in.
            AssetDatabase.CreateAsset(ScriptableObject.CreateInstance <PtAsset>(), assetLocalPath);
            PtAsset newAsset = AssetDatabase.LoadAssetAtPath <PtAsset>(assetLocalPath);

            newAsset.name    = baseName;
            newAsset.title   = request.polyAsset.displayName ?? "";
            newAsset.author  = request.polyAsset.authorName ?? "";
            newAsset.license = request.polyAsset.license;
            newAsset.url     = request.polyAsset.Url;

            // Ensure the imported object has a PtAssetObject component which references the PtAsset.
            result.root.AddComponent <PtAssetObject>().asset = newAsset;

            // Add all the meshes to the PtAsset.
            SaveMeshes(result.meshes, newAsset);

            // If the asset has materials, save those to the PtAsset.
            if (result.materials != null)
            {
                SaveMaterials(result.materials, newAsset);
            }

            // If the asset has textures, save those to the PtAsset.
            if (result.textures != null)
            {
                SaveTextures(result.textures, newAsset);
            }

            // Reimport is required to ensure custom asset displays correctly.
            AssetDatabase.ImportAsset(assetLocalPath);

            GameObject newPrefab;

            if (prefabToReplace)
            {
                // Replace the existing prefab with our new object, without breaking prefab connections.
                newPrefab = PrefabUtility.ReplacePrefab(result.root, prefabToReplace, ReplacePrefabOptions.ReplaceNameBased);
                AssetDatabase.RenameAsset(AssetDatabase.GetAssetPath(newPrefab), baseName);
            }
            else
            {
                // Create a new prefab.
                // Prefab path is the same as the asset path but with the extension changed to '.prefab'.
                string prefabLocalPath = Regex.Replace(assetLocalPath, "\\.asset$", ".prefab");
                if (!prefabLocalPath.EndsWith(".prefab"))
                {
                    Debug.LogErrorFormat("Error: failed to compute prefab path for {0}", assetLocalPath);
                    PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_FAILED, "Prefab path error");
                    return;
                }
                newPrefab = PrefabUtility.CreatePrefab(prefabLocalPath, result.root);
            }

            // Now ensure the asset points to the prefab.
            newAsset.assetPrefab = newPrefab;
            if (newAsset.assetPrefab == null)
            {
                Debug.LogErrorFormat("Could not get asset prefab reference for asset {0}", newAsset);
                PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_FAILED, "Prefab ref error");
            }

            GameObject.DestroyImmediate(result.root);

            AssetDatabase.Refresh();

            if (request.options.alsoInstantiate)
            {
                PrefabUtility.InstantiatePrefab(newPrefab);
            }

            PtDebug.LogFormat("GLTF import complete: {0}", request);

            PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_SUCCESSFUL, isGltf2 ? "GLTF2" : "GLTF1");

            // If this is a third-party asset, we need to update the attributions file.
            AttributionFileGenerator.Generate(/* showUi */ false);

            EditorWindow.GetWindow <AssetBrowserWindow>().HandleAssetImported(request.polyAsset.name);

            // Select the prefab in the editor so the user knows where it is.
            AssetDatabase.Refresh();
            Selection.activeObject = newPrefab;
            EditorGUIUtility.PingObject(newPrefab);
        }