# How to make a hole of N vertices in the face of a Cube

I want to make a hole of N vertices in the face of a Cube, I'm adding just four like a square in this post to be simple, but eventually I want to be able to add as many as I want and maybe in a circular shape, but I can't make the triangle part right. The code to reproduce my steps are bellow.

1- After Raycasting into a Cube, to get the mesh I do this (don't forget to add a MeshCollider to the Cube):

if (Input.GetMouseButtonUp(0))
{
RaycastHit hit;

if (!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
{
return;
}

var meshCollider = hit.collider as MeshCollider;
var mesh = meshCollider.sharedMesh;

Mesh meshChanged = Instantiate(mesh);
meshChanged.name = "Changed Cube";
}


2- Them I get the vertices, normals, triangles and uv:

Vector3[] vertices = mesh.vertices.ToArray();
Vector3[] normals = mesh.normals.ToArray().ToArray();
int[] triangles = mesh.triangles.ToArray();
Vector2[] uvs = mesh.uv.ToArray();


3- I get the position of the hit.point, in the Cube local space and the normal of the triangle that the hit.point hitted.

Vector3 hitPositionOnMesh = hit.transform.InverseTransformPoint(hit.point);
Vector3 hittedTriangleNormal = CalculateNormalOfTriangle(normals, triangles, hit.triangleIndex);


3.a- CalculateNormalOfTriangle Function

private static Vector3 CalculateNormalOfTriangle(Vector3[] normals, int[] triangles, int triangleIndex)
{
var n0 = normals[triangles[triangleIndex * 3 + 0]];
var n1 = normals[triangles[triangleIndex * 3 + 1]];
var n2 = normals[triangles[triangleIndex * 3 + 2]];
return ((n0 + n1 + n2) / 3);
}


4- To be simple, I add only four vertices and add a distance (0.1f) to them.

Vector3 hitPositionOnMesh1 = new Vector3();
Vector3 hitPositionOnMesh2 = new Vector3();
Vector3 hitPositionOnMesh3 = new Vector3();
Vector3 hitPositionOnMesh4 = new Vector3();

Vector3 hitP = hit.transform.position;

Vector3 point1 = new Vector3(hitP.x + 0.1f, hitP.y + 0.1f, hitP.z);
Vector3 point2 = new Vector3(hitP.x - 0.1f, hitP.y + 0.1f, hitP.z);
Vector3 point3 = new Vector3(hitP.x - 0.1f, hitP.y - 0.1f, hitP.z);
Vector3 point4 = new Vector3(hitP.x + 0.1f, hitP.y - 0.1f, hitP.z);

hitPositionOnMesh1 = point1;
hitPositionOnMesh2 = point2;
hitPositionOnMesh3 = point3;
hitPositionOnMesh4 = point4;


5- I create the outside vertices and inside vertices lists.

List<Vector3> OutsideVerticesOfFace = new List<Vector3>();
for (int i = 0; i < normals.Length; i++)
{
if (normals[i] == hittedTriangleNormal)
{
}
}

List<Vector3> InsideVerticesOfFace = new List<Vector3>
{
hitPositionOnMesh1,
hitPositionOnMesh2,
hitPositionOnMesh3,
hitPositionOnMesh4
};


6- I remove the triangles from face of the Cube that the hit.point hitted.

triangles = RemoveFace(hittedTriangleNormal, triangles, normals);


6.a- RemoveFace Function

private static int[] RemoveFace(Vector3 normalToCompare, int[] triangles, Vector3[] normals)
{
List<int> trianglesToRemove = new List<int>();

for (int i = 0; i < triangles.Length; i += 3)
{
var p0 = normals[triangles[i + 0]];
var p1 = normals[triangles[i + 1]];
var p2 = normals[triangles[i + 2]];

if (((p0 + p1 + p2) / 3) == normalToCompare)
{
}
}

int[] _triangles = RemoveTriangles(triangles, trianglesToRemove.ToArray());
return _triangles;
}


6.b- RemoveTriangles Function

private static int[] RemoveTriangles(int[] triangles, int[] trianglesToRemove)
{
List<int> tmpT = new List<int>(triangles.ToList());
for (int i = 0; i < triangles.ToList().Count; i += 3)
{
bool v1 = (triangles.ToList()[i + 0] == trianglesToRemove[0]);
bool v2 = (triangles.ToList()[i + 1] == trianglesToRemove[1]);
bool v3 = (triangles.ToList()[i + 2] == trianglesToRemove[2]);

if ((v1 && v2 && v3))
{
tmpT.RemoveRange(i, trianglesToRemove.Length);
}
}
triangles = tmpT.ToArray();

return triangles;
}


7- I create a new list of vertices and change the normals and uvs lists.

List<Vector3> newVertices = new List<Vector3>(vertices.ToArray());

normals = (new List<Vector3>(normals)
{
hittedTriangleNormal,
hittedTriangleNormal,
hittedTriangleNormal,
hittedTriangleNormal,
}).ToArray();

uvs = (new List<Vector2>(uvs)
{
new Vector2(hitPositionOnMesh1.x, hitPositionOnMesh1.z),
new Vector2(hitPositionOnMesh2.x, hitPositionOnMesh2.z),
new Vector2(hitPositionOnMesh3.x, hitPositionOnMesh3.z),
new Vector2(hitPositionOnMesh4.x, hitPositionOnMesh4.z),
}).ToArray();


8- Now, this is the problem, this is where it isn't working, the part of making the new triangles.

List<int> outsideTriangles;
outsideTriangles = MakeOuterTriangles(_vertices.ToArray(), InsideVerticesOfFace, OutsideVerticesOfFace);
List<int> newTriangles = triangles.ToList();
triangles = newTriangles.ToArray();
meshChanged.vertices = newVertices.ToArray();
meshChanged.normals = normals;
meshChanged.triangles = triangles;
meshChanged.uv = uvs;


8.a- I tried Trigonometry, using cosine law, c = sqrt(a^2 + b^2 - 2ab * cos(C)). c being the distance from the inside vertice (0) with second outside vertice (1), a being the distance from the outside vertice (0) with outside vertice (1) and b being the distance from the inside vertice (0) with outside vertice (0). C being the angle between inside vertice (0) and outside vertice (0), like in the image:

Firstly I rearrange the outsideVertice list, because for some reason, Unity create vertices in a weird "0, 1, 3, 2". So I rearrange it so that the last item becames the third, and the second item becames the last, "0, 1, 2 (last), 3 (third)" and I also add the first item in the last position, so that it make a loop.

Secondly I sorted the newOutside list by distance the from the insideVertice list, so that outsideVertices[0] is always the right item.

*I tried to change the variables parameters to see if I misplaced something, it didn't work at all, in the best case, the triangles of the face where deleted or there where no triangles at all.

public static List<int> MakeOuterTriangles(Vector3[] vertices, List<Vector3> insideVertices, List<Vector3> outsideVertices)
{
List<int> newTriangles = new List<int>();
List<Vector3> newOutside = new List<Vector3>() { outsideVertices[0], outsideVertices[1], outsideVertices[outsideVertices.Count - 1], outsideVertices[2], outsideVertices[0]};
for (int i = 0; i < insideVertices.Count - 1; i++)
{
newOutside = newOutside.OrderBy(x => Vector3.Distance(x, insideVertices[i])).ToList();
float side_a = Vector3.Distance(outsideVertices[0], outsideVertices[1]);
float side_b = Vector3.Distance(outsideVertices[0], insideVertices[i]);
float angle = Vector3.Angle(outsideVertices[0], insideVertices[i]);
float side_c = Mathf.Sqrt(Mathf.Pow(side_a, 2) + Mathf.Pow(side_b, 2) - 2 * (side_a * side_b) * Mathf.Cos(angle));
if (side_c == Vector3.Distance(outsideVertices[1], insideVertices[i]))
{
}
}
return newTriangles;
}


8.b- I tried to adapt this code link1, from the video link2, the code is bellow, but I assume that the number of vertice in the inside has to be the same as the outside. So it didn't work also.

public static List<int> MakeOuterTriangles(Vector3[] vertices, List<Vector3> insideVertices, List<Vector3> outsideVertices)
{
List<int> newTriangles = new List<int>();
int sides = insideVertices.Count + outsideVertices.Count/2;
for(int i = 0; i<sides;i++)
{
int outerIndex = i;
int innerIndex = i+sides;

}
return newTriangles;
}


8.c- This my new try (code bellow), I get this image result:

List<int> outsideTriangles = new List<int>();
for (int i = 0; i < OutsideVerticesOfFace.Count - 1; i++)
{
if (i == OutsideVerticesOfFace.Count - 1)
{
InsideVerticesOfFace = InsideVerticesOfFace.OrderBy(x => Vector3.Distance(x, OutsideVerticesOfFace[i])).ToList();

float distanceV = Mathf.Abs(Vector3.Distance(OutsideVerticesOfFace[0], OutsideVerticesOfFace[i]));

if (distance == 1)
{
}
}
else if (i != OutsideVerticesOfFace.Count - 1)
{
InsideVerticesOfFace = InsideVerticesOfFace.OrderBy(x => Vector3.Distance(x, OutsideVerticesOfFace[i])).ToList();

float distanceV = Mathf.Abs(Vector3.Distance(OutsideVerticesOfFace[i + 1], OutsideVerticesOfFace[i]));

if (distanceV == 1)
{
}
}
}


8.d- (Almost success) First I have made a mistake, in the 4 step, I thought that I was using that piece of code, but I wasn't and I only notice it later, the rest of the could is the same thing. Here is the code that I was actually using.

Vector3 pivot = hit.transform.InverseTransformPoint(hit.transform.position);
Vector3 point = hitPositionOnMesh;
Vector3 dir = point - pivot;

dir = Quaternion.Euler(new Vector3(180, 0, 0)) * dir;
point = dir + pivot;

Vector3 point1 = new Vector3(point.x + distance, point.y + distance, point.z);
Vector3 point2 = new Vector3(point.x - distance, point.y + distance, point.z);
Vector3 point3 = new Vector3(point.x + distance, point.y - distance, point.z);
Vector3 point4 = new Vector3(point.x - distance, point.y - distance, point.z);

dir = point1 - pivot;
dir = Quaternion.Euler(new Vector3(-180, 0, 0)) * dir;
point1 = dir + pivot;

dir = point2 - pivot;
dir = Quaternion.Euler(new Vector3(-180, 0, 0)) * dir;
point2 = dir + pivot;

dir = point3 - pivot;
dir = Quaternion.Euler(new Vector3(-180, 0, 0)) * dir;
point3 = dir + pivot;

dir = point4 - pivot;
dir = Quaternion.Euler(new Vector3(-180, 0, 0)) * dir;
point4 = dir + pivot;

hitPositionOnMesh1 = point1;
hitPositionOnMesh2 = point2;
hitPositionOnMesh3 = point3;
hitPositionOnMesh4 = point4;


I was planning to use this code so that no matter what face the Raycast hitted, I would only need to rotate the face to match the positive z axis, and then I would only need to add the distance from the points and rotate it back. But currently it only works if you hit the negative z axis of the Cube, I don't know if it would work with other faces, I didn't implement it to them yet. And since my question isn't about only 4 vertices, I will not post 8.d as the answer.

public static List<int> MakeOuterTriangles(Vector3[] vertices, List<Vector3> insideVertices, List<Vector3> outsideVertices)
{
List<int> newTriangles = new List<int>();

for (int i = 0; i < OutsideVerticesOfFace.Count; i++)
{
List<Vector3> newOutsideTriangles = OutsideVerticesOfFace.Skip(i).Concat(OutsideVerticesOfFace.Take(i)).ToList();
List<Vector3> newInsideTriangles = InsideVerticesOfFace.Skip(i).Concat(InsideVerticesOfFace.Take(i)).ToList();

if (i % 2 == 0)
{
if (i % 3 == 0)
{
}
else if(i % 3 == 1)
{
}
else
{
}
}
else if (i % 2 == 1)
{
if (i % 3 == 0)
{
}
else if (i % 3 == 1)
{
}
}
}

for (int i = 0; i < OutsideVerticesOfFace.Count; i++)
{
List<Vector3> newOutsideTriangles = OutsideVerticesOfFace.Skip(i).Concat(OutsideVerticesOfFace.Take(i)).ToList();
List<Vector3> newInsideTriangles = InsideVerticesOfFace.Skip(i).Concat(InsideVerticesOfFace.Take(i)).ToList();

if (i % 2 == 0)
{
if (i % 3 == 0)
{
}
else
{
}
}
else if (i % 2 == 1)
{
if (i % 3 == 0)
{
}
else if (i % 3 == 1)
{