Beispiel #1
0
    static void InitExportableObjects(GameObject go,
                                      ExportContext context) {
      var smr = go.GetComponent<SkinnedMeshRenderer>();
      var mr = go.GetComponent<MeshRenderer>();
      var mf = go.GetComponent<MeshFilter>();
      var cam = go.GetComponent<Camera>();
      Transform expRoot = context.exportRoot;

      var tmpPath = new pxr.SdfPath(UnityTypeConverter.GetPath(go.transform, expRoot));
      while (!tmpPath.IsRootPrimPath()) {
        tmpPath = tmpPath.GetParentPath();
      }

      // TODO: What if this path is in use?
      string materialBasePath = tmpPath.ToString() + "/Materials/";

      // Ensure the "Materials" prim is defined with a valid prim type.
      context.scene.Write(materialBasePath.TrimEnd('/'), new ScopeSample());

      if (smr != null) {
        foreach (var mat in smr.sharedMaterials) {
          if (!context.matMap.ContainsKey(mat)) {
            string usdPath = materialBasePath + pxr.UsdCs.TfMakeValidIdentifier(mat.name + "_" + mat.GetInstanceID().ToString());
            context.matMap.Add(mat, usdPath);
          }
        }
        CreateExportPlan(go, CreateSample<MeshSample>(context), MeshExporter.ExportSkinnedMesh, context);
        CreateExportPlan(go, CreateSample<MeshSample>(context), NativeExporter.ExportObject, context, insertFirst: false);
        if (smr.rootBone == null) {
          Debug.LogWarning("No root bone at: " + UnityTypeConverter.GetPath(go.transform, expRoot));
        } else if (smr.bones == null || smr.bones.Length == 0) {
          Debug.LogWarning("No bones at: " + UnityTypeConverter.GetPath(go.transform, expRoot));
        } else {
          // Each mesh in a model may have a different root bone, which now must be merged into a
          // single skeleton for export to USD.
          try {
            MergeBonesSimple(smr.transform, smr.rootBone, smr.bones, smr.sharedMesh.bindposes, context);
          } catch (Exception ex) {
            Debug.LogException(new Exception("Failed to merge bones for " + UnityTypeConverter.GetPath(smr.transform), ex));
          }
        }
      } else if (mf != null && mr != null) {
        foreach (var mat in mr.sharedMaterials) {
          if (mat == null) {
            continue;
          }
          if (!context.matMap.ContainsKey(mat)) {
            string usdPath = materialBasePath + pxr.UsdCs.TfMakeValidIdentifier(mat.name + "_" + mat.GetInstanceID().ToString());
            context.matMap.Add(mat, usdPath);
          }
        }
        CreateExportPlan(go, CreateSample<MeshSample>(context), MeshExporter.ExportMesh, context);
        CreateExportPlan(go, CreateSample<MeshSample>(context), NativeExporter.ExportObject, context, insertFirst: false);
      } else if (cam) {
        CreateExportPlan(go, CreateSample<CameraSample>(context), CameraExporter.ExportCamera, context);
        CreateExportPlan(go, CreateSample<CameraSample>(context), NativeExporter.ExportObject, context, insertFirst: false);
      }
    }
