public bool Load(string path)
 {
     if (!InitUsd.Initialize())
     {
         return(false);
     }
     m_Scene = Scene.Open(path);
     return(m_Scene != null);
 }
Beispiel #2
0
 void Start()
 {
     InitUsd.Initialize();
     m_lastTime = m_usdTime;
     if (string.IsNullOrEmpty(m_usdFile))
     {
         m_usdFile = Path.Combine(PackageUtils.GetCallerRelativeToProjectFolderPath(), K_DEFAULT_MESH);
     }
 }
Beispiel #3
0
        /// Starts recording the transform to a named transform in a new usd file given by the path.
        public bool StartRecording(string path, string sketchName = "/Sketch", string xformName = "/VideoCamera")
        {
            m_xformName = sketchName + xformName;
            if (!InitUsd.Initialize() || string.IsNullOrEmpty(path))
            {
                return(false);
            }

            // Find the active camera.
            m_RecordingCamera = null;
            foreach (var c in GetComponentsInChildren <Camera>())
            {
                if (c.gameObject.activeInHierarchy && c.isActiveAndEnabled)
                {
                    m_RecordingCamera = c;
                }
            }
            if (m_RecordingCamera == null)
            {
                return(false);
            }

            var sketchRoot = ExportUsd.CreateSketchRoot();

            m_UsdCamera = new UsdCameraXformSample();
            try
            {
                m_Scene = USD.NET.Scene.Create(path);
            }
            catch (ApplicationException /*e*/)
            {
                Debug.LogError("Error creating usda file!");
                return(false);
            }

            m_Scene.Write(sketchName, sketchRoot);

            // The time code of the recording is in seconds.
            m_Scene.Stage.SetTimeCodesPerSecond(1);

            // CameraSample constructor converts the Unity Camera to USD.
            // Write the fallback camera parameters.
            var cameraSample = new UsdCameraSample(m_RecordingCamera);

            // Convert camera params to meters.
            cameraSample.clippingRange *= App.UNITS_TO_METERS;

            m_Scene.Write(m_xformName, cameraSample);

            m_Scene.Time      = 0;
            m_Scene.StartTime = 0;
            m_Scene.EndTime   = 0;

            m_IsRecording = true;
            return(true);
        }
Beispiel #4
0
        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();
        }
Beispiel #5
0
        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();
        }
Beispiel #6
0
        public void ExportUsdz(string filePath, bool deleteUsdDirectory)
        {
            InitUsd.Initialize();

            var currentDir   = Directory.GetCurrentDirectory();
            var usdFileName  = Path.GetFileName(filePath);
            var usdzFileName = Path.GetFileNameWithoutExtension(usdFileName) + ".usdz";

            string usdzDirectroy;

            if (string.IsNullOrEmpty(this.exportDirectory))
            {
                usdzDirectroy = currentDir;
            }
            else
            {
                usdzDirectroy = Path.GetFullPath(this.exportDirectory);
            }
            var usdzFilePath = Path.Combine(usdzDirectroy, usdzFileName);

            try
            {
                // 画像の検索パスを合わせるためにカレントディレクトリを変更する
                // 後で戻し忘れるとUnityが壊れるので注意
                Directory.SetCurrentDirectory(Path.GetDirectoryName(filePath));

                var assetPath = new SdfAssetPath(usdFileName);
                var success   = UsdCs.UsdUtilsCreateNewARKitUsdzPackage(assetPath, usdzFilePath);
                if (!success)
                {
                    Debug.LogError("usdzファイルの出力に失敗しました");
                    return;
                }

                Debug.Log($"出力完了: '{usdzFilePath}'");
            }
            finally
            {
                // 変更していたディレクトリを戻す
                Directory.SetCurrentDirectory(currentDir);

                if (deleteUsdDirectory)
                {
                    var d = Path.GetDirectoryName(filePath);
                    // 違うディレクトリを消してしまうとやばいのでチェック
                    if (Path.GetFileName(d).StartsWith("temp-"))
                    {
                        var di = new DirectoryInfo(d);
                        di.Delete(true);
                    }
                }
            }
        }
        public void Setup()
        {
            InitUsd.Initialize();
            var usdPath = Path.GetFullPath(AssetDatabase.GUIDToAssetPath(k_USDGUID));
            var stage   = pxr.UsdStage.Open(usdPath, pxr.UsdStage.InitialLoadSet.LoadNone);
            var scene   = Scene.Open(stage);

            m_usdRoot = ImportHelpers.ImportSceneAsGameObject(scene);
            scene.Close();

            m_usdAsset = m_usdRoot.GetComponent <UsdAsset>();
            Assume.That(m_usdAsset, Is.Not.Null, "Could not find USDAsset component on root gameobject.");
        }
        //
        // Technically, this entire example could be written in either Awake() or Start(), but Awake is
        // used here to emphasize the one-time-only initialization from the work that could
        // potentially be executed at run-time.
        //

        void Awake()
        {
            // Init USD.
            InitUsd.Initialize();

            // In this example, we assume there is a set of well known shaders, we will look up the
            // material based on the associated ID. This map allows the identifier in USD to differ from
            // the identifier specified in the Unity shader.
            m_shaderMap = new Dictionary <string, ShaderPair>();

            // Setup the Standard shader USD <-> Unity mapping.
            m_shaderMap.Add("Unity.Standard",
                            new ShaderPair(UnityEngine.Shader.Find("Standard"), new StandardShaderSample()));
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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();
        }
