Exemplo n.º 1
0
        /// 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);
        }
Exemplo n.º 2
0
        /// 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);
        }
Exemplo n.º 3
0
        /// 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;
        }
Exemplo n.º 4
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();
        }
Exemplo n.º 5
0
 /// 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));
 }
Exemplo n.º 6
0
        /// 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);
        }