Beispiel #2
0
        public static void Export(GameObject root,
                                  ExportContext context,
                                  bool zeroRootTransform)
        {
            // Remove parent transform effects while exporting.
            // This must be restored before returning from this function.
            var parent = root.transform.parent;

            if (zeroRootTransform)
            {
                root.transform.SetParent(null, worldPositionStays: false);
            }

            // Also zero out and restore local rotations on the root.
            var localPos   = root.transform.localPosition;
            var localRot   = root.transform.localRotation;
            var localScale = root.transform.localScale;

            if (zeroRootTransform)
            {
                root.transform.localPosition = Vector3.zero;
                root.transform.localRotation = Quaternion.identity;
                root.transform.localScale    = Vector3.one;
            }

            // Scale overall scene for export (e.g. USDZ export needs scale 100)
            root.transform.localScale *= context.scale;

            UnityEngine.Profiling.Profiler.BeginSample("USD: Export");
            try
            {
                ExportImpl(root, context);
                var path = new pxr.SdfPath(UnityTypeConverter.GetPath(root.transform));
                var prim = context.scene.Stage.GetPrimAtPath(path);
                if (prim)
                {
                    context.scene.Stage.SetDefaultPrim(prim);
                }
            }
            finally
            {
                if (zeroRootTransform)
                {
                    root.transform.localPosition = localPos;
                    root.transform.localRotation = localRot;
                    root.transform.localScale    = localScale;
                    root.transform.SetParent(parent, worldPositionStays: false);
                }
                else
                {
                    root.transform.localScale = localScale;
                }

                UnityEngine.Profiling.Profiler.EndSample();
            }
        }
Beispiel #3
0
        public static void ExportSkelRoot(ObjectContext objContext, ExportContext exportContext)
        {
            var sample = (SkelRootSample)objContext.sample;

            // Compute bounds for the root, required by USD.
            bool first = true;

            // Ensure the bounds are computed in root-local space.
            // This is required because USD expects the extent to be a local bound for the SkelRoot.
            var oldParent = objContext.gameObject.transform.parent;

            objContext.gameObject.transform.SetParent(null, worldPositionStays: false);

            try
            {
                foreach (var r in objContext.gameObject.GetComponentsInChildren <Renderer>())
                {
                    if (first)
                    {
                        // Ensure the bounds object starts growing from the first valid child bounds.
                        first         = false;
                        sample.extent = r.bounds;
                    }
                    else
                    {
                        sample.extent.Encapsulate(r.bounds);
                    }
                }
            }
            finally
            {
                // Restore the root parent.
                objContext.gameObject.transform.SetParent(oldParent, worldPositionStays: false);
            }

            // Convert handedness if needed.
            if (exportContext.basisTransform == BasisTransformation.SlowAndSafe)
            {
                sample.extent.center = UnityTypeConverter.ChangeBasis(sample.extent.center);
            }

            // Convert the transform
            var path = new pxr.SdfPath(objContext.path);

            // If exporting for Z-Up, rotate the world.
            bool correctZUp = exportContext.scene.UpAxis == Scene.UpAxes.Z;

            sample.transform = XformExporter.GetLocalTransformMatrix(
                objContext.gameObject.transform,
                correctZUp,
                path.IsRootPrimPath(),
                exportContext.basisTransform);

            exportContext.scene.Write(objContext.path, sample);
        }
        SkeletonSample ReadUsdSkeleton(Scene scene, out string skelRootPath)
        {
            skelRootPath = null;
            if (scene == null)
            {
                return(null);
            }

            try
            {
                var path        = new pxr.SdfPath(m_usdMeshPath);
                var absRoot     = pxr.SdfPath.AbsoluteRootPath();
                var skelRelName = new pxr.TfToken("skel:skeleton");

                while (path != absRoot)
                {
                    var prim = scene.GetPrimAtPath(path);
                    path = path.GetParentPath();

                    if (prim.HasRelationship(skelRelName))
                    {
                        var targets = prim.GetRelationship(skelRelName).GetForwardedTargets();
                        if (targets.Count == 0)
                        {
                            Debug.LogWarning("skel:skeleton has no targets at path: " + prim.GetPath());
                            continue;
                        }

                        var skelTarget = scene.GetPrimAtPath(targets[0]);
                        if (skelTarget == null)
                        {
                            Debug.LogWarning("prim <" + prim.GetPath() +
                                             "> has skel:skeleton with missing target path: " + targets[0]);
                            continue;
                        }

                        skelRootPath = skelTarget.GetPath().ToString();
                        var sample = new SkeletonSample();
                        scene.Read(skelTarget.GetPath(), sample);
                        return(sample);
                    }
                }

                Debug.LogWarning("Skeleton not found for path: " + m_usdMeshPath);
                return(null);
            }
            catch (System.Exception ex)
            {
                Debug.LogException(ex);
                return(null);
            }
        }
