Exemple #1
0
        public virtual void ImportParametersFromUsd(Scene scene,
                                                    string materialPath,
                                                    MaterialSample materialSample,
                                                    PreviewSurfaceSample previewSurf,
                                                    SceneImportOptions options)
        {
            var    primvars  = new List <string>();
            string uvPrimvar = null;

            ImportColorOrMap(scene, previewSurf.diffuseColor, false, options, ref DiffuseMap, ref Diffuse, out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportColorOrMap(scene, previewSurf.emissiveColor, false, options, ref EmissionMap, ref Emission, out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportValueOrMap(scene, previewSurf.normal, true, options, ref NormalMap, ref Normal, out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportValueOrMap(scene, previewSurf.displacement, false, options, ref DisplacementMap, ref Displacement, out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportValueOrMap(scene, previewSurf.occlusion, false, options, ref OcclusionMap, ref Occlusion, out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportValueOrMap(scene, previewSurf.roughness, false, options, ref RoughnessMap, ref Roughness, out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportValueOrMap(scene, previewSurf.clearcoat, false, options, ref ClearcoatMap, ref Clearcoat, out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ClearcoatRoughness = previewSurf.clearcoatRoughness.defaultValue;

            if (previewSurf.useSpecularWorkflow.defaultValue == 1)
            {
                ImportColorOrMap(scene, previewSurf.specularColor, false, options, ref SpecularMap, ref Specular, out uvPrimvar);
                MergePrimvars(uvPrimvar, primvars);
            }
            else
            {
                ImportValueOrMap(scene, previewSurf.metallic, false, options, ref MetallicMap, ref Metallic, out uvPrimvar);
                MergePrimvars(uvPrimvar, primvars);
            }

            options.materialMap.SetPrimvars(materialPath, primvars);
        }
Exemple #2
0
        /// <summary>
        /// Optimizes the given import options for fast playback. This assumes that the asset was
        /// previously imported, therefore it disables import of the material and scene hierarchy.
        /// </summary>
        public static void PrepOptionsForTimeChange(ref SceneImportOptions options)
        {
            options.forceRebuild       = false;
            options.materialImportMode = MaterialImportMode.None;
            options.meshOptions.debugShowSkeletonBindPose = false;
            options.meshOptions.debugShowSkeletonRestPose = false;

            options.meshOptions.generateLightmapUVs = false;
            options.importSkinWeights = false;

            // Note that tangent and Normals must be updated when the mesh deforms.
            options.importHierarchy = false;

            options.meshOptions.texcoord0 = ImportMode.Ignore;
            options.meshOptions.texcoord1 = ImportMode.Ignore;
            options.meshOptions.texcoord2 = ImportMode.Ignore;
            options.meshOptions.texcoord3 = ImportMode.Ignore;
        }
Exemple #3
0
 protected void ImportValueOrMap <T>(Scene scene,
                                     Connectable <T> usdParam,
                                     bool isNormalMap,
                                     SceneImportOptions options,
                                     ref Texture2D map,
                                     ref T?value,
                                     out string uvPrimvar) where T : struct
 {
     uvPrimvar = null;
     if (usdParam.IsConnected())
     {
         map = MaterialImporter.ImportConnectedTexture(scene, usdParam, isNormalMap, options, out uvPrimvar);
     }
     else
     {
         value = usdParam.defaultValue;
     }
 }
Exemple #4
0
        public static void BuildSkeletonBone(string skelPath,
                                             GameObject go,
                                             Matrix4x4 restXform,
                                             VtTokenArray joints,
                                             SceneImportOptions importOptions)
        {
            // Perform change of basis, if needed.
            XformImporter.ImportXform(ref restXform, importOptions);

            // Decompose into TSR.
            Vector3    pos   = Vector3.zero;
            Quaternion rot   = Quaternion.identity;
            Vector3    scale = Vector3.one;

            if (!UnityTypeConverter.Decompose(restXform, out pos, out rot, out scale))
            {
                throw new Exception("Failed to decompose bind trnsforms for <" + skelPath + ">");
            }
            go.transform.localScale    = scale;
            go.transform.localRotation = rot;
            go.transform.localPosition = pos;

            var cubeDebugName = "usdSkel_restPose_debug_cube";

            if (importOptions.meshOptions.debugShowSkeletonRestPose)
            {
                var cube = go.transform.Find(cubeDebugName);
                if (!cube)
                {
                    cube      = GameObject.CreatePrimitive(PrimitiveType.Cube).transform;
                    cube.name = cubeDebugName;
                    cube.SetParent(go.transform, worldPositionStays: false);
                    cube.localScale = Vector3.one * 2;
                }
            }
            else
            {
                var existing = go.transform.Find(cubeDebugName);
                if (existing)
                {
                    GameObject.DestroyImmediate(existing.gameObject);
                }
            }
        }
        /// <summary>
        /// Computes the bound material using UsdShade's inherited binding logic.
        /// If a material is bound, the request callback is executed to enable the caller to bind the
        /// material to the Unity geometry.
        /// </summary>
        public static void ProcessMaterialBindings(Scene scene, SceneImportOptions importOptions)
        {
            var requests = importOptions.materialMap.ClearRequestedBindings();
            var prims    = new pxr.UsdPrimVector();

            foreach (var pathAndRequest in requests)
            {
                var prim = scene.GetPrimAtPath(pathAndRequest.Key);
                if (prim == null)
                {
                    continue;
                }

                prims.Add(prim);
            }

            var matVector = pxr.UsdShadeMaterialBindingAPI.ComputeBoundMaterials(prims, materialBindToken);
            var matIndex  = -1;

            foreach (pxr.UsdShadeMaterial usdMat in matVector)
            {
                matIndex++;
                Material unityMat = importOptions.materialMap[usdMat.GetPath()];

                if (unityMat == null)
                {
                    continue;
                }

                // PERF: this is slow and garbage-y.
                string meshPath = prims[matIndex].GetPath();

                if (!requests.ContainsKey(meshPath))
                {
                    Debug.LogError("Source object key not found: " + meshPath);
                    continue;
                }

                System.Collections.Generic.List <string> primvars
                    = importOptions.materialMap.GetPrimvars(usdMat.GetPath());

                requests[meshPath](scene, unityMat, primvars);
            }
        }
Exemple #6
0
        public static void MenuImportAsPrefab()
        {
            var scene = InitForOpen();

            if (scene == null)
            {
                return;
            }

            string path = scene.FilePath;

            // Time-varying data is not supported and often scenes are written without "Default" time
            // values, which makes setting an arbitrary time safer (because if only default was authored
            // the time will be ignored and values will resolve to default time automatically).
            scene.Time = 1.0;

            var importOptions = new SceneImportOptions();

            importOptions.projectAssetPath   = GetSelectedAssetPath();
            importOptions.changeHandedness   = BasisTransformation.SlowAndSafe;
            importOptions.materialImportMode = MaterialImportMode.ImportDisplayColor;
            importOptions.usdRootPath        = GetDefaultRoot(scene);

            var invalidChars = Path.GetInvalidFileNameChars();
            var prefabName   = string.Join("_", GetPrefabName(path).Split(invalidChars,
                                                                          System.StringSplitOptions.RemoveEmptyEntries)).TrimEnd('.');
            string prefabPath = importOptions.projectAssetPath + prefabName + ".prefab";

            prefabPath = AssetDatabase.GenerateUniqueAssetPath(prefabPath);
            string clipName = Path.GetFileNameWithoutExtension(path);

            var go = new GameObject(GetObjectName(importOptions.usdRootPath, path));

            try
            {
                UsdToGameObject(go, scene, importOptions);
                SceneImporter.SavePrefab(go, prefabPath, clipName, importOptions);
            }
            finally
            {
                GameObject.DestroyImmediate(go);
                scene.Close();
            }
        }
Exemple #7
0
        /// <summary>
        /// Sets the variant selections in USD at the given prim path based on the selections parameter.
        /// </summary>
        /// <param name="go">The gameObject at the root of the variant set.</param>
        /// <param name="usdPrimPath">The USD prim at which to set the variant selection.</param>
        /// <param name="selections">A collection of (variant set, selection) pairs.</param>
        /// <remarks>
        /// A USD prim can have zero or more variant sets, for example a single prim amy have
        /// "modelingVariant" and "shadingVariant" sets. Each set can have their own slection.
        /// </remarks>
        /// <example>
        /// If two sets with selections are modelingVariant=CupWithHandle and shadingVariant=BrightBlue,
        /// resulting in a bright blue cup with a handle. In this example, the selections dictionary
        /// would contain:
        ///  { "modelingVariant" = "CupWithHandle",
        ///    "shadingVariant" = "BrightBlue" }
        /// </example>
        public void SetVariantSelection(GameObject go,
                                        string usdPrimPath,
                                        Dictionary <string, string> selections)
        {
            InitUsd.Initialize();
            var scene = GetScene();

            if (scene == null)
            {
                throw new Exception("Failed to open: " + usdFullPath);
            }

            var prim = scene.GetPrimAtPath(usdPrimPath);

            if (prim == null || !prim)
            {
                throw new Exception("Prim not found: " + usdPrimPath);
            }

            var varSets = prim.GetVariantSets();

            foreach (var sel in selections)
            {
                if (!varSets.HasVariantSet(sel.Key))
                {
                    throw new Exception("Unknown varient set: " + sel.Key + " at " + usdPrimPath);
                }

                varSets.GetVariantSet(sel.Key).SetVariantSelection(sel.Value);
            }

            // TODO: sparsely remove prims, rather than blowing away all the children.
            foreach (Transform child in go.transform)
            {
                GameObject.DestroyImmediate(child.gameObject);
            }

            SceneImportOptions importOptions = new SceneImportOptions();

            this.StateToOptions(ref importOptions);
            importOptions.usdRootPath = prim.GetPath();
            SceneImporter.ImportUsd(go, scene, new PrimMap(), true, importOptions);
        }
Exemple #8
0
        /// <summary>
        /// If there is a Payload authored on this prim, expose it so the user can change the
        /// load state.
        /// </summary>
        static void AddPayload(GameObject go, HierInfo info, SceneImportOptions options)
        {
            var pl = go.GetComponent <UsdPayload>();

            if (!info.hasPayload)
            {
                if (pl)
                {
                    Component.DestroyImmediate(pl);
                }
                return;
            }

            if (!pl)
            {
                pl = go.AddComponent <UsdPayload>();
                pl.SetInitialState(options.payloadPolicy == PayloadPolicy.LoadAll);
            }
        }
        public static GameObject ImportSceneAsGameObject(Scene scene, GameObject parent = null, SceneImportOptions importOptions = null)
        {
            if (scene == null || scene.Stage == null)
            {
                Debug.LogError("The USD Scene needs to be opened before being imported.");
                return(null);
            }

            string path = scene.FilePath;

            // Time-varying data is not supported and often scenes are written without "Default" time
            // values, which makes setting an arbitrary time safer (because if only default was authored
            // the time will be ignored and values will resolve to default time automatically).
            scene.Time = 1.0;

            if (importOptions == null)
            {
                importOptions             = new SceneImportOptions();
                importOptions.usdRootPath = GetDefaultRoot(scene);
            }

            GameObject root = new GameObject(GetObjectName(importOptions.usdRootPath, path));

            if (parent != null)
            {
                root.transform.SetParent(parent.transform);
            }

            try
            {
                UsdToGameObject(root, scene, importOptions);
                return(root);
            }
            catch (SceneImporter.ImportException)
            {
#if UNITY_EDITOR
                Object.DestroyImmediate(root);
#else
                Object.Destroy(root);
#endif
                return(null);
            }
        }
Exemple #10
0
 protected void ImportColorOrMap(Scene scene,
                                 Connectable <Vector3> usdParam,
                                 bool isNormalMap,
                                 SceneImportOptions options,
                                 ref Texture2D map,
                                 ref Color?value,
                                 out string uvPrimvar)
 {
     uvPrimvar = null;
     if (usdParam.IsConnected())
     {
         map = MaterialImporter.ImportConnectedTexture(scene, usdParam, isNormalMap, options, out uvPrimvar);
     }
     else
     {
         var rgb = usdParam.defaultValue;
         value = new Color(rgb.x, rgb.y, rgb.z).gamma;
     }
 }
Exemple #11
0
        public static void ImportUsd(GameObject goRoot,
                                     Scene scene,
                                     PrimMap primMap,
                                     bool composingSubtree,
                                     SceneImportOptions importOptions)
        {
            if (scene == null)
            {
                throw new ImportException("Null USD Scene");
            }

            scene.SetInterpolation(importOptions.interpolate ?
                                   Scene.InterpolationMode.Linear :
                                   Scene.InterpolationMode.Held);

            SceneImporter.BuildScene(scene,
                                     goRoot,
                                     importOptions,
                                     primMap,
                                     composingSubtree);
        }
Exemple #12
0
        static HierInfo[] BuildObjectLists(Scene scene,
                                           GameObject unityRoot,
                                           SdfPath usdRoot,
                                           PrimMap map,
                                           SceneImportOptions options)
        {
            if (map.SkelCache == null)
            {
                // Note that UsdSkelCache is thread safe and can be populated from multiple threads.
                map.SkelCache = new UsdSkelCache();

                // The skelBindings dictionary, however, is not thread safe and must be populated after the
                // hierarchy discovery thread joins, in ProcessPaths.
                map.SkelBindings = new Dictionary <SdfPath, UsdSkelBindingVector>();
            }

            BeginReading(scene, usdRoot, map, options).Complete();
            ProcessPaths(ReadHierJob.result, scene, unityRoot, usdRoot, map, options);

            return(ReadHierJob.result);
        }
Exemple #13
0
        public static void MenuImportAsTimelineClip()
        {
            var scene = InitForOpen();

            if (scene == null)
            {
                return;
            }

            string path = scene.FilePath;

            var invalidChars = Path.GetInvalidFileNameChars();
            var prefabName   = string.Join("_", GetPrefabName(path).Split(invalidChars,
                                                                          System.StringSplitOptions.RemoveEmptyEntries)).TrimEnd('.');

            string prefabPath = GetSelectedAssetPath() + prefabName + ".prefab";

            prefabPath = AssetDatabase.GenerateUniqueAssetPath(prefabPath);
            string clipName = Path.GetFileNameWithoutExtension(path);

            var importOptions = new SceneImportOptions();

            importOptions.projectAssetPath   = GetSelectedAssetPath();
            importOptions.changeHandedness   = BasisTransformation.FastWithNegativeScale;
            importOptions.materialImportMode = MaterialImportMode.ImportDisplayColor;
            importOptions.usdRootPath        = GetDefaultRoot(scene);

            var go = new GameObject(GetObjectName(importOptions.usdRootPath, path));

            try
            {
                // Ensure we have at least one GameObject with the import settings.
                XformImporter.BuildSceneRoot(scene, go.transform, importOptions);
                SceneImporter.SavePrefab(go, prefabPath, clipName, importOptions);
            }
            finally
            {
                GameObject.DestroyImmediate(go);
            }
        }
        /// <summary>
        /// Copies the transform value from USD to Unity, optionally changing handedness in the
        /// process.
        /// </summary>
        public static void BuildXform(pxr.SdfPath path,
                                      XformableSample usdXf,
                                      GameObject go,
                                      SceneImportOptions options,
                                      Scene scene)
        {
            // If there is an access mask and it's not initially being populated, check to see if the
            // transform for this object actually varies over time, if not, we can simply return.
            if (scene.AccessMask != null && !scene.IsPopulatingAccessMask)
            {
                System.Reflection.MemberInfo transformMember = null;
                transformMember = usdXf.GetType().GetMember("transform")[0];
                HashSet <System.Reflection.MemberInfo> members;
                if (!scene.AccessMask.Included.TryGetValue(path, out members) ||
                    !members.Contains(transformMember))
                {
                    return;
                }
            }

            BuildXform(usdXf.transform, go, options);
        }
Exemple #15
0
 /// <summary>
 /// Rebuilds the USD scene as Unity GameObjects, maintaining a mapping from USD to Unity.
 /// </summary>
 public static PrimMap BuildScene(Scene scene,
                                  GameObject root,
                                  SceneImportOptions importOptions,
                                  PrimMap primMap,
                                  bool composingSubtree)
 {
     try {
         Profiler.BeginSample("USD: Build Scene");
         var builder = BuildScene(scene,
                                  root,
                                  importOptions,
                                  primMap,
                                  0,
                                  composingSubtree);
         while (builder.MoveNext())
         {
         }
         return(primMap);
     } finally {
         Profiler.EndSample();
     }
 }
Exemple #16
0
        static void MenuExportLoadFromUsd()
        {
            var scene = InitForOpen();

            if (scene == null)
            {
                return;
            }
            string path = scene.FilePath;

            // Time-varying data is not supported and often scenes are written without "Default" time
            // values, which makes setting an arbitrary time safer (because if only default was authored
            // the time will be ignored and values will resolve to default time automatically).
            scene.Time = 1.0;

            var importOptions = new SceneImportOptions();

            importOptions.projectAssetPath     = GetSelectedAssetPath();
            importOptions.changeHandedness     = BasisTransformation.SlowAndSafe;
            importOptions.materialImportMode   = MaterialImportMode.ImportDisplayColor;
            importOptions.usdRootPath          = GetDefaultRoot(scene);
            importOptions.importMonoBehaviours = true;

            GameObject root = new GameObject(GetObjectName(importOptions.usdRootPath, path));

            if (Selection.gameObjects.Length > 0)
            {
                root.transform.SetParent(Selection.gameObjects[0].transform);
            }

            try
            {
                UsdToGameObject(root, scene, importOptions);
            }
            finally
            {
                scene.Close();
            }
        }
Exemple #17
0
        /// <summary>
        /// Given an array of bone names (HierInfo.skelJoints), creates GameObjects under unityRoot.
        /// </summary>
        static void ExpandSkeleton(HierInfo info,
                                   GameObject unityRoot,
                                   SdfPath usdRoot,
                                   UsdPrim prim,
                                   PrimMap map,
                                   SceneImportOptions options)
        {
            foreach (var joint in info.skelJoints)
            {
                var        path     = joint;
                GameObject parentGo = null;
                if (!map.TryGetValue(path.GetParentPath(), out parentGo))
                {
                    // This will happen when the joints are discontinuous, for example:
                    //
                    //   Foo/Bar
                    //   Foo/Bar/Baz/Qux
                    //
                    // Baz is implicitly defined, which is allowed by UsdSkel.
                    CreateAncestors(path, map, unityRoot, usdRoot, options, out parentGo);
                    if (!parentGo)
                    {
                        Debug.LogException(new Exception("Failed to create ancestors for " + path + " for prim: " +
                                                         prim.GetPath()));
                        continue;
                    }
                }

                Transform child = parentGo.transform.Find(path.GetName());
                if (!child)
                {
                    child = new GameObject(path.GetName()).transform;
                    child.SetParent(parentGo.transform, worldPositionStays: false);
                }

                map[path] = child.gameObject;
            }
        }
        // -------------------------------------------------------------------------------------------- //
        // Deserialize USD to -> Unity
        // -------------------------------------------------------------------------------------------- //

        static public void ImportObject(Scene scene,
                                        GameObject go,
                                        pxr.UsdPrim usdPrim,
                                        SceneImportOptions options)
        {
            if (!options.importMonoBehaviours)
            {
                return;
            }

            var comps = usdPrim.GetAuthoredPropertiesInNamespace("unity:component");

            foreach (var compProp in comps)
            {
                var    compAttr = usdPrim.GetAttribute(compProp.GetName());
                string assemblyQualifiedName = (string)compAttr.Get(0);
                var    compType = System.Type.GetType(assemblyQualifiedName);

                // TODO: Handle multiple components of the same type.
                Component comp = go.GetComponent(compType);
                if (comp == null)
                {
                    comp = go.AddComponent(compType);
                }

                var so   = new SerializedObject(comp);
                var prop = so.GetIterator();
                prop.Next(true);
                var sb = new System.Text.StringBuilder();

                // TODO: Handle multiple components of the same type.
                PropertyFromUsd(usdPrim, prop, sb, comp.GetType().Name);

                so.ApplyModifiedProperties();
                Debug.Log(sb.ToString());
            }
        }
Exemple #19
0
        static void ProcessPaths(HierInfo[] infos,
                                 Scene scene,
                                 GameObject unityRoot,
                                 SdfPath usdRoot,
                                 PrimMap map,
                                 SceneImportOptions options)
        {
            Profiler.BeginSample("Process all paths");
            foreach (var info in infos)
            {
                var prim = info.prim;
                var path = info.prim.GetPath();

                if (info.skelBindings != null)
                {
                    // Collect all discovered skelBindings back into the PrimMap.
                    map.SkelBindings.Add(info.prim.GetPath(), info.skelBindings);
                }

                GameObject go;
                if (path == usdRoot)
                {
                    go = unityRoot;
                }
                else
                {
                    GameObject parentGo = null;
                    CreateAncestors(path, map, unityRoot, usdRoot, options, out parentGo);

                    if (!parentGo)
                    {
                        Debug.LogWarning("Parent path not found for child: " + path.ToString());
                        continue;
                    }

                    var parent = parentGo ? parentGo.transform : null;
                    if (!map.TryGetValue(path, out go))
                    {
                        go = FindOrCreateGameObject(parent,
                                                    path,
                                                    unityRoot.transform,
                                                    map,
                                                    options);
                    }
                }

                if (options.importSceneInstances)
                {
                    Profiler.BeginSample("Add Scene Instance Root");
                    if (prim.IsInstance())
                    {
                        map.AddInstanceRoot(prim.GetPath(), go, prim.GetMaster().GetPath());
                    }
                    Profiler.EndSample();
                }

                if (!options.importHierarchy)
                {
                    continue;
                }

                ApplySelfVisibility(go, prim);

                try {
                    Profiler.BeginSample("Add Model Root");
                    AddModelRoot(go, info);
                    Profiler.EndSample();

                    Profiler.BeginSample("Add Variant Set");
                    AddVariantSet(go, prim);
                    Profiler.EndSample();

                    Profiler.BeginSample("Add Payload");
                    AddPayload(go, info, options);
                    Profiler.EndSample();
                } catch (Exception ex) {
                    Debug.LogException(new Exception("Error processing " + prim.GetPath(), ex));
                }
            }
            Profiler.EndSample();
        }
Exemple #20
0
        /// <summary>
        /// Map all UsdPrims and build Unity GameObjects, reconstructing the parent relationship.
        /// </summary>
        /// <remarks>
        /// When forceRebuild is true, game objects will be destroyed and recreated. If buildHierarchy
        /// is false, the primMap will be populated, but missing game objects will not be created.
        /// </remarks>
        static public PrimMap BuildGameObjects(Scene scene,
                                               GameObject unityRoot,
                                               SdfPath usdRoot,
                                               IEnumerable <SdfPath> paths,
                                               PrimMap map,
                                               SceneImportOptions options)
        {
            map[usdRoot] = unityRoot;

            // Like all GameObjects imported from USD, ensure the root has a UsdPrimSource.
            if (unityRoot.GetComponent <UsdPrimSource>() == null)
            {
                var ua = unityRoot.AddComponent <UsdPrimSource>();
                ua.m_usdPrimPath = usdRoot.ToString();
            }

            Profiler.BeginSample("Build Object Lists");
            var hierInfo = BuildObjectLists(scene, unityRoot, usdRoot, map, options);

            Profiler.EndSample();

            // TODO: Should recurse to discover deeply nested instancing.
            // TODO: Generates garbage for every prim, but we expect few masters.
            if (options.importPointInstances || options.importSceneInstances)
            {
                Profiler.BeginSample("Build Masters");
                foreach (var masterRootPrim in scene.Stage.GetMasters())
                {
                    var goMaster = FindOrCreateGameObject(unityRoot.transform,
                                                          masterRootPrim.GetPath(),
                                                          unityRoot.transform,
                                                          map,
                                                          options);

                    goMaster.hideFlags = HideFlags.HideInHierarchy;
                    goMaster.SetActive(false);
                    map.AddMasterRoot(masterRootPrim.GetPath(), goMaster);
                    try {
                        var info = new HierInfo();
                        info.prim = masterRootPrim;
                        ReadModelInfo(ref info);
                        AddModelRoot(goMaster, info);
                        AddVariantSet(goMaster, masterRootPrim);
                    } catch (Exception ex) {
                        Debug.LogException(new Exception("Error processing " + masterRootPrim.GetPath(), ex));
                    }

                    foreach (var usdPrim in masterRootPrim.GetDescendants())
                    {
                        var       parentPath = usdPrim.GetPath().GetParentPath();
                        Transform parentXf   = null;
                        if (parentPath == masterRootPrim.GetPath())
                        {
                            parentXf = goMaster.transform;
                        }
                        else
                        {
                            parentXf = map[parentPath].transform;
                        }

                        var goPrim = FindOrCreateGameObject(parentXf,
                                                            usdPrim.GetPath(),
                                                            unityRoot.transform,
                                                            map,
                                                            options);
                        ApplySelfVisibility(goPrim, usdPrim);

                        if (usdPrim.IsInstance())
                        {
                            map.AddInstanceRoot(usdPrim.GetPath(), goPrim, usdPrim.GetMaster().GetPath());
                        }

                        try {
                            var info = new HierInfo();
                            info.prim = usdPrim;
                            ReadModelInfo(ref info);
                            AddModelRoot(goPrim, info);
                            AddVariantSet(goPrim, usdPrim);
                        } catch (Exception ex) {
                            Debug.LogException(new Exception("Error processing " + usdPrim.GetPath(), ex));
                            continue;
                        }
                    }
                }
                Profiler.EndSample();
            }

            if (options.importSkinning)
            {
                Profiler.BeginSample("Expand Skeletons");
                foreach (var info in hierInfo)
                {
                    if (info.skelJoints == null || info.skelJoints.Length == 0)
                    {
                        continue;
                    }

                    try {
                        ExpandSkeleton(info, unityRoot, usdRoot, info.prim, map, options);
                    } catch (Exception ex) {
                        Debug.LogException(new Exception("Error expanding skeleton at " + info.prim.GetPath(), ex));
                    }
                }
                Profiler.EndSample();
            }

            return(map);
        }
Exemple #21
0
        BeginReading(Scene scene,
                     SdfPath usdRoot,
                     PrimMap map,
                     SceneImportOptions options)
        {
            FindPathsJob.usdRoot = usdRoot;
            FindPathsJob.scene   = scene;
            FindPathsJob.results = new SdfPath[8][];
            FindPathsJob.queries = new FindPathsJob.IQuery[8];

            if (options.ShouldBindMaterials)
            {
                FindPathsJob.queries[0] = (FindPathsJob.IQuery) new FindPathsJob.Query <MaterialSample>();
            }
            if (options.importCameras)
            {
                FindPathsJob.queries[1] = (FindPathsJob.IQuery) new FindPathsJob.Query <CameraSample>();
            }
            if (options.importMeshes)
            {
                FindPathsJob.queries[2] = (FindPathsJob.IQuery) new FindPathsJob.Query <MeshSample>();
                FindPathsJob.queries[3] = (FindPathsJob.IQuery) new FindPathsJob.Query <CubeSample>();
                FindPathsJob.queries[4] = (FindPathsJob.IQuery) new FindPathsJob.Query <SphereSample>();
            }

            FindPathsJob.queries[5] = (FindPathsJob.IQuery) new FindPathsJob.Query <SkelRootSample>();

            if (options.importSkinning)
            {
                FindPathsJob.queries[6] = (FindPathsJob.IQuery) new FindPathsJob.Query <SkeletonSample>();
            }
            if (options.importTransforms)
            {
                FindPathsJob.queries[7] = (FindPathsJob.IQuery) new FindPathsJob.Query <XformSample>();
            }

            var findPathsJob = new FindPathsJob();

#if !UNITY_2017
            var findHandle = findPathsJob.Schedule(FindPathsJob.queries.Length, 1);
            findHandle.Complete();
#else
            findPathsJob.Run();
#endif

            map.Materials = FindPathsJob.results[0];
            map.Cameras   = FindPathsJob.results[1];
            map.Meshes    = FindPathsJob.results[2];
            map.Cubes     = FindPathsJob.results[3];
            map.Spheres   = FindPathsJob.results[4];
            map.SkelRoots = FindPathsJob.results[5];
            map.Skeletons = FindPathsJob.results[6];
            map.Xforms    = FindPathsJob.results[7];

            ReadHierJob.paths     = FindPathsJob.results.Where(i => i != null).SelectMany(i => i).ToArray();
            ReadHierJob.result    = new HierInfo[ReadHierJob.paths.Length];
            ReadHierJob.scene     = scene;
            ReadHierJob.skelCache = map.SkelCache;
            var readHierInfo = new ReadHierJob();
#if !UNITY_2017
            return(readHierInfo.Schedule(ReadHierJob.paths.Length, 8, dependsOn: findHandle));
#else
            readHierInfo.Run();
            return;
#endif
        }
Exemple #22
0
        void OnEnable()
        {
            InitUsd.Initialize();

            if (string.IsNullOrEmpty(m_usdMeshPath))
            {
                m_usdMeshPath = UnityTypeConverter.GetPath(transform);
            }

            var    scene   = GetScene();
            var    binding = ReadUsdWeights(scene);
            string skelRootPath;
            var    skeleton = ReadUsdSkeleton(scene, out skelRootPath);

            if (binding == null)
            {
                binding = new SkelBindingSample();
            }

            var mesh = GetComponent <SkinnedMeshRenderer>().sharedMesh;

            // Process classic four-bone weights first.
            var sb = new System.Text.StringBuilder();

#if UNITY_2019_1_OR_NEWER
            var bonesPerVert   = mesh.GetBonesPerVertex();
            int weightsPerBone = 0;
            foreach (int count in bonesPerVert)
            {
                weightsPerBone = weightsPerBone > count ? weightsPerBone : count;
            }
            var boneWeights = mesh.GetAllBoneWeights();
            sb.AppendLine("Many-bone indices: (" + boneWeights.Length + " * 4)");
            int bone = 0;
            int bi   = 0;
            int wi   = 0;
            foreach (var weight in boneWeights)
            {
                if (wi == 0)
                {
                    sb.Append("i: " + bone + " [");
                }

                sb.Append(weight.boneIndex + GetUsdBoneData(bi, wi, binding.jointIndices) + ",");

                wi++;
                if (wi == weightsPerBone)
                {
                    sb.Append("]\n");
                    bi++;
                    wi = 0;
                }

                if (bonesPerVert[bi] != weightsPerBone)
                {
                    // TODO: Unity supports a variable number of weights per bone, but USD does not.
                    // Therefore, the number of weights may be greater in USD than in Unity. Currently
                    // the way this works does not correctly handle that case.
                    Debug.LogWarning("Unity bone count issue, see code comment for details.");
                }

                bone++;
            }
            Debug.Log(sb.ToString());

            bone = 0;
            bi   = 0;
            wi   = 0;
            sb   = new System.Text.StringBuilder();
            sb.AppendLine("Many-bone weights: (" + boneWeights.Length + " * 4)");
            foreach (var weight in boneWeights)
            {
                if (wi == 0)
                {
                    sb.Append("i: " + bone + " [");
                }
                sb.Append(weight.weight + GetUsdBoneData(bi, wi, binding.jointWeights) + ",");

                wi++;
                if (wi == weightsPerBone)
                {
                    sb.Append("]\n");
                    bi++;
                    wi = 0;
                }
                bone++;
            }
            Debug.Log(sb.ToString());
#else
            sb.AppendLine("Legacy 4-bone indices: (" + mesh.boneWeights.Length + " * 4)");
            int bone = 0;
            foreach (var weight in mesh.boneWeights)
            {
                sb.Append("[");
                sb.Append(weight.boneIndex0 + GetUsdBoneData(bone, 0, binding.jointIndices) + ",");
                sb.Append(weight.boneIndex1 + GetUsdBoneData(bone, 1, binding.jointIndices) + ",");
                sb.Append(weight.boneIndex2 + GetUsdBoneData(bone, 2, binding.jointIndices) + ",");
                sb.Append(weight.boneIndex3 + GetUsdBoneData(bone, 3, binding.jointIndices) + "]\n");
                bone++;
            }
            Debug.Log(sb.ToString());

            bone = 0;
            sb   = new System.Text.StringBuilder();
            sb.AppendLine("Legacy 4-bone weights: (" + mesh.boneWeights.Length + " * 4)");
            foreach (var weight in mesh.boneWeights)
            {
                sb.Append("[");
                sb.Append(weight.weight0 + GetUsdBoneData(bone, 0, binding.jointWeights) + ",");
                sb.Append(weight.weight1 + GetUsdBoneData(bone, 1, binding.jointWeights) + ",");
                sb.Append(weight.weight2 + GetUsdBoneData(bone, 2, binding.jointWeights) + ",");
                sb.Append(weight.weight3 + GetUsdBoneData(bone, 3, binding.jointWeights) + "]\n");
                bone++;
            }
            Debug.Log(sb.ToString());
#endif


            sb = new System.Text.StringBuilder();
            var bones    = GetComponent <SkinnedMeshRenderer>().bones;
            var rootBone = GetComponent <SkinnedMeshRenderer>().rootBone;
            var root     = UnityTypeConverter.GetPath(rootBone);
            sb.AppendLine("Bones: (" + bones.Length + ")");
            sb.AppendLine("Root Bone: " + root);
            int i = 0;
            foreach (var boneXf in bones)
            {
                sb.AppendLine(UnityTypeConverter.GetPath(boneXf));
                if (binding.joints != null)
                {
                    sb.AppendLine(root + "\\" + binding.joints[i++] + "\n");
                }
            }
            Debug.Log(sb.ToString());

            sb = new System.Text.StringBuilder();
            sb.AppendLine("Bind Transforms: (" + mesh.bindposes.Length + ")");
            i = -1;
            var options = new SceneImportOptions();
            options.changeHandedness = m_basisTransform;
            foreach (var boneXf in bones)
            {
                i++;
                var bindPose = mesh.bindposes[i];
                var bonePath = UnityTypeConverter.GetPath(boneXf);
                sb.AppendLine("Pose[" + i + "] " + bonePath);
                sb.AppendLine(bindPose.ToString());

                if (skeleton.bindTransforms != null)
                {
                    if (string.IsNullOrEmpty(skelRootPath))
                    {
                        continue;
                    }

                    bonePath = bonePath.Substring(skelRootPath.Length);
                    bonePath = bonePath.TrimStart('/');
                    foreach (var joint in skeleton.joints)
                    {
                        if (joint == bonePath)
                        {
                            var usdMat = skeleton.bindTransforms[i];
                            XformImporter.ImportXform(ref usdMat, options);
                            sb.AppendLine(usdMat.ToString() + "\n");
                            bonePath = null;
                            break;
                        }
                    }

                    if (string.IsNullOrEmpty(bonePath))
                    {
                        continue;
                    }
                    sb.Append("Bone not found in USD: " + bonePath + "\n\n");
                }
            }
            Debug.Log(sb.ToString());
        }
Exemple #23
0
        /// <summary>
        /// Custom importer. This works almost exactly as the ScriptedImporter, but does not require
        /// the new API.
        /// </summary>
        public static void SavePrefab(GameObject rootObject,
                                      string prefabPath,
                                      string playableClipName,
                                      SceneImportOptions importOptions)
        {
            Directory.CreateDirectory(Path.GetDirectoryName(prefabPath));

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

            if (oldPrefab == null)
            {
                // Create the prefab. At this point, the meshes do not yet exist and will be
                // dangling references
#if UNITY_2018_3_OR_NEWER
                prefab = PrefabUtility.SaveAsPrefabAsset(rootObject, prefabPath);
#else
                prefab = PrefabUtility.CreatePrefab(prefabPath, rootObject);
#endif
                HashSet <Mesh>     meshes;
                HashSet <Material> materials;
                AddObjectsToAsset(rootObject, prefab, importOptions, out meshes, out materials);

                foreach (var mesh in meshes)
                {
                    AssetDatabase.AddObjectToAsset(mesh, prefab);
                }

                foreach (var mat in materials)
                {
                    AssetDatabase.AddObjectToAsset(mat, prefab);
                }

                // Fix the dangling references.
#if UNITY_2018_3_OR_NEWER
                prefab = PrefabUtility.SaveAsPrefabAsset(rootObject, prefabPath);
#else
                prefab = PrefabUtility.ReplacePrefab(rootObject, prefab);
#endif
                var playable = ScriptableObject.CreateInstance <UsdPlayableAsset>();

                playable.SourceUsdAsset.defaultValue = prefab.GetComponent <UsdAsset>();
                playable.name = playableClipName;
                AssetDatabase.AddObjectToAsset(playable, prefab);
#if UNITY_2018_3_OR_NEWER
                prefab = PrefabUtility.SavePrefabAsset(prefab);
#endif
            }
            else
            {
                HashSet <Mesh>     meshes;
                HashSet <Material> materials;
#if UNITY_2018_3_OR_NEWER
                oldPrefab = PrefabUtility.SaveAsPrefabAsset(rootObject, prefabPath);
#endif
                AddObjectsToAsset(rootObject, oldPrefab, importOptions, out meshes, out materials);

                // 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)
                    {
                        continue;
                    }
                    if (obj is Mesh && meshes.Contains((Mesh)obj))
                    {
                        meshes.Remove((Mesh)obj);
                        continue;
                    }
                    if (obj is Material && materials.Contains((Material)obj))
                    {
                        materials.Remove((Material)obj);
                        continue;
                    }
                    Object.DestroyImmediate(obj, allowDestroyingAssets: true);
                }

                foreach (var mesh in meshes)
                {
                    AssetDatabase.AddObjectToAsset(mesh, oldPrefab);
                }

                foreach (var mat in materials)
                {
                    AssetDatabase.AddObjectToAsset(mat, oldPrefab);
                }

#if UNITY_2018_3_OR_NEWER
                prefab = PrefabUtility.SaveAsPrefabAsset(rootObject, prefabPath);
#else
                if (oldPrefab != rootObject)
                {
                    prefab = PrefabUtility.ReplacePrefab(
                        rootObject, oldPrefab, ReplacePrefabOptions.ReplaceNameBased);
                }
                else
                {
                    prefab = oldPrefab;
                }
#endif

                var playable = ScriptableObject.CreateInstance <UsdPlayableAsset>();
                playable.SourceUsdAsset.defaultValue = prefab.GetComponent <UsdAsset>();
                playable.name = playableClipName;
                AssetDatabase.AddObjectToAsset(playable, prefab);
#if UNITY_2018_3_OR_NEWER
                PrefabUtility.SavePrefabAsset(prefab);
#endif
            }

            AssetDatabase.ImportAsset(prefabPath, ImportAssetOptions.ForceUpdate);
            AssetDatabase.SaveAssets();
        }
Exemple #24
0
        public static void BuildPointInstances(Scene scene,
                                               PrimMap primMap,
                                               string pointInstancerPath,
                                               PointInstancerSample sample,
                                               GameObject root,
                                               SceneImportOptions options)
        {
            Matrix4x4[] transforms = sample.ComputeInstanceMatrices(scene, pointInstancerPath);
            int         i          = 0;

            foreach (var protoRoot in sample.prototypes.targetPaths)
            {
                GameObject go;
                if (!primMap.TryGetValue(new pxr.SdfPath(protoRoot), out go))
                {
                    Debug.LogWarning("Proto not found in PrimMap: " + protoRoot);
                    continue;
                }

                go.SetActive(false);
                if (options.enableGpuInstancing)
                {
                    EnableGpuInstancing(go);
                }
            }

            var inactiveIds = new System.Collections.Generic.HashSet <long>();

            /*
             * Disabled until this bug is resolved:
             * https://github.com/PixarAnimationStudios/USD/issues/639
             *
             * if (sample.inactiveIds != null) {
             * foreach (long id in sample.inactiveIds.GetExplicitItems()) {
             *  inactiveIds.Add(id);
             * }
             * }
             */

            foreach (var index in sample.protoIndices)
            {
                if (inactiveIds.Contains(index))
                {
                    continue;
                }

                if (index >= sample.prototypes.targetPaths.Length)
                {
                    Debug.LogWarning("ProtoIndex out of bounds: [" + index + "] " +
                                     "for instancer: " + pointInstancerPath);
                    continue;
                }

                var targetPath = sample.prototypes.targetPaths[index];

                GameObject goMaster;
                if (!primMap.TryGetValue(new pxr.SdfPath(targetPath), out goMaster))
                {
                    Debug.LogWarning("Proto not found in PrimMap: " + targetPath);
                    continue;
                }

                if (i >= transforms.Length)
                {
                    Debug.LogWarning("No transform for instance index [" + i + "] " +
                                     "for instancer: " + pointInstancerPath);
                    break;
                }

                var xf         = transforms[i];
                var goInstance = GameObject.Instantiate(goMaster, root.transform);
                goInstance.SetActive(true);
                goInstance.name = goMaster.name + "_" + i;
                XformImporter.BuildXform(xf, goInstance, options);

                i++;
            }
        }
Exemple #25
0
        /// <summary>
        /// Applies the contents of this USD file to a foreign root object.
        /// </summary>
        /// <remarks>
        /// The idea here is that one may have many animation clips, but only a single GameObject in
        /// the Unity scenegraph.
        /// </remarks>
        public void SetTime(double time, UsdAsset foreignRoot, bool saveMeshUpdates)
        {
            var scene = GetScene();

            if (scene == null)
            {
                Debug.LogWarning("Null scene from GetScene() at " + UnityTypeConverter.GetPath(transform));
                return;
            }

            // Careful not to update any local members here, if this data is driven from a prefab, we
            // dont want those changes to be baked back into the asset.
            time += foreignRoot.m_usdTimeOffset;
            float usdTime = (float)(scene.StartTime + time * scene.Stage.GetTimeCodesPerSecond());

            if (usdTime > scene.EndTime)
            {
                return;
            }
            if (usdTime < scene.StartTime)
            {
                return;
            }

            scene.Time = usdTime;

            var options = new SceneImportOptions();

            foreignRoot.StateToOptions(ref options);

            PrepOptionsForTimeChange(ref options);

            if (foreignRoot.m_lastPrimMap == null)
            {
                foreignRoot.m_lastPrimMap = new PrimMap();
                options.importHierarchy   = true;
            }

            if (m_usdVariabilityCache)
            {
                if (m_lastAccessMask == null)
                {
                    m_lastAccessMask             = new AccessMask();
                    scene.IsPopulatingAccessMask = true;
                }
            }
            else
            {
                m_lastAccessMask = null;
            }

            if (m_debugPrintVariabilityCache && m_lastAccessMask != null &&
                !scene.IsPopulatingAccessMask)
            {
                var sb = new System.Text.StringBuilder();
                foreach (var kvp in m_lastAccessMask.Included)
                {
                    sb.AppendLine(kvp.Key);
                    foreach (var member in kvp.Value)
                    {
                        sb.AppendLine("  ." + member.Name);
                    }
                    sb.AppendLine();
                }
                Debug.Log(sb.ToString());
            }

            scene.AccessMask = m_lastAccessMask;
            SceneImporter.ImportUsd(foreignRoot.gameObject,
                                    scene,
                                    foreignRoot.m_lastPrimMap,
                                    options);
            scene.AccessMask = null;

            if (m_lastAccessMask != null)
            {
                scene.IsPopulatingAccessMask = false;
            }
        }
Exemple #26
0
        /// <summary>
        /// Rebuilds the USD scene as Unity GameObjects, with a limited budget per update.
        /// </summary>
        public static IEnumerator BuildScene(Scene scene,
                                             GameObject root,
                                             SceneImportOptions importOptions,
                                             PrimMap primMap,
                                             float targetFrameMilliseconds,
                                             bool composingSubtree)
        {
            var timer       = new System.Diagnostics.Stopwatch();
            var usdPrimRoot = new pxr.SdfPath(importOptions.usdRootPath);

            // Setting an arbitrary fudge factor of 20% is very non-scientific, however it's better than
            // nothing. The correct way to hit a deadline is to predict how long each iteration actually
            // takes and then return early if the estimated time is over budget.
            float targetTime = targetFrameMilliseconds * .8f;

            timer.Start();

            // Reconstruct the USD hierarchy as Unity GameObjects.
            // A PrimMap is returned for tracking the USD <-> Unity mapping.
            Profiler.BeginSample("USD: Build Hierarchy");
            if (importOptions.importHierarchy || importOptions.forceRebuild)
            {
                // When a USD file is fully RE-imported, all exsiting USD data must be removed. The old
                // assumption was that the root would never have much more than the UsdAsset component
                // itself, however it's now clear that the root may also have meaningful USD data added
                // too.
                //
                // TODO(jcowles): This feels like a workaround. What we really want here is an "undo"
                // process for changes made to the root GameObject. For example, to clean up non-USD
                // components which may have been added (e.g. what if a mesh is imported to the root?
                // currently the MeshRenderer etc will remain after re-import).
                RemoveComponent <UsdAssemblyRoot>(root);
                RemoveComponent <UsdVariantSet>(root);
                RemoveComponent <UsdModelRoot>(root);
                RemoveComponent <UsdLayerStack>(root);
                RemoveComponent <UsdPayload>(root);
                RemoveComponent <UsdPrimSource>(root);

                primMap.Clear();
                HierarchyBuilder.BuildGameObjects(scene,
                                                  root,
                                                  usdPrimRoot,
                                                  scene.Find(usdPrimRoot.ToString(), "UsdSchemaBase"),
                                                  primMap,
                                                  importOptions);
            }
            Profiler.EndSample();

            if (ShouldYield(targetTime, timer))
            {
                yield return(null); ResetTimer(timer);
            }

            Profiler.BeginSample("USD: Post Process Hierarchy");
            foreach (var processor in root.GetComponents <IImportPostProcessHierarchy>())
            {
                try {
                    processor.PostProcessHierarchy(primMap, importOptions);
                } catch (System.Exception ex) {
                    Debug.LogException(ex);
                }
            }
            Profiler.EndSample();

            if (ShouldYield(targetTime, timer))
            {
                yield return(null); ResetTimer(timer);
            }

            //
            // Pre-process UsdSkelRoots.
            //

            var skelRoots = new List <pxr.UsdSkelRoot>();

            if (importOptions.importSkinning)
            {
                Profiler.BeginSample("USD: Process UsdSkelRoots");
                foreach (var path in primMap.SkelRoots)
                {
                    try {
                        var skelRootPrim = scene.GetPrimAtPath(path);
                        if (!skelRootPrim)
                        {
                            Debug.LogWarning("SkelRoot prim not found: " + path);
                            continue;
                        }
                        var skelRoot = new pxr.UsdSkelRoot(skelRootPrim);
                        if (!skelRoot)
                        {
                            Debug.LogWarning("SkelRoot prim not SkelRoot type: " + path);
                            continue;
                        }

                        skelRoots.Add(skelRoot);
                        GameObject go = primMap[path];
                        ImporterBase.GetOrAddComponent <Animator>(go, true);
                    } catch (System.Exception ex) {
                        Debug.LogException(
                            new ImportException("Error pre-processing SkelRoot <" + path + ">", ex));
                    }

                    if (ShouldYield(targetTime, timer))
                    {
                        yield return(null); ResetTimer(timer);
                    }
                }
                Profiler.EndSample();
            }

            //
            // Import known prim types.
            //

            // Materials.
            Profiler.BeginSample("USD: Build Materials");
            if (importOptions.ShouldBindMaterials)
            {
                foreach (var pathAndSample in scene.ReadAll <MaterialSample>(primMap.Materials))
                {
                    try {
                        var mat = MaterialImporter.BuildMaterial(scene,
                                                                 pathAndSample.path,
                                                                 pathAndSample.sample,
                                                                 importOptions);
                        if (mat != null)
                        {
                            importOptions.materialMap[pathAndSample.path] = mat;
                        }
                    } catch (System.Exception ex) {
                        Debug.LogException(
                            new ImportException("Error processing material <" + pathAndSample.path + ">", ex));
                    }

                    if (ShouldYield(targetTime, timer))
                    {
                        yield return(null); ResetTimer(timer);
                    }
                }
            }
            Profiler.EndSample();

            //
            // Start threads.
            //
            ReadAllJob <XformSample> readXforms;

            if (importOptions.importTransforms)
            {
                readXforms = new ReadAllJob <XformSample>(scene, primMap.Xforms);
#if UNITY_2018_1_OR_NEWER
                readXforms.Schedule(primMap.Xforms.Length, 4);
#else
                readXforms.Run();
#endif
            }
            if (importOptions.importMeshes)
            {
                ActiveMeshImporter.BeginReading(scene, primMap);
            }
#if UNITY_2018_1_OR_NEWER
            JobHandle.ScheduleBatchedJobs();
#endif


            // Xforms.
            //
            // Note that we are specifically filtering on XformSample, not Xformable, this way only
            // Xforms are processed to avoid doing that work redundantly.
            if (importOptions.importTransforms)
            {
                Profiler.BeginSample("USD: Build Xforms");
                foreach (var pathAndSample in readXforms)
                {
                    try {
                        if (pathAndSample.path == usdPrimRoot)
                        {
                            // Never read the xform from the USD root, that will be authored in Unity.
                            continue;
                        }
                        GameObject go = primMap[pathAndSample.path];
                        NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                        XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);
                    } catch (System.Exception ex) {
                        Debug.LogException(
                            new ImportException("Error processing xform <" + pathAndSample.path + ">", ex));
                    }

                    if (ShouldYield(targetTime, timer))
                    {
                        yield return(null); ResetTimer(timer);
                    }
                }

                foreach (var pathAndSample in scene.ReadAll <XformSample>(primMap.SkelRoots))
                {
                    try {
                        if (pathAndSample.path == usdPrimRoot)
                        {
                            // Never read the xform from the USD root, that will be authored in Unity.
                            continue;
                        }
                        GameObject go = primMap[pathAndSample.path];
                        NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                        XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);
                    } catch (System.Exception ex) {
                        Debug.LogException(
                            new ImportException("Error processing xform <" + pathAndSample.path + ">", ex));
                    }

                    if (ShouldYield(targetTime, timer))
                    {
                        yield return(null); ResetTimer(timer);
                    }
                }

                if (importOptions.importSkinning)
                {
                    foreach (var pathAndSample in scene.ReadAll <XformSample>(primMap.Skeletons))
                    {
                        try {
                            if (pathAndSample.path == usdPrimRoot)
                            {
                                // Never read the xform from the USD root, that will be authored in Unity.
                                continue;
                            }
                            GameObject go = primMap[pathAndSample.path];
                            NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                            XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);
                        } catch (System.Exception ex) {
                            Debug.LogException(
                                new ImportException("Error processing xform <" + pathAndSample.path + ">", ex));
                        }

                        if (ShouldYield(targetTime, timer))
                        {
                            yield return(null); ResetTimer(timer);
                        }
                    }
                }

                Profiler.EndSample();
            }

            // Meshes.
            if (importOptions.importMeshes)
            {
                Profiler.BeginSample("USD: Build Meshes");
                IEnumerator it = ActiveMeshImporter.Import(scene, primMap, importOptions);

                while (it.MoveNext())
                {
                    if (ShouldYield(targetTime, timer))
                    {
                        yield return(null); ResetTimer(timer);
                    }
                }
                Profiler.EndSample();

                // Cubes.
                Profiler.BeginSample("USD: Build Cubes");
                foreach (var pathAndSample in scene.ReadAll <CubeSample>(primMap.Cubes))
                {
                    try {
                        GameObject go = primMap[pathAndSample.path];
                        NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                        XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);
                        CubeImporter.BuildCube(pathAndSample.sample, go, importOptions);
                    } catch (System.Exception ex) {
                        Debug.LogException(
                            new ImportException("Error processing cube <" + pathAndSample.path + ">", ex));
                    }

                    if (ShouldYield(targetTime, timer))
                    {
                        yield return(null); ResetTimer(timer);
                    }
                }
                Profiler.EndSample();
            }

            // Cameras.
            if (importOptions.importCameras)
            {
                Profiler.BeginSample("USD: Cameras");
                foreach (var pathAndSample in scene.ReadAll <CameraSample>(primMap.Cameras))
                {
                    try {
                        GameObject go = primMap[pathAndSample.path];
                        NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                        XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);

                        // The camera has many value-type parameters that need to be handled correctly when not
                        // not animated. For now, only the camera transform will animate, until this is fixed.
                        if (scene.AccessMask == null || scene.IsPopulatingAccessMask)
                        {
                            CameraImporter.BuildCamera(pathAndSample.sample, go, importOptions);
                        }
                    } catch (System.Exception ex) {
                        Debug.LogException(
                            new ImportException("Error processing camera <" + pathAndSample.path + ">", ex));
                    }

                    if (ShouldYield(targetTime, timer))
                    {
                        yield return(null); ResetTimer(timer);
                    }
                }
                Profiler.EndSample();
            }

            // Build out masters for instancing.
            Profiler.BeginSample("USD: Build Instances");
            foreach (var masterRootPath in primMap.GetMasterRootPaths())
            {
                try {
                    Transform masterRootXf = primMap[masterRootPath].transform;

                    // Transforms
                    if (importOptions.importTransforms)
                    {
                        Profiler.BeginSample("USD: Build Xforms");
                        foreach (var pathAndSample in scene.ReadAll <XformSample>(masterRootPath))
                        {
                            try {
                                GameObject go = primMap[pathAndSample.path];
                                NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                                XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);
                            } catch (System.Exception ex) {
                                Debug.LogException(
                                    new ImportException("Error processing xform <" + pathAndSample.path + ">", ex));
                            }
                        }

                        foreach (var pathAndSample in scene.ReadAll <XformSample>(masterRootPath))
                        {
                            try {
                                GameObject go = primMap[pathAndSample.path];
                                NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                                XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);
                            } catch (System.Exception ex) {
                                Debug.LogException(
                                    new ImportException("Error processing xform <" + pathAndSample.path + ">", ex));
                            }
                        }

                        foreach (var pathAndSample in scene.ReadAll <XformSample>(primMap.Skeletons))
                        {
                            try {
                                GameObject go = primMap[pathAndSample.path];
                                NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                                XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);
                            } catch (System.Exception ex) {
                                Debug.LogException(
                                    new ImportException("Error processing xform <" + pathAndSample.path + ">", ex));
                            }
                        }
                        Profiler.EndSample();
                    }

                    // Meshes.
                    if (importOptions.importMeshes)
                    {
                        Profiler.BeginSample("USD: Build Meshes");
                        foreach (var pathAndSample in scene.ReadAll <MeshSample>(masterRootPath))
                        {
                            try {
                                GameObject go = primMap[pathAndSample.path];
                                NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                                XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);
                                var subsets = MeshImporter.ReadGeomSubsets(scene, pathAndSample.path);
                                MeshImporter.BuildMesh(pathAndSample.path, pathAndSample.sample, subsets, go, importOptions);
                            } catch (System.Exception ex) {
                                Debug.LogException(
                                    new ImportException("Error processing mesh <" + pathAndSample.path + ">", ex));
                            }
                        }
                        Profiler.EndSample();

                        // Cubes.
                        Profiler.BeginSample("USD: Build Cubes");
                        foreach (var pathAndSample in scene.ReadAll <CubeSample>(masterRootPath))
                        {
                            try {
                                GameObject go = primMap[pathAndSample.path];
                                NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                                XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);
                                CubeImporter.BuildCube(pathAndSample.sample, go, importOptions);
                            } catch (System.Exception ex) {
                                Debug.LogException(
                                    new ImportException("Error processing cube <" + pathAndSample.path + ">", ex));
                            }
                        }
                        Profiler.EndSample();
                    }

                    // Cameras.
                    if (importOptions.importCameras)
                    {
                        Profiler.BeginSample("USD: Build Cameras");
                        foreach (var pathAndSample in scene.ReadAll <CameraSample>(masterRootPath))
                        {
                            try {
                                GameObject go = primMap[pathAndSample.path];
                                NativeImporter.ImportObject(scene, go, scene.GetPrimAtPath(pathAndSample.path), importOptions);
                                XformImporter.BuildXform(pathAndSample.path, pathAndSample.sample, go, importOptions, scene);
                                CameraImporter.BuildCamera(pathAndSample.sample, go, importOptions);
                            } catch (System.Exception ex) {
                                Debug.LogException(
                                    new ImportException("Error processing camera <" + pathAndSample.path + ">", ex));
                            }
                        }
                        Profiler.EndSample();
                    }
                } catch (System.Exception ex) {
                    Debug.LogException(
                        new ImportException("Error processing master <" + masterRootPath + ">", ex));
                }

                if (ShouldYield(targetTime, timer))
                {
                    yield return(null); ResetTimer(timer);
                }
            } // Instances.
            Profiler.EndSample();

            //
            // Post-process dependencies: materials and bones.
            //

            Profiler.BeginSample("USD: Process Material Bindings");
            try {
                // TODO: Currently ProcessMaterialBindings runs too long and will go over budget for any
                // large scene. However, pulling the loop into this code feels wrong in terms of
                // responsibilities.

                // Process all material bindings in a single vectorized request.
                MaterialImporter.ProcessMaterialBindings(scene, importOptions);
            } catch (System.Exception ex) {
                Debug.LogException(new ImportException("Failed in ProcessMaterialBindings", ex));
            }
            Profiler.EndSample();

            if (ShouldYield(targetTime, timer))
            {
                yield return(null); ResetTimer(timer);
            }

            //
            // SkinnedMesh bone bindings.
            //
            if (importOptions.importSkinning)
            {
                Profiler.BeginSample("USD: Build Skeletons");
                var skeletonSamples = new Dictionary <pxr.SdfPath, SkeletonSample>();
                foreach (var skelRoot in skelRoots)
                {
                    try {
                        var bindings = new pxr.UsdSkelBindingVector();
                        if (!primMap.SkelBindings.TryGetValue(skelRoot.GetPath(), out bindings))
                        {
                            Debug.LogWarning("No bindings found skelRoot: " + skelRoot.GetPath());
                        }

                        if (bindings.Count == 0)
                        {
                            Debug.LogWarning("No bindings found skelRoot: " + skelRoot.GetPath());
                        }

                        foreach (var skelBinding in bindings)
                        {
                            // The SkelRoot will likely have a skeleton binding, but it's inherited, so the bound
                            // skeleton isn't actually known until it's queried from the binding. Still, we would
                            // like not to reprocess skeletons redundantly, so skeletons are cached into a
                            // dictionary.

                            Profiler.BeginSample("Build Bind Transforms");
                            var            skelPath   = skelBinding.GetSkeleton().GetPath();
                            SkeletonSample skelSample = null;
                            if (!skeletonSamples.TryGetValue(skelPath, out skelSample))
                            {
                                skelSample = new SkeletonSample();

                                Profiler.BeginSample("Read Skeleton");
                                scene.Read(skelPath, skelSample);
                                Profiler.EndSample();

                                skeletonSamples.Add(skelPath, skelSample);

                                // Unity uses the inverse bindTransform, since that's actually what's needed for
                                // skinning. Do that once here, so each skinned mesh doesn't need to do it
                                // redundantly.
                                SkeletonImporter.BuildBindTransforms(skelPath, skelSample, importOptions);

                                var bindXforms = new pxr.VtMatrix4dArray();

                                var prim = scene.GetPrimAtPath(skelPath);
                                var skel = new pxr.UsdSkelSkeleton(prim);

                                Profiler.BeginSample("Get SkelQuery");
                                pxr.UsdSkelSkeletonQuery skelQuery = primMap.SkelCache.GetSkelQuery(skel);
                                Profiler.EndSample();

                                Profiler.BeginSample("Get JointWorldBind Transforms");
                                if (!skelQuery.GetJointWorldBindTransforms(bindXforms))
                                {
                                    throw new ImportException("Failed to compute binding trnsforms for <" + skelPath + ">");
                                }
                                Profiler.EndSample();

                                SkeletonImporter.BuildDebugBindTransforms(skelSample, primMap[skelPath], importOptions);
                            }
                            Profiler.EndSample();

                            if (importOptions.importSkinWeights)
                            {
                                //
                                // Apply skinning weights to each skinned mesh.
                                //
                                Profiler.BeginSample("Apply Skin Weights");
                                foreach (var skinningQuery in skelBinding.GetSkinningTargetsAsVector())
                                {
                                    var meshPath = skinningQuery.GetPrim().GetPath();
                                    try {
                                        var skelBindingSample = new SkelBindingSample();
                                        var goMesh            = primMap[meshPath];

                                        scene.Read(meshPath, skelBindingSample);

                                        Profiler.BeginSample("Build Skinned Mesh");
                                        SkeletonImporter.BuildSkinnedMesh(
                                            meshPath,
                                            skelPath,
                                            skelSample,
                                            skelBindingSample,
                                            goMesh,
                                            primMap,
                                            importOptions);
                                        Profiler.EndSample();

                                        // In terms of performance, this is almost free.
                                        goMesh.GetComponent <SkinnedMeshRenderer>().rootBone = primMap[skelPath].transform.GetChild(0);
                                    } catch (System.Exception ex) {
                                        Debug.LogException(new ImportException("Error skinning mesh: " + meshPath, ex));
                                    }
                                }
                                Profiler.EndSample();
                            }
                        }
                    } catch (System.Exception ex) {
                        Debug.LogException(
                            new ImportException("Error processing SkelRoot <" + skelRoot.GetPath() + ">", ex));
                    }
                } // foreach SkelRoot
                Profiler.EndSample();

                if (ShouldYield(targetTime, timer))
                {
                    yield return(null); ResetTimer(timer);
                }

                //
                // Bone transforms.
                //
                Profiler.BeginSample("USD: Pose Bones");
                foreach (var pathAndSample in skeletonSamples)
                {
                    var skelPath = pathAndSample.Key;

                    try {
                        var prim = scene.GetPrimAtPath(skelPath);
                        var skel = new pxr.UsdSkelSkeleton(prim);

                        pxr.UsdSkelSkeletonQuery skelQuery = primMap.SkelCache.GetSkelQuery(skel);
                        var joints     = skelQuery.GetJointOrder();
                        var restXforms = new pxr.VtMatrix4dArray();
                        var time       = scene.Time.HasValue ? scene.Time.Value : pxr.UsdTimeCode.Default();

                        Profiler.BeginSample("Compute Joint Local Transforms");
                        if (!skelQuery.ComputeJointLocalTransforms(restXforms, time, atRest: false))
                        {
                            throw new ImportException("Failed to compute bind trnsforms for <" + skelPath + ">");
                        }
                        Profiler.EndSample();

                        Profiler.BeginSample("Build Bones");
                        for (int i = 0; i < joints.size(); i++)
                        {
                            var jointPath = scene.GetSdfPath(joints[i]);
                            if (joints[i] == "/")
                            {
                                jointPath = skelPath;
                            }
                            else if (jointPath.IsAbsolutePath())
                            {
                                Debug.LogException(new System.Exception("Unexpected absolute joint path: " + jointPath));
                                jointPath = new pxr.SdfPath(joints[i].ToString().TrimStart('/'));
                                jointPath = skelPath.AppendPath(jointPath);
                            }
                            else
                            {
                                jointPath = skelPath.AppendPath(jointPath);
                            }
                            var goBone = primMap[jointPath];

                            Profiler.BeginSample("Convert Matrix");
                            var restXform = UnityTypeConverter.FromMatrix(restXforms[i]);
                            Profiler.EndSample();

                            Profiler.BeginSample("Build Bone");
                            SkeletonImporter.BuildSkeletonBone(skelPath, goBone, restXform, joints, importOptions);
                            Profiler.EndSample();
                        }
                        Profiler.EndSample();
                    } catch (System.Exception ex) {
                        Debug.LogException(
                            new ImportException("Error processing SkelRoot <" + skelPath + ">", ex));
                    }

                    if (ShouldYield(targetTime, timer))
                    {
                        yield return(null); ResetTimer(timer);
                    }
                }
                Profiler.EndSample();
            }

            //
            // Apply instancing.
            //
            if (importOptions.importSceneInstances)
            {
                Profiler.BeginSample("USD: Build Scene-Instances");
                try {
                    // Build scene instances.
                    InstanceImporter.BuildSceneInstances(primMap, importOptions);
                } catch (System.Exception ex) {
                    Debug.LogException(new ImportException("Failed in BuildSceneInstances", ex));
                }
                Profiler.EndSample();
            }

            if (ShouldYield(targetTime, timer))
            {
                yield return(null); ResetTimer(timer);
            }

            // Build point instances.
            if (importOptions.importPointInstances)
            {
                Profiler.BeginSample("USD: Build Point-Instances");
                // TODO: right now all point instancer data is read, but we only need prototypes and indices.
                foreach (var pathAndSample in scene.ReadAll <PointInstancerSample>())
                {
                    try {
                        GameObject instancerGo = primMap[pathAndSample.path];

                        // Now build the point instances.
                        InstanceImporter.BuildPointInstances(scene,
                                                             primMap,
                                                             pathAndSample.path,
                                                             pathAndSample.sample,
                                                             instancerGo,
                                                             importOptions);
                    } catch (System.Exception ex) {
                        Debug.LogError("Error processing point instancer <" + pathAndSample.path + ">: " + ex.Message);
                    }

                    if (ShouldYield(targetTime, timer))
                    {
                        yield return(null); ResetTimer(timer);
                    }
                }
                Profiler.EndSample();
            }

            //
            // Apply root transform corrections.
            //
            Profiler.BeginSample("USD: Build Root Transforms");
            if (!composingSubtree)
            {
                if (!root)
                {
                    // There is no single root,
                    // Apply root transform corrections to all imported root prims.
                    foreach (KeyValuePair <pxr.SdfPath, GameObject> kvp in primMap)
                    {
                        if (kvp.Key.IsRootPrimPath() && kvp.Value != null)
                        {
                            // The root object at which the USD scene will be reconstructed.
                            // It may need a Z-up to Y-up conversion and a right- to left-handed change of basis.
                            XformImporter.BuildSceneRoot(scene, kvp.Value.transform, importOptions);
                        }
                    }
                }
                else
                {
                    // There is only one root, apply a single transform correction.
                    XformImporter.BuildSceneRoot(scene, root.transform, importOptions);
                }
            }
            Profiler.EndSample();

            Profiler.BeginSample("USD: Post Process Components");
            foreach (var processor in root.GetComponents <IImportPostProcessComponents>())
            {
                try {
                    processor.PostProcessComponents(primMap, importOptions);
                } catch (System.Exception ex) {
                    Debug.LogException(ex);
                }
            }
            Profiler.EndSample();
        }
        /// <summary>
        /// Build the root of a scene under which more USD data will be imported. If the handedness
        /// is changed here, no subsequent changes are required below, however the root will contain
        /// a negative scale.
        /// </summary>
        public static void BuildSceneRoot(Scene scene, Transform root, SceneImportOptions options)
        {
            var  stageRoot    = root.GetComponent <UsdAsset>();
            bool newStageRoot = false;

            if (stageRoot == null)
            {
                stageRoot             = root.gameObject.AddComponent <UsdAsset>();
                stageRoot.usdFullPath = scene.FilePath;
                newStageRoot          = true;
                ImporterBase.MoveComponentFirst(stageRoot);
                stageRoot.OptionsToState(options);
            }

            if (newStageRoot ||
                options.changeHandedness != stageRoot.LastHandedness ||
                options.scale != stageRoot.LastScale ||
                options.forceRebuild)
            {
                var localScale    = root.transform.localScale;
                var localRotation = root.transform.localRotation;

                if (options.forceRebuild)
                {
                    localScale    = Vector3.one;
                    localRotation = Quaternion.identity;
                }
                else if (!newStageRoot)
                {
                    // Undo the previous transforms.
                    UndoRootTransform(scene, stageRoot, ref localScale, ref localRotation);
                }

                stageRoot.LastScale      = options.scale;
                stageRoot.LastHandedness = options.changeHandedness;

                // Handle configurable up-axis (Y or Z).
                float invert = options.changeHandedness == BasisTransformation.FastWithNegativeScale ? -1 : 1;
                if (scene.UpAxis == Scene.UpAxes.Z)
                {
                    localRotation *= Quaternion.AngleAxis(invert * 90, Vector3.right);
                }

                if (options.changeHandedness == BasisTransformation.FastWithNegativeScale)
                {
                    // Convert from right-handed (USD) to left-handed (Unity).
                    if (scene.UpAxis == Scene.UpAxes.Z)
                    {
                        localScale.y *= -1;
                    }
                    else
                    {
                        localScale.z *= -1;
                    }
                }

                if (Mathf.Abs(options.scale - 1.0f) > 0.0001)
                {
                    // Unilaterally setting the scale here is a little wrong, since it will stomp the root
                    // object scale if set in Unity.
                    localScale *= options.scale;
                }

                root.transform.localScale    = localScale;
                root.transform.localRotation = localRotation;
            }
        }
