- Home /
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[i].x;
}
}
What kind of mesh do we talk about? A 3d mesh or a 2d mesh? So do you want to find the projected silhouette of a 3d mesh (like you would when calculating a shadow volume) or about a flat 2d mesh which consists of several coplanar trianges and you just want to find the bounding edges?
Do you have a screenshot / drawing of your mesh?
Thanks for the reply, The mesh is 2d and am in need to find the bounding edges. I would show an image but the mesh is dynamic and constantly changing.
Answer by Bunny83 · Aug 01, 2015 at 02:08 PM
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.
Thanks, but i am getting a error: I had to add System.Collections.Generic to the edge helpers script to allow the list class but now in my other script using var boundaryPath = EdgeHelpers.GetEdges(mesh.triangles).FindBoundary().SortEdges();
i am getting this error.
error CS1061: Type `System.Collections.Generic.List<EdgeHelpers.Edge>' does not contain a definition for `FindBoundary' and no extension method `FindBoundary' of type `System.Collections.Generic.List<EdgeHelpers.Edge>' could be found (are you missing a using directive or an assembly reference?)
semed to fix the error by adding:
public static List<Edge> FindBoundary(this List<Edge> aEdges)
ins$$anonymous$$d of:
public static List<Edge> FindBoundary(List<Edge> aEdges)
Could you please explain more about "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.", Thanks for all your help i really appreciate it.
@Chris12345: Hmm, that's strange ^^ i thought i have just copy&pasted the whole class from my project and i have the "this" in my code ^^. I've edited the answer.
Well, the indices from the triangle array define which vertices are used to create a triangle. An "Edge" represents always 2 vertices. To get the position of a vertex you just have to use "v1" as index into the vertices array:
Vector3[] vertices = mesh.vertices;
List<Edge> boundaryPath = EdgeHelpers.GetEdges(mesh.triangles).FindBoundary().SortEdges();
for(int i = 0; i < boundaryPath.Count; i++)
{
Vector3 pos = vertices[ boundaryPath[i].v1 ];
// do something with pos
}
Since the resulting edges should form a closed path we can ignore "v2" (the second point of each edge) since the second point of the first edge is the first point of the second edge. The second point of the second edge is the first point of the third edge and so on. The last edge should connect back to the first one since it's a closed path.
Thanks for all the help, but i had to fix
List<Edge> boundaryPath EdgeHelpers.GetEdges(mesh.triangles).FindBoundary().SortEdges();
Change to:
var boundaryPath EdgeHelpers.GetEdges(mesh.triangles).FindBoundary().SortEdges();
Also I am getting a error, my code requires a vector3[] and am getting the following:
error CS0029: Cannot implicitly convert type `UnityEngine.Vector3' to `UnityEngine.Vector3[]
Line: Vector3[] pos = vertices[boundaryPath[i].v1];
It will not let me set pos to a vector3[]
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Illuminating a 3D object's edges OnMouseOver (script in c#)? 1 Answer
Flip over an object (smooth transition) 3 Answers