Beispiel #5
0
        /// <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);
        }
        public static void ExportXform(ObjectContext objContext, ExportContext exportContext)
        {
            UnityEngine.Profiling.Profiler.BeginSample("USD: Xform Conversion");

            XformSample sample     = (XformSample)objContext.sample;
            var         localRot   = objContext.gameObject.transform.localRotation;
            var         localScale = objContext.gameObject.transform.localScale;
            var         path       = new pxr.SdfPath(objContext.path);

            // If exporting for Z-Up, rotate the world.
            bool correctZUp = exportContext.scene.UpAxis == Scene.UpAxes.Z;

            sample.transform = GetLocalTransformMatrix(
                objContext.gameObject.transform,
                correctZUp,
                path.IsRootPrimPath(),
                exportContext.basisTransform);

            UnityEngine.Profiling.Profiler.EndSample();

            UnityEngine.Profiling.Profiler.BeginSample("USD: Xform Write");
            exportContext.scene.Write(objContext.path, sample);
            UnityEngine.Profiling.Profiler.EndSample();
        }
        //
        // Start generates a USD scene procedurally, containing a single cube with a material, shader
        // and texture bound. It then inspects the cube to discover the material. A Unity material is
        // constructed and the parameters are copied in a generic way. Similarly, the texture is
        // discovered and loaded as a Unity Texture2D and bound to the material.
        //
        // Also See: https://docs.unity3d.com/Manual/MaterialsAccessingViaScript.html
        //
        void Start()
        {
            // Create a scene for this test, but could also be read from disk.
            Scene usdScene = CreateSceneWithShading();

            // Read the material and shader ID.
            var    usdMaterial = new MaterialSample();
            string shaderId;

            // ReadMaterial was designed for Unity and assumes there is one "surface" shader bound.
            if (!MaterialSample.ReadMaterial(usdScene, kCubePath, usdMaterial, out shaderId))
            {
                throw new System.Exception("Failed to read material");
            }

            // Map the shader ID to the corresponding Unity/USD shader pair.
            ShaderPair shader;

            if (shaderId == null || !m_shaderMap.TryGetValue(shaderId, out shader))
            {
                throw new System.Exception("Material had no surface bound");
            }

            //
            // Read and process the shader-specific parameters.
            //

            // UsdShade requires all connections target an attribute, but we actually want to deserialize
            // the entire prim, so we get just the prim path here.
            var shaderPath = new pxr.SdfPath(usdMaterial.surface.connectedPath).GetPrimPath();

            usdScene.Read(shaderPath, shader.usdShader);

            //
            // Construct material & process the inputs, textures, and keywords.
            //

            var mat = new UnityEngine.Material(shader.unityShader);

            // Apply material keywords.
            foreach (string keyword in usdMaterial.requiredKeywords ?? new string[0])
            {
                mat.EnableKeyword(keyword);
            }

            // Iterate over all input parameters and copy values and/or construct textures.
            foreach (var param in shader.usdShader.GetInputParameters())
            {
                if (!SetMaterialParameter(mat, param.unityName, param.value))
                {
                    throw new System.Exception("Incompatible shader data type: " + param.ToString());
                }
            }

            foreach (var param in shader.usdShader.GetInputTextures())
            {
                if (string.IsNullOrEmpty(param.connectedPath))
                {
                    // Not connected to a texture.
                    continue;
                }

                // Only 2D textures are supported in this example.
                var usdTexture = new Texture2DSample();

                // Again, we want the prim path, not the attribute path.
                var texturePath = new pxr.SdfPath(param.connectedPath).GetPrimPath();
                usdScene.Read(texturePath, usdTexture);

                // This example also only supports explicit sourceFiles, they cannot be connected.
                if (string.IsNullOrEmpty(usdTexture.sourceFile.defaultValue))
                {
                    continue;
                }

                // For details, see: https://docs.unity3d.com/Manual/MaterialsAccessingViaScript.html
                foreach (string keyword in param.requiredShaderKeywords)
                {
                    mat.EnableKeyword(keyword);
                }

                var data     = System.IO.File.ReadAllBytes(usdTexture.sourceFile.defaultValue);
                var unityTex = new Texture2D(2, 2);
                unityTex.LoadImage(data);
                mat.SetTexture(param.unityName, unityTex);
                Debug.Log("Set " + param.unityName + " to " + usdTexture.sourceFile.defaultValue);

                unityTex.Apply(updateMipmaps: true, makeNoLongerReadable: false);
            }

            //
            // Create and bind the geometry.
            //

            // Create a cube and set the material.
            // Note that geometry is handled minimally here and is incomplete.
            var cubeSample = new CubeSample();

            usdScene.Read(kCubePath, cubeSample);

            var go = GameObject.CreatePrimitive(PrimitiveType.Cube);

            go.transform.SetParent(transform, worldPositionStays: false);
            go.transform.localScale = Vector3.one * (float)cubeSample.size;
            m_cube = transform;

            go.GetComponent <MeshRenderer>().material = mat;
        }