Exemple #28
0
        static void AddObjectsToAsset(GameObject rootObject,
                                      Object asset,
                                      SceneImportOptions importOptions,
                                      out HashSet <Mesh> usedMeshes,
                                      out HashSet <Material> usedMaterials)
        {
            var meshes    = new HashSet <Mesh>();
            var materials = new HashSet <Material>();

            materials.Add(importOptions.materialMap.DisplayColorMaterial);
            materials.Add(importOptions.materialMap.MetallicWorkflowMaterial);
            materials.Add(importOptions.materialMap.SpecularWorkflowMaterial);

            var tempMat = importOptions.materialMap.DisplayColorMaterial;

            if (tempMat != null && AssetDatabase.GetAssetPath(tempMat) == "")
            {
                materials.Add(tempMat);
            }

            tempMat = importOptions.materialMap.MetallicWorkflowMaterial;
            if (tempMat != null && AssetDatabase.GetAssetPath(tempMat) == "")
            {
                materials.Add(tempMat);
            }

            tempMat = importOptions.materialMap.SpecularWorkflowMaterial;
            if (tempMat != null && AssetDatabase.GetAssetPath(tempMat) == "")
            {
                materials.Add(tempMat);
            }

            foreach (var mf in rootObject.GetComponentsInChildren <MeshFilter>())
            {
                if (!mf)
                {
                    continue;
                }
                if (mf.sharedMesh != null && meshes.Add(mf.sharedMesh))
                {
                    mf.sharedMesh.name = mf.name;
                }
            }

            foreach (var mf in rootObject.GetComponentsInChildren <MeshRenderer>())
            {
                if (!mf)
                {
                    continue;
                }
                foreach (var mat in mf.sharedMaterials)
                {
                    if (mat != null && !materials.Add(mat))
                    {
                        mat.name = mf.name;
                        continue;
                    }
                }
            }

            foreach (var mf in rootObject.GetComponentsInChildren <SkinnedMeshRenderer>())
            {
                if (!mf)
                {
                    continue;
                }
                if (mf.sharedMesh != null && meshes.Add(mf.sharedMesh))
                {
                    mf.sharedMesh.name = mf.name;
                }
                foreach (var mat in mf.sharedMaterials)
                {
                    if (mat != null && !materials.Add(mat))
                    {
                        mat.name = mf.name;
                        continue;
                    }
                }
            }

            usedMeshes    = meshes;
            usedMaterials = materials;
        }
        /// <summary>
        /// Builds a Unity Material from the given USD material sample.
        /// </summary>
        public static Material BuildMaterial(Scene scene,
                                             string materialPath,
                                             MaterialSample sample,
                                             SceneImportOptions options)
        {
            if (string.IsNullOrEmpty(sample.surface.connectedPath))
            {
                return(null);
            }

            var previewSurf = new UnityPreviewSurfaceSample();

            scene.Read(new pxr.SdfPath(sample.surface.connectedPath).GetPrimPath(), previewSurf);

            // Currently, only UsdPreviewSurface is supported.
            if (previewSurf.id == null || previewSurf.id != "UsdPreviewSurface")
            {
                Debug.LogWarning("Unknown surface type: <" + sample.surface.connectedPath + ">"
                                 + "Surface ID: " + previewSurf.id);
                return(null);
            }

            Material mat = null;

            if (options.materialMap.useOriginalShaderIfAvailable && !string.IsNullOrEmpty(previewSurf.unity.shaderName))
            {
                // We may or may not have the original shader.
                var shader = Shader.Find(previewSurf.unity.shaderName);
                if (shader)
                {
                    mat = new Material(shader);
                    mat.shaderKeywords = previewSurf.unity.shaderKeywords;
                }
                else
                {
                    Debug.LogWarning("Original shader not found: " + previewSurf.unity.shaderName);
                }
            }

            if (mat == null)
            {
                if (previewSurf.useSpecularWorkflow.defaultValue == 1)
                {
                    // Metallic workflow.
                    mat = Material.Instantiate(options.materialMap.SpecularWorkflowMaterial);
                }
                else
                {
                    // Metallic workflow.
                    mat = Material.Instantiate(options.materialMap.MetallicWorkflowMaterial);
                }
            }

            foreach (var kvp in previewSurf.unity.colorArgs)
            {
                mat.SetColor(kvp.Key, kvp.Value);
            }

            foreach (var kvp in previewSurf.unity.floatArgs)
            {
                mat.SetFloat(kvp.Key, kvp.Value);
            }

            foreach (var kvp in previewSurf.unity.vectorArgs)
            {
                mat.SetVector(kvp.Key, kvp.Value);
            }

            var pipeline = UnityEngine.Rendering.GraphicsSettings.renderPipelineAsset;

            if (!pipeline)
            {
                var matAdapter = new StandardShaderImporter(mat);
                matAdapter.ImportParametersFromUsd(scene, materialPath, sample, previewSurf, options);
                matAdapter.ImportFromUsd();
            }
            else if (pipeline.GetType().Name == "HDRenderPipelineAsset")
            {
                // Robustness: Comparing a strng ^ here is not great, but there is no other option.
                var matAdapter = new HdrpShaderImporter(mat);
                matAdapter.ImportParametersFromUsd(scene, materialPath, sample, previewSurf, options);
                matAdapter.ImportFromUsd();
            }
            else
            {
                // Fallback to the Standard importer, which may pickup some attributes by luck.
                var matAdapter = new StandardShaderImporter(mat);
                matAdapter.ImportParametersFromUsd(scene, materialPath, sample, previewSurf, options);
                matAdapter.ImportFromUsd();
            }

            // Get the material name from the path
            if (mat != null && !string.IsNullOrEmpty(materialPath))
            {
                mat.name = new pxr.SdfPath(materialPath).GetName();
            }

            return(mat);
        }
        public static Texture2D ImportConnectedTexture <T>(Scene scene,
                                                           Connectable <T> connection,
                                                           bool isNormalMap,
                                                           SceneImportOptions options,
                                                           out string uvPrimvar)
        {
            uvPrimvar = null;

            // TODO: look for the expected texture/primvar reader pair.
            var       textureSample     = new TextureReaderSample();
            var       connectedPrimPath = scene.GetSdfPath(connection.connectedPath).GetPrimPath();
            Texture2D result            = null;

            scene.Read(connectedPrimPath, textureSample);

            if (textureSample.file.defaultValue != null &&
                !string.IsNullOrEmpty(textureSample.file.defaultValue.GetResolvedPath()))
            {
                if (OnResolveTexture != null)
                {
                    result = OnResolveTexture(textureSample.file.defaultValue, isNormalMap, options);
                }
                else
                {
                    result = DefaultTextureResolver(textureSample.file.defaultValue, isNormalMap, options);
                }
            }

            Connectable <Vector2> st = textureSample.st;

            if (st != null && st.IsConnected() && !string.IsNullOrEmpty(st.connectedPath))
            {
                var pvSrc = new PrimvarReaderSample <Vector2>();
                scene.Read(new pxr.SdfPath(textureSample.st.connectedPath).GetPrimPath(), pvSrc);

                if (pvSrc.varname != null)
                {
                    if (pvSrc.varname.IsConnected())
                    {
                        var connPath = new pxr.SdfPath(pvSrc.varname.GetConnectedPath());
                        var attr     = scene.GetAttributeAtPath(connPath);
                        if (attr != null)
                        {
                            var value = attr.Get(scene.Time);
                            uvPrimvar = pxr.UsdCs.VtValueToTfToken(value).ToString();
                        }
                        else
                        {
                            Debug.LogWarning("No primvar name was provided at the connected path: " + connPath);
                            uvPrimvar = "";
                        }
                    }
                    else if (pvSrc.varname.defaultValue != null)
                    {
                        // Ask the mesh importer to load the specified texcoord.
                        // This must be a callback, since materials-to-meshes are one-to-many.
                        uvPrimvar = pvSrc.varname.defaultValue;
                    }
                }
            }

            return(result);
        }