I have an array of four 3D points (Vector3[]
), which are all on the same plane. I'm using Unity
with C#
and the purpose is to use 2D Traingulator
for these 4 points.
using UnityEngine;
Vector3[] vertices3D = new Vector3[] {
new Vector3(0,10,0),
new Vector3(50,20,0),
new Vector3(0,10,30),
new Vector3(50,20,30)
};
Since the Triangulator is only for 2D and all the points are on the same plane, the approach should be to calculate the basis vectors or the principal components of the plane, but I couldn't find how. I want to reduce the dimensionality of the points to 2D to use Triangulator
for them in a way that the resulting triangles lie on the plane.
So my desired outputs are only the triangles.
The source code for Triangulator
is in here, and my goal is to create a mesh for the given points, but as you see the following sample code, the input points of the triangulator should be in 2D:
using UnityEngine;
public class PolygonTester : MonoBehaviour {
void Start () {
// Create Vector2 vertices
Vector2[] vertices2D = new Vector2[] {
new Vector2(0,0),
new Vector2(0,50),
new Vector2(50,50),
new Vector2(50,100)
};
// Use the triangulator to get indices for creating triangles
Triangulator tr = new Triangulator(vertices2D);
int[] indices = tr.Triangulate();
// Create the Vector3 vertices
Vector3[] vertices = new Vector3[vertices2D.Length];
for (int i=0; i<vertices.Length; i++) {
vertices[i] = new Vector3(vertices2D[i].x, vertices2D[i].y, 0);
}
// Create the mesh
Mesh msh = new Mesh();
msh.vertices = vertices;
msh.triangles = indices;
msh.RecalculateNormals();
msh.RecalculateBounds();
// Set up game object with mesh;
gameObject.AddComponent(typeof(MeshRenderer));
MeshFilter filter = gameObject.AddComponent(typeof(MeshFilter)) as MeshFilter;
filter.mesh = msh;
}
}
Solution 1 - Trivial
If the quad is convex and you know the ordering of the vertices, use indices = new double[6]{0,1,2,0,2,3};
Solution 2 - Triangulate by hand
If the quad is convex but you are unsure about the ordering, test the orientation and adjust the indices.
edge1 = vertices3D[1] - vertices3D[0];
edge2 = vertices3D[2] - vertices3D[0];
edge3 = vertices3D[3] - vertices3D[0];
normal12 = Vector3.Cross(edge1, edge2);
normal23 = Vector3.Cross(edge2, edge3);
if (Vector3.Dot(normal12, normal23) > 0)
indices = new double[6]{0,1,2,0,2,3};
else
indices = new double[6]{0,1,3,0,3,2};
Solution 3 - Using Triangulator
If the quad is not convex or you really have to use the library Triangulator, transform all vertices such that they are on the XY plane with the first vertex being at (0,0,0)
.
edge1 = vertices3D[1] - vertices3D[0];
edge2 = vertices3D[2] - vertices3D[0];
normal = Vector3.Cross(edge1, edge2).normalized;
rotation = Quaternion.FromToRotation(normal, new Vector3(0,0,1));
Vector2[] vertices2D = new Vector2[vertices3D.Length];
for (int i=0; i<vertices3D.Length; i++) {
rotatedVertex = rotation * (vertices3D[i]-vertices3D[0]);
vertices2D[i] = new Vector2(rotatedVertex.x, rotatedVertex.y);
}
I do not recommend using Triangulator for only 4 points forming a wall. However, it should become handy for complex polygons and for non-convex shapes.