简体   繁体   中英

order Mesh vertices for whatever mesh's form (concave/convex )?

在此处输入图像描述

I have a 3D mesh and what I want to do is to draw the outline of my top 2D face, so here what I have acess to top mesh vertices and triangles indices and what i want is to order vertices so that I can draw my outline.

 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;
}

here I m trying to get for all points candidates to get next vertice

I don't have convenient access to unity3D, to the following example will be using MeshGeometry3D. But I hope the classes are similar enough that it would be easy to translate.

This should produce a list of border edges for triangles that pass some arbitrary criteria. I have assumed that this is the actual goal you are trying to accomplish. Edges are represented as a pair of indices for the vertex-list of the mesh.

It should be possible to simply draw each edge. It should also be possible to join edges to a line-strip with some additional processing.

            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);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM