/// <summary> /// Ensure each layer path is expressed in the USD sub layer stack of the given scene, /// creating the sublayer USD files if needed. /// </summary> public void SaveLayerStack(Scene scene, string[] layerStack) { if (scene == null) { throw new NullReferenceException("Null scene provided to SaveLayerStack"); } SdfSubLayerProxy subLayers = scene.Stage.GetRootLayer().GetSubLayerPaths(); for (int i = 0; i < m_layerStack.Length; i++) { string absoluteLayerPath = m_layerStack[i]; string relativeLayerPath = ImporterBase.MakeRelativePath(scene.FilePath, absoluteLayerPath); if (!System.IO.File.Exists(absoluteLayerPath)) { var newSubLayer = Scene.Create(absoluteLayerPath); SetupNewSubLayer(scene, newSubLayer); newSubLayer.Save(); newSubLayer.Close(); } if (subLayers.Count(relativeLayerPath) == 0) { subLayers.push_back(relativeLayerPath); } } scene.Save(); }
public static void FrameRateTest() { USD.NET.Scene scene = USD.NET.Scene.Create(); scene.FrameRate = 30; AssertEqual(scene.FrameRate, 30); scene.Close(); }
public static void PrintScene(USD.NET.Scene scene) { string layer; scene.Stage.ExportToString(out layer, addSourceFileComment: false); Console.WriteLine(layer); }
public static void StartEndTimeTest() { USD.NET.Scene scene = USD.NET.Scene.Create(); scene.StartTime = 0; scene.EndTime = 1; AssertEqual(scene.StartTime, 0); AssertEqual(scene.EndTime, 1); scene.Close(); }
public string CreateTmpUsdFile(string fileName) { var filePath = System.IO.Path.Combine(UnityEngine.Application.dataPath, fileName); var scene = Scene.Create(filePath); scene.Save(); scene.Close(); m_filesToDelete.Add(filePath); return(filePath); }
public void SetUp() { InitUsd.Initialize(); var usdPath = Path.GetFullPath(AssetDatabase.GUIDToAssetPath(m_usdGUID)); var stage = pxr.UsdStage.Open(usdPath, pxr.UsdStage.InitialLoadSet.LoadNone); var scene = Scene.Open(stage); m_usdRoot = ImportHelpers.ImportSceneAsGameObject(scene); scene.Close(); }
/// <summary> /// Initialize a layer as a subLayer to be compatible with the parentLayer. /// </summary> private void SetupNewSubLayer(Scene parentScene, Scene subLayerScene) { if (parentScene == null) { throw new NullReferenceException("ParentScene is null"); } subLayerScene.WriteMode = Scene.WriteModes.Over; subLayerScene.UpAxis = parentScene.UpAxis; }
public void SetUp() { InitUsd.Initialize(); var usdPath = Path.GetFullPath(AssetDatabase.GUIDToAssetPath(m_usdGUID)); var stage = pxr.UsdStage.Open(usdPath, pxr.UsdStage.InitialLoadSet.LoadNone); var scene = Scene.Open(stage); var importOptions = new SceneImportOptions(); importOptions.materialImportMode = MaterialImportMode.ImportPreviewSurface; m_usdRoot = ImportHelpers.ImportSceneAsGameObject(scene, importOptions: importOptions); scene.Close(); }
/// Authors a USD Xform prim at the given path with the given matrix transform. static void CreateXform(USD.NET.Scene scene, string path, Matrix4x4?xform = null) { var sample = new XformSample(); if (xform.HasValue) { sample.transform = xform.Value; } else { sample.transform = Matrix4x4.identity; } scene.Write(path, sample); }
/// Authors the root "Sketch" object to be exported, with sketch metadta. static void AddSketchRoot(USD.NET.Scene scene, string path) { var sample = CreateSketchRoot(); // Setup time to author default values, at no time sample. var oldTime = scene.Time; scene.Time = null; // Write the data. scene.Write(path, sample); // Restore the desired time. scene.Time = oldTime; }
private GameObject LoadUSD(Object usdObject, BasisTransformation changeHandedness = BasisTransformation.SlowAndSafeAsFBX) { InitUsd.Initialize(); var usdPath = Path.GetFullPath(AssetDatabase.GetAssetPath(usdObject)); var stage = pxr.UsdStage.Open(usdPath, pxr.UsdStage.InitialLoadSet.LoadNone); var scene = Scene.Open(stage); var importOptions = new SceneImportOptions(); importOptions.changeHandedness = changeHandedness; importOptions.scale = 0.01f; importOptions.materialImportMode = MaterialImportMode.ImportDisplayColor; var usdRoot = ImportHelpers.ImportSceneAsGameObject(scene, importOptions: importOptions); scene.Close(); return(usdRoot); }
/// Authors USD Texture and PrimvarReader shader nodes for the given exportable material. /// /// Note that textureUris are stored as metadata and only the "Export Texture" is authored as a /// true texture in the shading network. This is due to the fact that the actual material textures /// are not currently exported with the USD file, but export textures are. /// /// Returns the texture path if a texture node was created, otherwise null. static string CreateAlphaTexture(USD.NET.Scene scene, string shaderPath, IExportableMaterial material) { // Currently, only export texture is previewed in USD. // Create an input parameter to read the texture, e.g. inputs:_MainTex. if (!material.HasExportTexture()) { return(null); } string texFile = SanitizeIdentifier(material.DurableName) + System.IO.Path.GetExtension(material.GetExportTextureFilename()); // Establish paths in the USD scene. string texturePath = GetTexturePath(material, "MainTex", shaderPath); string primvarPath = GetPrimvarPath(material, "uv", texturePath); // Create the texture Prim. var texture = new ExportTextureSample(); // Connect the texture to the file on disk. texture.file.defaultValue = new pxr.SdfAssetPath(texFile); texture.st.SetConnectedPath(primvarPath, "outputs:result"); scene.Write(texturePath, texture); if (scene.GetPrimAtPath(new pxr.SdfPath(primvarPath)) == null) { if (material.VertexLayout.texcoord0.size == 2) { var primvar = new PrimvarReader2fSample("uv"); scene.Write(primvarPath, primvar); } else if (material.VertexLayout.texcoord0.size == 3) { var primvar = new PrimvarReader3fSample("uv"); scene.Write(primvarPath, primvar); } else if (material.VertexLayout.texcoord0.size == 4) { var primvar = new PrimvarReader4fSample("uv"); scene.Write(primvarPath, primvar); } } return(texturePath); }
/// <summary> /// Writes overrides to the currently targeted subLayer. /// </summary> public void SaveToLayer() { var stageRoot = GetComponent <UsdAsset>(); Scene subLayerScene = Scene.Create(m_targetLayer); if (subLayerScene == null) { throw new NullReferenceException("Could not create layer: " + m_targetLayer); } Scene rootScene = Scene.Open(stageRoot.usdFullPath); if (rootScene == null) { throw new NullReferenceException("Could not open base layer: " + stageRoot.usdFullPath); } SetupNewSubLayer(rootScene, subLayerScene); rootScene.Close(); rootScene = null; try { SceneExporter.Export(stageRoot.gameObject, subLayerScene, stageRoot.m_changeHandedness, exportUnvarying: false, zeroRootTransform: false); } catch (Exception ex) { Debug.LogException(ex); return; } finally { if (subLayerScene != null) { subLayerScene.Save(); subLayerScene.Close(); subLayerScene = null; } } }
public UnityEngine.Matrix4x4[] ComputeInstanceMatrices(USD.NET.Scene scene, string primPath) { var prim = scene.GetPrimAtPath(primPath); var pi = new pxr.UsdGeomPointInstancer(prim); var xforms = new pxr.VtMatrix4dArray(); pi.ComputeInstanceTransformsAtTime(xforms, scene.Time == null ? pxr.UsdTimeCode.Default() : scene.Time, 0); // Slow, but works. var matrices = new UnityEngine.Matrix4x4[xforms.size()]; for (int i = 0; i < xforms.size(); i++) { matrices[i] = UnityTypeConverter.FromMatrix(xforms[i]); } return(matrices); }
public void SetUp() { var fbxPath = AssetDatabase.GUIDToAssetPath(fbxGUID); var asset = AssetDatabase.LoadAssetAtPath <GameObject>(fbxPath); fbxRoot = PrefabUtility.InstantiatePrefab(asset) as GameObject; InitUsd.Initialize(); var usdPath = Path.GetFullPath(AssetDatabase.GUIDToAssetPath(usdGUID)); var stage = pxr.UsdStage.Open(usdPath, pxr.UsdStage.InitialLoadSet.LoadNone); var scene = Scene.Open(stage); var importOptions = new SceneImportOptions(); importOptions.changeHandedness = BasisTransformation.SlowAndSafeAsFBX; importOptions.scale = 0.01f; importOptions.materialImportMode = MaterialImportMode.ImportDisplayColor; usdRoot = USD.UsdMenu.ImportSceneAsGameObject(scene, importOptions); scene.Close(); }
public static GameObject Import( USD.NET.Scene scene, GameObject rootObj, Dictionary <SdfPath, GameObject> objectMap, UpdateMask mask, out List <string> warnings, List <string> pathsToUpdate = null) { // TODO: generalize this to avoid having to dig down into USD for sparse reads. TfToken brushToken = new pxr.TfToken("brush"); TfToken faceVertexIndicesToken = new pxr.TfToken("faceVertexIndices"); warnings = new List <string>(); // Would be nice to find a way to kick this off automatically. // Redundant calls are ignored. if (!InitUsd.Initialize()) { return(null); } // PLAN: Process any UsdStage either constructing or updating GameObjects as needed. // This should include analysis of the time samples to see what attributes are // actually varying so they are updated minimally. UsdPrimVector prims = null; if (pathsToUpdate == null) { prims = scene.Stage.GetAllPrims(); } else { prims = new UsdPrimVector(); foreach (var path in pathsToUpdate) { prims.Add(scene.Stage.GetPrimAtPath(new pxr.SdfPath(path))); } } for (int p = 0; p < prims.Count; p++) { // TODO: prims[p] generates garbage. UsdPrim usdPrim = prims[p]; UsdGeomMesh usdMesh = new UsdGeomMesh(usdPrim); if (!usdMesh) { continue; } ExportUsd.BrushSample sample = new ExportUsd.BrushSample(); if (mask == UpdateMask.All) { scene.Read(usdPrim.GetPath(), sample); } else { // TODO: Generalize this as a reusable mechanism for sparse reads. if (mask == UpdateMask.Topology) { sample.brush = new Guid((string)usdPrim.GetCustomDataByKey(brushToken)); var fv = usdPrim.GetAttribute(faceVertexIndicesToken).Get(scene.Time); sample.faceVertexIndices = USD.NET.IntrinsicTypeConverter.FromVtArray((VtIntArray)fv); } else { throw new NotImplementedException(); } } GameObject strokeObj; Mesh unityMesh; // // Construct the GameObject if needed. // if (!objectMap.TryGetValue(usdPrim.GetPath(), out strokeObj)) { // On first import, we need to pull in all the data, regardless of what was requested. mask = UpdateMask.All; BrushDescriptor brush = BrushCatalog.m_Instance.GetBrush(sample.brush); if (brush == null) { Debug.LogWarningFormat("Invalid brush GUID at path: <{0}> guid: {1}", usdPrim.GetPath(), sample.brush); continue; } strokeObj = UnityEngine.Object.Instantiate(brush.m_BrushPrefab); // Register the Prim/Object mapping. objectMap.Add(usdPrim.GetPath(), strokeObj); // Init the game object. strokeObj.transform.parent = rootObj.transform; strokeObj.GetComponent <MeshRenderer>().material = brush.Material; strokeObj.GetComponent <MeshFilter>().sharedMesh = new Mesh(); strokeObj.AddComponent <BoxCollider>(); unityMesh = strokeObj.GetComponent <MeshFilter>().sharedMesh; } else { unityMesh = strokeObj.GetComponent <MeshFilter>().sharedMesh; } // // Points // Note that points must come first, before all other mesh data. // if ((mask & UpdateMask.Points) == UpdateMask.Points) { unityMesh.vertices = sample.points; } // // Bounds // if ((mask & UpdateMask.Bounds) == UpdateMask.Bounds) { var bc = strokeObj.GetComponent <BoxCollider>(); bc.center = sample.extent.center; bc.size = sample.extent.size; unityMesh.bounds = bc.bounds; } // // Topology // if ((mask & UpdateMask.Topology) == UpdateMask.Topology) { unityMesh.triangles = sample.faceVertexIndices; } // // Normals // if ((mask & UpdateMask.Normals) == UpdateMask.Normals) { unityMesh.normals = sample.normals; } // // Color & Opacity // if ((mask & UpdateMask.Colors) == UpdateMask.Colors && sample.colors != null) { unityMesh.colors = sample.colors; } // // Tangents // if ((mask & UpdateMask.Tangents) == UpdateMask.Tangents && sample.tangents != null) { unityMesh.tangents = sample.tangents; } // // UVs // if ((mask & UpdateMask.UVs) == UpdateMask.UVs) { SetUv(unityMesh, 0, sample.uv); SetUv(unityMesh, 1, sample.uv2); SetUv(unityMesh, 2, sample.uv3); SetUv(unityMesh, 3, sample.uv4); } } // For each prim return(rootObj); }
public static void YUpTest() { USD.NET.Scene scene = USD.NET.Scene.Create(); AssertEqual(scene.UpAxis, USD.NET.Scene.UpAxes.Y); scene.Close(); }
// // 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. USD.NET.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; }
/// Authors a USD Material, Shader, parameters and connections between the two. /// The USD shader structure consists of a Material, which is connected to a shader output. The /// Shader consists of input parameters which are either connected to other shaders or in the case /// of public parameters, back to the material which is the public interface for the shading /// network. /// /// This function creates a material, shader, inputs, outputs, zero or more textures, and for each /// texture, a single primvar reader node to read the UV data from the geometric primitive. static string CreateMaterialNetwork(USD.NET.Scene scene, IExportableMaterial material, string rootPath = null) { var matSample = new ExportMaterialSample(); // Used scene object paths. string materialPath = GetMaterialPath(material, rootPath); string shaderPath = GetShaderPath(material, materialPath); string displayColorPrimvarReaderPath = GetPrimvarPath(material, "displayColor", shaderPath); string displayOpacityPrimvarReaderPath = GetPrimvarPath(material, "displayOpacity", shaderPath); // The material was already created. if (scene.GetPrimAtPath(materialPath) != null) { return(materialPath); } // Ensure the root material path is defined in the scene. scene.Stage.DefinePrim(new pxr.SdfPath(rootPath)); // Connect the materail surface to the output of the shader. matSample.surface.SetConnectedPath(shaderPath, "outputs:result"); scene.Write(materialPath, matSample); // Create the shader and conditionally connect the diffuse color to the MainTex output. var shaderSample = GetShaderSample(material); var texturePath = CreateAlphaTexture(scene, shaderPath, material); if (texturePath != null) { // A texture was created, so connect the opacity input to the texture output. shaderSample.opacity.SetConnectedPath(texturePath, "outputs:a"); } else { // TODO: currently primvars:displayOpacity is not multiplied when an alpha texture is // present. However, this only affects the USD preview. The correct solution // requires a multiply node in the shader graph, but this does not yet exist. scene.Write(displayOpacityPrimvarReaderPath, new PrimvarReader1fSample("displayOpacity")); shaderSample.opacity.SetConnectedPath(displayOpacityPrimvarReaderPath, "outputs:result"); } // Create a primvar reader to read primvars:displayColor. scene.Write(displayColorPrimvarReaderPath, new PrimvarReader3fSample("displayColor")); // Connect the diffuse color to the primvar reader. shaderSample.diffuseColor.SetConnectedPath(displayColorPrimvarReaderPath, "outputs:result"); scene.Write(shaderPath, shaderSample); // // Everything below is ad-hoc data, which is written using the low level USD API. // It consists of the Unity shader parameters and the non-exported texture URIs. // Also note that scene.GetPrimAtPath will return null when the prim is InValid, // so there is no need to call IsValid() on the resulting prim. // var shadeMaterial = new pxr.UsdShadeMaterial(scene.GetPrimAtPath(materialPath)); var shadeShader = new pxr.UsdShadeShader(scene.GetPrimAtPath(shaderPath)); if (material.SupportsDetailedMaterialInfo) { CreateShaderInputs(shadeShader, shadeMaterial, material.FloatParams); CreateShaderInputs(shadeShader, shadeMaterial, material.ColorParams); CreateShaderInputs(shadeShader, shadeMaterial, material.VectorParams); } CreateTextureUris(shadeShader.GetPrim(), material); return(materialPath); }
/// Set the material:binding relationship on the mesh/curve to target the given materialPath. static void BindMaterial(USD.NET.Scene scene, string primPath, string materialPath) { scene.Write(primPath, new MaterialBindingSample(materialPath)); }
// -------------------------------------------------------------------------------------------- // // 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(); }