Beispiel #8
0
        public static void SdfPathEqualityTest()
        {
            var A = new pxr.SdfPath("/Foo");
            var B = new pxr.SdfPath("/Foo");
            var C = new pxr.SdfPath("/Foo/Bar");

            AssertEqual(A, A);
            AssertEqual(B, B);
            AssertEqual(C, C);
            AssertEqual(A, B);
            AssertEqual(A, C.GetParentPath());
            AssertEqual(C.GetParentPath(), A);

            AssertEqual(A.GetHashCode(), A.GetHashCode());
            AssertEqual(B.GetHashCode(), B.GetHashCode());
            AssertEqual(C.GetHashCode(), C.GetHashCode());
            AssertEqual(A.GetHashCode(), B.GetHashCode());
            AssertEqual(A.GetHashCode(), C.GetParentPath().GetHashCode());
            AssertEqual(C.GetParentPath().GetHashCode(), A.GetHashCode());

            AssertEqual(A.GetHash(), A.GetHash());
            AssertEqual(B.GetHash(), B.GetHash());
            AssertEqual(C.GetHash(), C.GetHash());
            AssertEqual(A.GetHash(), B.GetHash());
            AssertEqual(A.GetHash(), C.GetParentPath().GetHash());
            AssertEqual(C.GetParentPath().GetHash(), A.GetHash());

            AssertEqual(A.ToString(), A.ToString());
            AssertEqual(B.ToString(), B.ToString());
            AssertEqual(C.ToString(), C.ToString());
            AssertEqual(A.ToString(), B.ToString());
            AssertEqual(A.ToString(), C.GetParentPath().ToString());
            AssertEqual(C.GetParentPath().ToString(), A.ToString());

            var hashSet = new HashSet <pxr.SdfPath>();

            hashSet.Add(A);
            AssertTrue(hashSet.Contains(A));
            AssertTrue(hashSet.Contains(B));
            AssertTrue(hashSet.Contains(C.GetParentPath()));
            AssertTrue(hashSet.Remove(B));

            hashSet.Add(B);
            AssertTrue(hashSet.Contains(A));
            AssertTrue(hashSet.Contains(B));
            AssertTrue(hashSet.Contains(C.GetParentPath()));
            AssertTrue(hashSet.Remove(C.GetParentPath()));

            var dict = new Dictionary <pxr.SdfPath, string>();

            dict.Add(A, A.GetString());
            AssertTrue(dict.ContainsKey(A));
            AssertTrue(dict.ContainsKey(B));
            AssertTrue(dict.ContainsKey(C.GetParentPath()));
            AssertTrue(dict.Remove(B));

            dict.Add(B, B.GetString());
            AssertTrue(dict.ContainsKey(A));
            AssertTrue(dict.ContainsKey(B));
            AssertTrue(dict.ContainsKey(C.GetParentPath()));
            AssertTrue(dict.Remove(C.GetParentPath()));
        }
        /// <summary>
        /// Writes SerializedProperty to USD, traversing all nested properties.
        /// </summary>
        static void PropertyToUsd(string path,
                                  string propPrefix,
                                  Scene scene,
                                  SerializedProperty prop,
                                  System.Text.StringBuilder sb)
        {
            string prefix = "";

            try
            {
                var nameStack = new List <string>();
                nameStack.Add("unity");
                if (!string.IsNullOrEmpty(propPrefix))
                {
                    nameStack.Add(propPrefix);
                }

                string lastName  = "";
                int    lastDepth = 0;

                while (prop.Next(prop.propertyType == SerializedPropertyType.Generic && !prop.isArray))
                {
                    string tabIn = "";
                    for (int i = 0; i < prop.depth; i++)
                    {
                        tabIn += "  ";
                    }

                    if (prop.depth > lastDepth)
                    {
                        Debug.Assert(lastName != "");
                        nameStack.Add(lastName);
                    }
                    else if (prop.depth < lastDepth)
                    {
                        nameStack.RemoveRange(nameStack.Count - (lastDepth - prop.depth), lastDepth - prop.depth);
                    }

                    lastDepth = prop.depth;
                    lastName  = prop.name;

                    if (nameStack.Count > 0)
                    {
                        prefix  = string.Join(":", nameStack.ToArray());
                        prefix += ":";
                    }
                    else
                    {
                        prefix = "";
                    }

                    sb.Append(tabIn + prefix + prop.name + "[" + prop.propertyType.ToString() + "] = ");
                    if (prop.isArray && prop.propertyType != SerializedPropertyType.String)
                    {
                        // TODO.
                        sb.AppendLine("ARRAY");
                    }
                    else if (prop.propertyType == SerializedPropertyType.Generic)
                    {
                        sb.AppendLine("Generic");
                    }
                    else if (prop.propertyType == SerializedPropertyType.AnimationCurve ||
                             prop.propertyType == SerializedPropertyType.Gradient)
                    {
                        // TODO.
                        sb.AppendLine(NativeSerialization.ValueToString(prop));
                    }
                    else
                    {
                        sb.AppendLine(NativeSerialization.ValueToString(prop));
                        var vtValue  = NativeSerialization.PropToVtValue(prop);
                        var primPath = new pxr.SdfPath(path);
                        var attrName = new pxr.TfToken(prefix + prop.name);

                        /*
                         * var oldPrim = context.prevScene.Stage.GetPrimAtPath(primPath);
                         * pxr.VtValue oldVtValue = null;
                         * if (oldPrim.IsValid()) {
                         * var oldAttr = oldPrim.GetAttribute(attrName);
                         * if (oldAttr.IsValid()) {
                         *  oldVtValue = oldAttr.Get(0);
                         * }
                         * }
                         *
                         * if (oldVtValue != null && vtValue == oldVtValue) {
                         * Debug.Log("skipping: " + prop.name);
                         * continue;
                         * }
                         */

                        var sdfType = NativeSerialization.GetSdfType(prop);
                        var prim    = scene.GetPrimAtPath(primPath);
                        var attr    = prim.CreateAttribute(attrName, sdfType);
                        attr.Set(vtValue);
                    }
                }
            }
            catch
            {
                Debug.LogWarning("Failed on: " + path + "." + prefix + prop.name);
                throw;
            }
        }
