Example #1
0
            public void Execute(int index)
            {
                HierInfo info = new HierInfo();

                info.prim = scene.Stage.GetPrimAtPath(paths[index]);

                if (!info.prim)
                {
                    info.prim = null;
                    return;
                }

                info.isVisible  = HierarchyBuilder.IsVisible(info.prim);
                info.isInstance = info.prim.IsInstance();
                HierarchyBuilder.ReadModelInfo(ref info);
                HierarchyBuilder.ReadSkeleton(ref info);
                info.hasPayload = info.prim.GetPrimIndex().HasPayload();

                result[index] = info;
            }
Example #2
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();
        }