Beispiel #11
0
        public void TestExportSparseTimesampling()
        {
            Assert.That(m_recordedUsdFile, Does.Exist);
            // Check that the Cube and Cylinder have timesamples, but not the Sphere (not animated)
            InitUsd.Initialize();
            var stage        = pxr.UsdStage.Open(m_recordedUsdFile, pxr.UsdStage.InitialLoadSet.LoadAll);
            var scene        = Scene.Open(stage);
            var cubePath     = "/Cube";
            var spherePath   = "/Cube/Sphere";
            var cylinderPath = "/Cube/Cylinder";

            var keyframeDict = scene.ComputeKeyFrames(cubePath, attribute: "xformOp:transform");

            // there should be transform keyframes for cube and cylinder but not sphere
            Assert.That(keyframeDict.ContainsKey(cubePath), Is.True, "Missing timesamples for Cube in recorded usd");
            Assert.That(keyframeDict.ContainsKey(cylinderPath), Is.True, "Missing timesamples for Cylinder in recorded usd");
            Assert.That(keyframeDict.ContainsKey(spherePath), Is.False, "There should not be timesamples for Sphere in the recorded usd");

            scene.Close();
        }
Beispiel #12
0
        protected override void SessionCreated(RecordingSession session)
        {
            base.SessionCreated(session);

            InitUsd.Initialize();
            var outputFile = Settings.FileNameGenerator.BuildAbsolutePath(session);

            if (Settings.ExportFormat == UsdRecorderSettings.Format.USDZ) // FIXME Support USDz
            {
                try
                {
                    currentDir = Directory.GetCurrentDirectory();
                    // Setup a temporary directory to export the wanted USD file and zip it.
                    var tmpDirPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                    usdzTemporaryDir = Directory.CreateDirectory(tmpDirPath);

                    // Get the usd file name to export and the usdz file name of the archive.
                    usdcFileName = Path.GetFileNameWithoutExtension(outputFile) + ".usdc";
                    usdzFileName = Path.GetFileName(outputFile);
                    var fi = new FileInfo(outputFile);
                    usdzFilePath = fi.FullName;

                    // Set the current working directory to the tmp directory to export with relative paths.
                    Directory.SetCurrentDirectory(tmpDirPath);

                    outputFile = Path.Combine(tmpDirPath, usdcFileName);
                }
                finally
                {
                    Directory.SetCurrentDirectory(currentDir);
                }
            }

            try
            {
                context = new ExportContext
                {
                    scene = ExportHelpers.InitForSave(outputFile)
                };
            }
            catch (Exception)
            {
                throw new InvalidOperationException($"The file is already open in Unity. Please close all references to it and try again: {outputFile}");
            }


            context.scene.FrameRate = Settings.FrameRate;                         // Variable framerate support ?
            context.scene.Stage.SetInterpolationType(Settings.InterpolationType); // User Option

            context.basisTransform  = Settings.BasisTransformation;
            context.activePolicy    = Settings.ActivePolicy;
            context.exportMaterials = Settings.ExportMaterials;

            context.scale = Settings.Scale;

            context.scene.StartTime = 0; // Absolute vs relative Time

            // Export the "default" frame, that is, all data which doesn't vary over time.
            context.scene.Time = null;

            Input.Context = context;
        }
