【问题标题】:order Mesh vertices for whatever mesh's form (concave/convex )?为任何网格形式(凹/凸)订购网格顶点?
【发布时间】:2021-02-03 13:13:46
【问题描述】:

我有一个 3D 网格,我想做的是绘制我的顶部 2D 面的轮廓,所以在这里我可以访问顶部网格顶点和三角形索引,我想要的是排序顶点以便我可以画出我的轮廓。

 List<Vector3> GetSortedVerticesTest(Dictionary<CreateMesh.Faces, MeshData> mesh, Mesh mainMesh)
{
    List<Vector3> borderVertices = mesh[CreateMesh.Faces.Top].vertices.Where(p => mesh[CreateMesh.Faces.other].vertices.Any(e => e == p)).ToList();
    borderVertices = borderVertices.Distinct().ToList();
    List<Vector3> sortedVertices = new List<Vector3>();
    List<PointAngle> candidateAngles = new List<PointAngle>();
    Vector3 startingPoint = borderVertices[0];
    sortedVertices.Add(startingPoint);
    borderVertices.Remove(startingPoint);
    while (borderVertices.Count > 0)
    {
        List<Vector3> candidates = new List<Vector3>();
        for (int i = 0; i < mesh[CreateMesh.Faces.Top].triangles.Count(); i += 3)
        {
            bool commonTriangle = false;
            // verifie que le vertice courant est compris dans le triangle
            for (int k = 0; k < 3; k++)
            {
                int triIndex = mesh[CreateMesh.Faces.Top].triangles[i + k];
                Vector3 posToCompare = mainMesh.vertices[triIndex];

                if (startingPoint == posToCompare)
                {
                    commonTriangle = true;
                }
            }

            if (commonTriangle)
            {
                for (int k = 0; k < 3; k++)
                {
                    int triIndex = mesh[CreateMesh.Faces.Top].triangles[i + k];
                    Vector3 posToCompare = mainMesh.vertices[triIndex];
                    if (borderVertices.Contains(posToCompare))//epsilon
                        candidates.Add(posToCompare);

                }
                candidates.Remove(startingPoint);
                if (candidates.Count != 0)
                {
                    candidates.ForEach(c => candidateAngles.Add(new PointAngle { angle = Vector3.SignedAngle(c - startingPoint, transform.forward, Vector3.up), point = c }));
                    double min = candidateAngles.Min(kvp => kvp.angle);
                    var a = candidateAngles[0].point;
                    PointAngle pointsToKeep = new PointAngle();
                    pointsToKeep = candidateAngles.Where(s => s.angle == min).First();
                    sortedVertices.Add(pointsToKeep.point);
                    borderVertices.Remove(pointsToKeep.point);
                    print("vert coun" + borderVertices.Count);
                    startingPoint = pointsToKeep.point;
                    candidateAngles.Clear();
                }
            }
        }
    }
    return sortedVertices;
}

我在这里尝试让所有点候选人获得下一个顶点

【问题讨论】:

  • 我会假设输出将代表顶部三角形的边界边缘?边缘是否排序是否重要?问题是如何将边列表排序为线段,还是如何生成边列表?
  • 输出将是有序的顶点或顶部网格边的列表。
  • 按什么顺序?您认为正确排序的顶点数组的标准是什么?还要考虑一个在 X 上旋转约 45° 的网格......现在哪个是“顶部顶点”?
  • 我的最终目标是将网格数据导出到 dxf 文件,这样我就需要网格的所有顶点(顶部、底部)按照绘制每个面轮廓的顺序。

标签: c# unity3d mesh vertices


【解决方案1】:

我无法方便地访问 unity3D,以下示例将使用 MeshGeometry3D。但我希望这些类足够相似,以便于翻译。

这应该为通过一些任意标准的三角形生成边界边缘列表。我假设这是您要实现的实际目标。边表示为网格顶点列表的一对索引。

应该可以简单地绘制每条边。还应该可以通过一些额外的处理将边缘连接到线条。

            public static IEnumerable<(int e1, int e2)> GetBorderEdges(MeshGeometry3D mesh, Func<Vector3D, bool > triangleNormalFilter )
    {
        var numTriangles = mesh.TriangleIndices.Count / 3;
        
        // use a value tuple to represent edges,
        // value tuples have a default equal/getHashCode, so can be used in HashSet
        // Since (1, 2) and (2, 1) are considered the same edge,
        // all edges should be ordered smallest index first.
        var allEdges = new HashSet<(int e1, int e2)>();
        var nonBorderEdges = new HashSet<(int e1, int e2)>();
        for (int i = 0; i < numTriangles; i++)
        {
            var normal = mesh.Normals[i];

            // Only process triangles that pass some test,
            // like normals pointing up (assuming normals exist)
            if (triangleNormalFilter(normal))
            {
                // Multiply by three to get the index of the first value in the TriangleIndices list
                var triangleIndex = i * 3;
                foreach (var edge in GetEdges(mesh, triangleIndex))
                {
                    // If the edge is already in allEdges, Add will return false
                    if (!allEdges.Add(edge))
                    {
                        // Since the edge must be part of two triangles, it is a non border edge
                        nonBorderEdges.Add(edge);
                    }
                }
            }
        }

        // Remove non border edges and return the result
        allEdges.ExceptWith(nonBorderEdges);

        return allEdges;
    }

    // return all edges for a triangle
    private static (int e1, int e2)[] GetEdges(MeshGeometry3D mesh, int triangleIndex)
    {
        var t = triangleIndex;
        var ti = mesh.TriangleIndices;
        return new[]
        {
            CreateEdge(ti[triangleIndex], ti[t + 1]),
            CreateEdge(ti[triangleIndex + 1], ti[t + 2]),
            CreateEdge(ti[triangleIndex + 2], ti[t]),
        };
    }

    // ensures edges are always created smaller index first
    private static (int e1, int e2) CreateEdge(int e1, int e2)
    {
        if (e2 < e1)
        {
            return (e2, e1);
        }
        return (e1, e2);
    }

【讨论】:

  • 谢谢,这对我很有帮助。提取网格边缘效果很好
猜你喜欢
  • 2018-05-05
  • 2013-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-11
  • 2019-02-14
  • 2021-11-06
相关资源
最近更新 更多