コード例 #1
0
        public static UsdGeomMesh Define(UsdStageWeakPtr stage, SdfPath path)
        {
            UsdGeomMesh ret = new UsdGeomMesh(UsdCsPINVOKE.UsdGeomMesh_Define(UsdStageWeakPtr.getCPtr(stage), SdfPath.getCPtr(path)), true);

            if (UsdCsPINVOKE.SWIGPendingException.Pending)
            {
                throw UsdCsPINVOKE.SWIGPendingException.Retrieve();
            }
            return(ret);
        }
コード例 #2
0
        public static void TestTriangulation()
        {
            VtIntArray indices    = new VtIntArray();
            VtIntArray faceCounts = new VtIntArray();

            faceCounts.push_back(5);
            indices.push_back(0);
            indices.push_back(1);
            indices.push_back(2);
            indices.push_back(3);
            indices.push_back(4);

            faceCounts.push_back(4);
            indices.push_back(5);
            indices.push_back(6);
            indices.push_back(7);
            indices.push_back(8);

            faceCounts.push_back(3);
            indices.push_back(9);
            indices.push_back(10);
            indices.push_back(11);

            // Degenerate face.
            faceCounts.push_back(2);
            indices.push_back(12);
            indices.push_back(13);

            UsdGeomMesh.Triangulate(indices, faceCounts);

            AssertEqual((int)faceCounts.size(), 6);

            for (int i = 0; i < faceCounts.size(); i++)
            {
                AssertEqual((int)faceCounts[i], 3);
            }

            AssertEqual((int)indices.size(), 18);

            AssertEqual(indices[0], 0);
            AssertEqual(indices[1], 1);
            AssertEqual(indices[2], 2);

            AssertEqual(indices[3], 0);
            AssertEqual(indices[4], 2);
            AssertEqual(indices[5], 3);

            AssertEqual(indices[6], 0);
            AssertEqual(indices[7], 3);
            AssertEqual(indices[8], 4);

            AssertEqual(indices[9], 5);
            AssertEqual(indices[10], 6);
            AssertEqual(indices[11], 7);

            AssertEqual(indices[12], 5);
            AssertEqual(indices[13], 7);
            AssertEqual(indices[14], 8);

            AssertEqual(indices[15], 9);
            AssertEqual(indices[16], 10);
            AssertEqual(indices[17], 11);
        }
コード例 #3
0
        private static void BuildMesh_(string path,
                                       MeshSample usdMesh,
                                       Mesh unityMesh,
                                       GeometrySubsets geomSubsets,
                                       GameObject go,
                                       Renderer renderer,
                                       SceneImportOptions options)
        {
            // TODO: Because this method operates on a GameObject, it must be single threaded. For this
            // reason, it should be extremely light weight. All computation should be completed prior to
            // this step, allowing heavy computations to happen in parallel. This is not currently the
            // case, triangulation and change of basis are non-trivial operations. Computing the mesh
            // bounds, normals and tangents should similarly be moved out of this function and should not
            // rely on the UnityEngine.Mesh API.

            Material mat = renderer.sharedMaterial;
            bool     changeHandedness = options.changeHandedness == BasisTransformation.SlowAndSafe;

            //
            // Points.
            //

            if (options.meshOptions.points == ImportMode.Import && usdMesh.points != null)
            {
                if (changeHandedness)
                {
                    for (int i = 0; i < usdMesh.points.Length; i++)
                    {
                        usdMesh.points[i] = UnityTypeConverter.ChangeBasis(usdMesh.points[i]);
                    }
                }

                if (usdMesh.faceVertexIndices != null)
                {
                    // Annoyingly, there is a circular dependency between vertices and triangles, which makes
                    // it impossible to have a fixed update order in this function. As a result, we must clear
                    // the triangles before setting the points, to break that dependency.
                    unityMesh.SetTriangles(new int[0] {
                    }, 0);
                }
                unityMesh.vertices = usdMesh.points;
            }

            //
            // Purpose.
            //

            // Deactivate non-geometry prims (e.g. guides, render, etc).
            if (usdMesh.purpose != Purpose.Default)
            {
                go.SetActive(false);
            }

            //
            // Mesh Topology.
            //

            // TODO: indices should not be accessed if topology is not requested, however it may be
            // needed for facevarying primvars; that special case should throw a warning, rather than
            // reading the value.
            int[] originalIndices = new int[usdMesh.faceVertexIndices == null
                                      ? 0
                                      : usdMesh.faceVertexIndices.Length];
            // Optimization: only do this when there are face varying primvars.
            if (usdMesh.faceVertexIndices != null)
            {
                Array.Copy(usdMesh.faceVertexIndices, originalIndices, originalIndices.Length);
            }

            if (options.meshOptions.topology == ImportMode.Import && usdMesh.faceVertexIndices != null)
            {
                Profiler.BeginSample("Triangulate Mesh");
                if (options.meshOptions.triangulateMesh)
                {
                    // Triangulate n-gons.
                    // For best performance, triangulate off-line and skip conversion.
                    if (usdMesh.faceVertexIndices == null)
                    {
                        Debug.LogWarning("Mesh had no face indices: " + UnityTypeConverter.GetPath(go.transform));
                        return;
                    }
                    if (usdMesh.faceVertexCounts == null)
                    {
                        Debug.LogWarning("Mesh had no face counts: " + UnityTypeConverter.GetPath(go.transform));
                        return;
                    }
                    var indices = UnityTypeConverter.ToVtArray(usdMesh.faceVertexIndices);
                    var counts  = UnityTypeConverter.ToVtArray(usdMesh.faceVertexCounts);
                    UsdGeomMesh.Triangulate(indices, counts);
                    UnityTypeConverter.FromVtArray(indices, ref usdMesh.faceVertexIndices);
                }
                Profiler.EndSample();

                Profiler.BeginSample("Convert LeftHanded");
                bool isLeftHanded = usdMesh.orientation == Orientation.LeftHanded;
                if (changeHandedness && !isLeftHanded || !changeHandedness && isLeftHanded)
                {
                    // USD is right-handed, so the mesh needs to be flipped.
                    // Unity is left-handed, but that doesn't matter here.
                    for (int i = 0; i < usdMesh.faceVertexIndices.Length; i += 3)
                    {
                        int tmp = usdMesh.faceVertexIndices[i];
                        usdMesh.faceVertexIndices[i]     = usdMesh.faceVertexIndices[i + 1];
                        usdMesh.faceVertexIndices[i + 1] = tmp;
                    }
                }
                Profiler.EndSample();

                if (usdMesh.faceVertexIndices.Length > 65535)
                {
                    unityMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                }

                Profiler.BeginSample("Breakdown triangles for Mesh Subsets");
                if (geomSubsets.Subsets.Count == 0)
                {
                    unityMesh.triangles = usdMesh.faceVertexIndices;
                }
                else
                {
                    unityMesh.subMeshCount = geomSubsets.Subsets.Count;
                    int subsetIndex = 0;
                    foreach (var kvp in geomSubsets.Subsets)
                    {
                        int[] faceIndices     = kvp.Value;
                        int[] triangleIndices = new int[faceIndices.Length * 3];

                        for (int i = 0; i < faceIndices.Length; i++)
                        {
                            triangleIndices[i * 3 + 0] = usdMesh.faceVertexIndices[faceIndices[i] * 3 + 0];
                            triangleIndices[i * 3 + 1] = usdMesh.faceVertexIndices[faceIndices[i] * 3 + 1];
                            triangleIndices[i * 3 + 2] = usdMesh.faceVertexIndices[faceIndices[i] * 3 + 2];
                        }

                        unityMesh.SetTriangles(triangleIndices, subsetIndex);
                        subsetIndex++;
                    }
                }
                Profiler.EndSample();
            }

            //
            // Extent / Bounds.
            //

            bool hasBounds = usdMesh.extent.size.x > 0 ||
                             usdMesh.extent.size.y > 0 ||
                             usdMesh.extent.size.z > 0;

            if (ShouldImport(options.meshOptions.boundingBox) && hasBounds)
            {
                Profiler.BeginSample("Import Bounds");
                if (changeHandedness)
                {
                    usdMesh.extent.center  = UnityTypeConverter.ChangeBasis(usdMesh.extent.center);
                    usdMesh.extent.extents = UnityTypeConverter.ChangeBasis(usdMesh.extent.extents);
                }
                unityMesh.bounds = usdMesh.extent;
                Profiler.EndSample();
            }
            else if (ShouldCompute(options.meshOptions.boundingBox))
            {
                Profiler.BeginSample("Calculate Bounds");
                unityMesh.RecalculateBounds();
                Profiler.EndSample();
            }

            //
            // Normals.
            //

            if (usdMesh.normals != null && ShouldImport(options.meshOptions.normals))
            {
                Profiler.BeginSample("Import Normals");
                if (changeHandedness)
                {
                    for (int i = 0; i < usdMesh.points.Length; i++)
                    {
                        usdMesh.normals[i] = UnityTypeConverter.ChangeBasis(usdMesh.normals[i]);
                    }
                }
                // If more normals than verts, assume face-varying.
                if (usdMesh.normals.Length > usdMesh.points.Length)
                {
                    usdMesh.normals = UnrollFaceVarying(usdMesh.points.Length, usdMesh.normals, usdMesh.faceVertexCounts, originalIndices);
                }
                unityMesh.normals = usdMesh.normals;
                Profiler.EndSample();
            }
            else if (ShouldCompute(options.meshOptions.normals))
            {
                Profiler.BeginSample("Calculate Normals");
                unityMesh.RecalculateNormals();
                Profiler.EndSample();
            }

            //
            // Tangents.
            //

            if (usdMesh.tangents != null && ShouldImport(options.meshOptions.tangents))
            {
                Profiler.BeginSample("Import Tangents");
                if (changeHandedness)
                {
                    for (int i = 0; i < usdMesh.points.Length; i++)
                    {
                        var w = usdMesh.tangents[i].w;
                        var t = UnityTypeConverter.ChangeBasis(usdMesh.tangents[i]);
                        usdMesh.tangents[i] = new Vector4(t.x, t.y, t.z, w);
                    }
                }
                unityMesh.tangents = usdMesh.tangents;
                Profiler.EndSample();
            }
            else if (ShouldCompute(options.meshOptions.tangents))
            {
                Profiler.BeginSample("Calculate Tangents");
                unityMesh.RecalculateTangents();
                Profiler.EndSample();
            }

            //
            // Display Color.
            //

            if (ShouldImport(options.meshOptions.color) && usdMesh.colors != null && usdMesh.colors.Length > 0)
            {
                Profiler.BeginSample("Import Display Color");
                // NOTE: The following color conversion assumes PlayerSettings.ColorSpace == Linear.
                // For best performance, convert color space to linear off-line and skip conversion.

                if (usdMesh.colors.Length == 1)
                {
                    // Constant color can just be set on the material.
                    if (options.useDisplayColorAsFallbackMaterial && options.materialImportMode != MaterialImportMode.None)
                    {
                        mat = options.materialMap.InstantiateSolidColor(usdMesh.colors[0].gamma);
                    }
                }
                else if (usdMesh.colors.Length == usdMesh.points.Length)
                {
                    // Vertex colors map on to verts.
                    // TODO: move the conversion to C++ and use the color management API.
                    for (int i = 0; i < usdMesh.colors.Length; i++)
                    {
                        usdMesh.colors[i] = usdMesh.colors[i];
                    }
                    unityMesh.colors = usdMesh.colors;
                }
                else if (usdMesh.colors.Length == usdMesh.faceVertexCounts.Length)
                {
                    // Uniform colors, one per face.
                    // Unroll face colors into vertex colors. This is not strictly correct, but it's much faster
                    // than the fully correct solution.
                    var colors = new Color[unityMesh.vertexCount];
                    int idx    = 0;
                    try {
                        for (int faceIndex = 0; faceIndex < usdMesh.colors.Length; faceIndex++)
                        {
                            var faceColor = usdMesh.colors[faceIndex];
                            for (int f = 0; f < usdMesh.faceVertexCounts[faceIndex]; f++)
                            {
                                int vertexInFaceIdx = originalIndices[idx++];
                                colors[vertexInFaceIdx] = faceColor;
                            }
                        }
                        unityMesh.colors = colors;
                    } catch (Exception ex) {
                        Debug.LogException(new Exception("Failed loading uniform/per-face colors at " + path, ex));
                    }
                }
                else if (usdMesh.colors.Length > usdMesh.points.Length)
                {
                    try {
                        usdMesh.colors = UnrollFaceVarying(unityMesh.vertexCount,
                                                           usdMesh.colors,
                                                           usdMesh.faceVertexCounts,
                                                           originalIndices);
                        for (int i = 0; i < usdMesh.colors.Length; i++)
                        {
                            usdMesh.colors[i] = usdMesh.colors[i];
                        }
                        unityMesh.colors = usdMesh.colors;
                    } catch (Exception ex) {
                        Debug.LogException(
                            new Exception("Error unrolling Face-Varying colors at <" + path + ">", ex));
                    }
                }
                else
                {
                    Debug.LogWarning("Uniform (color per face) display color not supported");
                }
                Profiler.EndSample();
            } // should import color

            //
            // UVs / Texture Coordinates.
            //

            // TODO: these should also be driven by the UV privmars required by the bound shader.
            Profiler.BeginSample("Import UV Sets");
            ImportUv(path, unityMesh, 0, usdMesh.st, usdMesh.indices, usdMesh.faceVertexCounts, originalIndices, options.meshOptions.texcoord0, go);
            ImportUv(path, unityMesh, 0, usdMesh.uv, null, usdMesh.faceVertexCounts, originalIndices, options.meshOptions.texcoord0, go);
            ImportUv(path, unityMesh, 1, usdMesh.uv2, null, usdMesh.faceVertexCounts, originalIndices, options.meshOptions.texcoord1, go);
            ImportUv(path, unityMesh, 2, usdMesh.uv3, null, usdMesh.faceVertexCounts, originalIndices, options.meshOptions.texcoord2, go);
            ImportUv(path, unityMesh, 3, usdMesh.uv4, null, usdMesh.faceVertexCounts, originalIndices, options.meshOptions.texcoord3, go);
            Profiler.EndSample();

            Profiler.BeginSample("Request Material Bindings");

            //
            // Materials.
            //

            if (options.materialImportMode != MaterialImportMode.None)
            {
                if (mat == null)
                {
                    mat = options.materialMap.InstantiateSolidColor(Color.white);
                }

                if (unityMesh.subMeshCount == 1)
                {
                    renderer.sharedMaterial = mat;
                    if (options.ShouldBindMaterials)
                    {
                        options.materialMap.RequestBinding(path,
                                                           (scene, boundMat, primvars) => BindMat(scene, unityMesh, boundMat, renderer, path, primvars, usdMesh.faceVertexCounts, originalIndices));
                    }
                }
                else
                {
                    var mats = new Material[unityMesh.subMeshCount];
                    for (int i = 0; i < mats.Length; i++)
                    {
                        mats[i] = mat;
                    }
                    renderer.sharedMaterials = mats;
                    if (options.ShouldBindMaterials)
                    {
                        Debug.Assert(geomSubsets.Subsets.Count == unityMesh.subMeshCount);
                        var subIndex = 0;
                        foreach (var kvp in geomSubsets.Subsets)
                        {
                            int idx = subIndex++;
                            options.materialMap.RequestBinding(kvp.Key,
                                                               (scene, boundMat, primvars) => BindMat(scene, unityMesh, boundMat, renderer, idx, path, primvars, usdMesh.faceVertexCounts, originalIndices));
                        }
                    }
                }
            }
            Profiler.EndSample();

            //
            // Lightmap UV Unwrapping.
            //

#if UNITY_EDITOR
            if (options.meshOptions.generateLightmapUVs)
            {
#if !UNITY_2018_3_OR_NEWER
                if (unityMesh.indexFormat == UnityEngine.Rendering.IndexFormat.UInt32)
                {
                    Debug.LogWarning("Skipping prim " + path + " due to large IndexFormat (UInt32) bug in older vesrsions of Unity");
                    return;
                }
#endif
                Profiler.BeginSample("Unwrap Lightmap UVs");
                var unwrapSettings = new UnityEditor.UnwrapParam();

                unwrapSettings.angleError = options.meshOptions.unwrapAngleError;
                unwrapSettings.areaError  = options.meshOptions.unwrapAngleError;
                unwrapSettings.hardAngle  = options.meshOptions.unwrapHardAngle;

                // Convert pixels to unitless UV space, which is what unwrapSettings uses internally.
                unwrapSettings.packMargin = options.meshOptions.unwrapPackMargin / 1024.0f;

                UnityEditor.Unwrapping.GenerateSecondaryUVSet(unityMesh, unwrapSettings);
                Profiler.EndSample();
            }
#else
            if (options.meshOptions.generateLightmapUVs)
            {
                Debug.LogWarning("Lightmap UVs were requested to be generated, but cannot be generated outside of the editor");
            }
#endif
        }
コード例 #4
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(UsdGeomMesh obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
コード例 #5
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);
        }