Beispiel #13
0
 void Start()
 {
     InitUsd.Initialize();
     m_lastTime = m_usdTime;
 }
Beispiel #14
0
 public void SetUp()
 {
     InitUsd.Initialize();
 }
Beispiel #15
0
 void Start()
 {
     InitUsd.Initialize();
     Test();
 }
Beispiel #16
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 #17
0
 private void Awake()
 => InitUsd.Initialize();
Beispiel #18
0
        public void SetupScene()
        {
            InitUsd.Initialize();

            // Is the stage already loaded?
            if (m_scene != null && m_scene.Stage.GetRootLayer().GetIdentifier() == m_usdFile)
            {
                return;
            }

            // Does the path exist?
            if (!System.IO.File.Exists(m_usdFile))
            {
                return;
            }

            // Clear out the old scene.
            UnloadGameObjects();

            // Load the new scene.
            m_scene = Scene.Open(m_usdFile);
            if (m_scene == null)
            {
                throw new Exception("Failed to load");
            }

            // Set the time at which to read samples from USD.
            m_scene.Time = 0;

            // Handle configurable up-axis (Y or Z).
            Vector3 up     = GetUpVector(m_scene);
            var     rootXf = new GameObject("root");

            rootXf.transform.SetParent(transform, worldPositionStays: false);

            if (up != Vector3.up)
            {
                rootXf.transform.localRotation = Quaternion.FromToRotation(Vector3.up, up);
            }

            // Convert from right-handed (USD) to left-handed (Unity).
            // The math below works out to either (1, -1, 1) or (1, 1, -1), depending on up.
            rootXf.transform.localScale = up + -1 * (Vector3.one - up - Vector3.right) + Vector3.right;

            // Assign this transform as the root.
            m_primMap.Add("/", rootXf);

            // Load transforms.
            foreach (var path in m_scene.AllXforms)
            {
                var xf = new USD.NET.Unity.XformSample();
                m_scene.Read(path, xf);
                var go = new GameObject(path.GetName());
                AssignTransform(xf, go);
                AssignParent(path, go);
            }

            // Load meshes.
            foreach (var path in m_scene.AllMeshes)
            {
                var mesh = new USD.NET.Unity.MeshSample();
                m_scene.Read(path, mesh);
                var go = new GameObject(path.GetName());
                AssignTransform(mesh, go);
                AssignParent(path, go);
                BuildMesh(mesh, go);
            }

            // Load cameras.
            foreach (var prim in m_scene.Stage.GetAllPrimsByType("Camera"))
            {
                pxr.UsdGeomCamera camera = new pxr.UsdGeomCamera(prim);
                var go = new GameObject(prim.GetName());
                var xf = new USD.NET.Unity.XformSample();
                m_scene.Read(prim.GetPath(), xf);
                AssignTransform(xf, go);
                BuildCamera(camera, go);
                AssignParent(prim.GetPath(), go);
            }

            // Ensure the file and the identifier match.
            m_usdFile = m_scene.Stage.GetRootLayer().GetIdentifier();
        }
        // ------------------------------------------------------------------------------------------ //
        // Unity Behavior Events.
        // ------------------------------------------------------------------------------------------ //

        void Awake()
        {
            // Init USD.
            InitUsd.Initialize();
        }
Beispiel #20
0
        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);
        }