Get Outer/Edge Vertices C#

Good Afternoon, I am trying to get all the outer/edge vertices from my mesh. I know I can get the y and x array but am having troubles just getting the outer vertices.

using UnityEngine;
using System.Collections;

public class Shape : MonoBehaviour {

public Vector3[] Vertices;
public Vector3[] Outer;

void Start(){
// Set Vertices //


// Get Vertices //
for(int i = 0; i < Vertices.Length; i++)
Outer = Vertices*.x;*

}

}

Ok, even it’s 2d there are several approaches. First of all it depends on if the mesh actually uses shared vertices or not. If the vertices in the inside are not shared the mesh is technically not closed.

If all inside vertices are shared you can simply create pairs of shared edges. All edges which don’t have a shared edge have to be a boundary edge. This method would work also with concave meshes.

The next method only works with convex meshes but the mesh don’t need to have shared vertices. You simply test each edge and see if all vertices are on one side of the edge. If there are no vertices on the outside it’s a boundary edge.

If the mesh doesn’t have shared edges / vertices and is concave it’s getting difficult. You would have to match vertices based on their local position to determine if they are actually the same. Once all split vertices have been logically merged you can use the first approach.

ps: The first method actually don’t need the vertices array at all. You only work with indices. In the second and third case of course you have to use the vertices array.

edit
Here are some methods that will work on shared edges:

public static class EdgeHelpers
{
    public struct Edge
    {
        public int v1;
        public int v2;
        public int triangleIndex;
        public Edge(int aV1, int aV2, int aIndex)
        {
            v1 = aV1;
            v2 = aV2;
            triangleIndex = aIndex;
        }
    }

    public static List<Edge> GetEdges(int[] aIndices)
    {
        List<Edge> result = new List<Edge>();
        for (int i = 0; i < aIndices.Length; i += 3)
        {
            int v1 = aIndices[i];
            int v2 = aIndices[i + 1];
            int v3 = aIndices[i + 2];
            result.Add(new Edge(v1, v2, i));
            result.Add(new Edge(v2, v3, i));
            result.Add(new Edge(v3, v1, i));
        }
        return result;
    }

    public static List<Edge> FindBoundary(this List<Edge> aEdges)
    {
        List<Edge> result = new List<Edge>(aEdges);
        for (int i = result.Count - 1; i > 0; i--)
        {
            for (int n = i - 1; n >= 0; n--)
            {
                if (result[i].v1 == result[n].v2 && result[i].v2 == result[n].v1)
                {
                    // shared edge so remove both
                    result.RemoveAt(i);
                    result.RemoveAt(n);
                    i--;
                    break;
                }
            }
        }
        return result;
    }
    
    public static List<Edge> SortEdges(this List<Edge> aEdges)
    {
        List<Edge> result = new List<Edge>(aEdges);
        for (int i = 0; i < result.Count - 2; i++)
        {
            Edge E = result[i];
            for(int n = i + 1; n < result.Count; n++)
            {
                Edge a = result[n];
                if (E.v2 == a.v1)
                {
                    // in this case they are already in order so just continoue with the next one
                    if (n == i+1)
                        break;
                    // if we found a match, swap them with the next one after "i"
                    result[n] = result[i + 1];
                    result[i + 1] = a;
                    break;
                }
            }
        }
        return result;
    }
}

You can simply use it like that:

var boundary = EdgeHelpers.GetEdges(mesh.triangles).FindBoundary();

Now you have all boundary edges in a list.

edit
They are probably not sorted in any way. To get a a continuous path you just have to match “v2” of an edge with “v1” of another edge. I just added the “SortEdges” extension method. So you can simply do:

var boundaryPath = EdgeHelpers.GetEdges(mesh.triangles).FindBoundary().SortEdges();

To get the actual vertices you have to iterate through the edges and just use v1 value of each edge as index into the vertices array.
If you need to support a mesh without shared edges you could simply “preprocess” the mesh to create a indices list with only shared indices. Which vertices are shared has to be determined by looking at the vertex positions.

Hey,

This code has been very helpful, but I think there is a bug in the SortEdges() method. In order to sort the edges properly you need to feed the mesh vertex array into the method and replace the line:

if (E.v2 == a.v1)

with

if (vertex_array[E.v2] == vertex_array[a.v1])

This is because we need to make sure that the vertices are sorted, not the indices.

this does not seem to get the perimeter alt text