Beispiel #10
0
        // -------------------------------------------------------------------------------------------- //
        // Export Logic
        // -------------------------------------------------------------------------------------------- //

        /// Exports either all brush strokes or the given selection to the specified file.
        static public void ExportPayload(string outputFile)
        {
            // Would be nice to find a way to kick this off automatically.
            // Redundant calls are ignored.
            if (!InitUsd.Initialize())
            {
                return;
            }

            // Unity is left handed (DX), USD is right handed (GL)
            var payload      = ExportCollector.GetExportPayload(AxisConvention.kUsd);
            var brushCatalog = BrushCatalog.m_Instance;

            // The Scene object provids serialization methods arbitrary C# objects to USD.
            USD.NET.Scene scene = USD.NET.Scene.Create(outputFile);

            // The target time at which samples will be written.
            //
            // In this case, all data is being written to the "default" time, which means it can be
            // overridden by animated values later.
            scene.Time = null;

            // Bracketing times to specify the valid animation range.
            scene.StartTime = 1.0;
            scene.EndTime   = 1.0;

            const string kGeomName   = "/Geom";
            const string kCurvesName = "/Curves";

            string path = "";

            AddSketchRoot(scene, GetSketchPath()); // Create: </Sketch>

            CreateXform(scene, GetStrokesPath());  // Create: </Sketch/Strokes>
            CreateXform(scene, GetModelsPath());   // Create: </Sketch/Models>

            // Main export loop.
            try
            {
                foreach (ExportUtils.GroupPayload group in payload.groups)
                {
                    // Example: </Sketch/Strokes/Group_0>
                    path = GetGroupPath(group.id);
                    CreateXform(scene, path);

                    // Example: </Sketch/Strokes/Group_0/Geom>
                    CreateXform(scene, path + kGeomName);

                    // Example: </Sketch/Strokes/Group_0/Curves>
                    CreateXform(scene, path + kCurvesName);

                    int iBrushMeshPayload = -1;
                    foreach (var brushMeshPayload in group.brushMeshes)
                    {
                        ++iBrushMeshPayload;
                        // Conditionally moves Normal into Texcoord1 so that the normal semantic is respected.
                        // This only has an effect when layout.bFbxExportNormalAsTexcoord1 == true.
                        // Note that this modifies the GeometryPool in place.
                        FbxUtils.ApplyFbxTexcoordHack(brushMeshPayload.geometry);

                        // Brushes are expected to be batched by type/GUID.
                        Guid   brushGuid = brushMeshPayload.strokes[0].m_BrushGuid;
                        string brushName = "/" +
                                           SanitizeIdentifier(brushCatalog.GetBrush(brushGuid).DurableName) + "_";

                        // Example: </Sketch/Strokes/Group_0/Geom/Marker_0>
                        string meshPath = path + kGeomName + brushName;

                        // Example: </Sketch/Strokes/Group_0/Curves/Marker_0>
                        string curvePath = path + kCurvesName + brushName;

                        var geomPool       = brushMeshPayload.geometry;
                        var strokes        = brushMeshPayload.strokes;
                        var mat44          = Matrix4x4.identity;
                        var meshPrimPath   = new pxr.SdfPath(meshPath + iBrushMeshPayload.ToString());
                        var curvesPrimPath = new pxr.SdfPath(curvePath + iBrushMeshPayload.ToString());

                        //
                        // Geometry
                        //
                        BrushSample brushSample = GetBrushSample(geomPool, strokes, mat44);

                        // Write the BrushSample to the same point in the scenegraph at which it exists in Tilt
                        // Brush. Notice this method is Async, it is queued to a background thread to perform I/O
                        // which means it is not safe to read from the scene until WaitForWrites() is called.
                        scene.Write(meshPrimPath, brushSample);

                        //
                        // Stroke Curves
                        //
                        var curvesSample = GetCurvesSample(payload, strokes, Matrix4x4.identity);
                        scene.Write(curvesPrimPath, curvesSample);

                        //
                        // Materials
                        //
                        double?oldTime = scene.Time;
                        scene.Time = null;

                        string materialPath = CreateMaterialNetwork(
                            scene,
                            brushMeshPayload.exportableMaterial,
                            GetStrokesPath());

                        BindMaterial(scene, meshPrimPath.ToString(), materialPath);
                        BindMaterial(scene, curvesPrimPath.ToString(), materialPath);

                        scene.Time = oldTime;
                    }
                }

                //
                // Models
                //

                var knownModels = new Dictionary <Model, string>();

                int iModelMeshPayload = -1;
                foreach (var modelMeshPayload in payload.modelMeshes)
                {
                    ++iModelMeshPayload;
                    var modelId         = modelMeshPayload.modelId;
                    var modelNamePrefix = "/Model_"
                                          + SanitizeIdentifier(modelMeshPayload.model.GetExportName())
                                          + "_";
                    var modelName = modelNamePrefix + modelId;

                    var xf = modelMeshPayload.xform;
                    // Geometry pools may be repeated and should be turned into references.
                    var geomPool = modelMeshPayload.geometry;

                    var modelRootPath = new pxr.SdfPath(GetModelsPath() + modelName);

                    // Example: </Sketch/Models/Model_Andy_0>
                    CreateXform(scene, modelRootPath, xf);

                    // Example: </Sketch/Models/Model_Andy_0/Geom>
                    CreateXform(scene, modelRootPath + kGeomName);

                    string modelPathToReference;
                    if (knownModels.TryGetValue(modelMeshPayload.model, out modelPathToReference) &&
                        modelPathToReference != modelRootPath)
                    {
                        // Create an Xform, note that the world transform here will override the referenced model.
                        var meshXf = new MeshXformSample();
                        meshXf.transform = xf;
                        scene.Write(modelRootPath, meshXf);
                        // Add a USD reference to previously created model.
                        var prim = scene.Stage.GetPrimAtPath(modelRootPath);
                        prim.GetReferences().AddReference("", new pxr.SdfPath(modelPathToReference));
                        continue;
                    }

                    // Example: </Sketch/Models/Geom/Model_Andy_0/Mesh_0>
                    path = modelRootPath + kGeomName + "/Mesh_" + iModelMeshPayload.ToString();

                    var meshPrimPath = new pxr.SdfPath(path);
                    var meshSample   = new MeshSample();

                    GetMeshSample(geomPool, Matrix4x4.identity, meshSample);
                    scene.Write(path, meshSample);
                    scene.Stage.GetPrimAtPath(new pxr.SdfPath(path)).SetInstanceable(true);

                    //
                    // Materials
                    //

                    // Author at default time.
                    double?oldTime = scene.Time;
                    scene.Time = null;

                    // Model materials must live under the model root, since we will reference the model.
                    string materialPath = CreateMaterialNetwork(
                        scene,
                        modelMeshPayload.exportableMaterial,
                        modelRootPath);
                    BindMaterial(scene, meshPrimPath.ToString(), materialPath);

                    // Continue authoring at the desired time index.
                    scene.Time = oldTime;

                    //
                    // Setup to be referenced.
                    //
                    if (!knownModels.ContainsKey(modelMeshPayload.model))
                    {
                        knownModels.Add(modelMeshPayload.model, modelRootPath);
                    }
                }
            }
            catch
            {
                scene.Save();
                scene.Close();
                throw;
            }

            // Save will force a sync with all async reads and writes.
            scene.Save();
            scene.Close();
        }
Beispiel #11
0
 private static string GetObjectName(pxr.SdfPath rootPrimName, string path)
 {
     return(pxr.UsdCs.TfIsValidIdentifier(rootPrimName.GetName())
         ? rootPrimName.GetName()
         : GetObjectName(path));
 }
        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);
        }
Beispiel #13
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();
        }
Beispiel #14
0
 // Recreate hierarchy.
 void AssignParent(pxr.SdfPath path, GameObject go)
 {
     m_primMap.Add(path, go);
     go.transform.SetParent(m_primMap[path.GetParentPath()].transform, worldPositionStays: false);
 }