/// <summary> /// Add a set of points to a face and retriangulate. Points are added to the nearest edge. /// </summary> /// <param name="mesh">The source mesh.</param> /// <param name="face">The face to append points to.</param> /// <param name="points">Points to added to the face.</param> /// <returns>The face created by appending the points.</returns> public static Face AppendVerticesToFace(this ProBuilderMesh mesh, Face face, Vector3[] points) { if (mesh == null) { throw new ArgumentNullException("mesh"); } if (face == null) { throw new ArgumentNullException("face"); } if (points == null) { throw new ArgumentNullException("points"); } List <Vertex> vertices = mesh.GetVertices().ToList(); List <Face> faces = new List <Face>(mesh.facesInternal); Dictionary <int, int> lookup = mesh.sharedVertexLookup; Dictionary <int, int> lookupUV = null; if (mesh.sharedTextures != null) { lookupUV = new Dictionary <int, int>(); SharedVertex.GetSharedVertexLookup(mesh.sharedTextures, lookupUV); } List <Edge> wound = WingedEdge.SortEdgesByAdjacency(face); List <Vertex> n_vertices = new List <Vertex>(); List <int> n_shared = new List <int>(); List <int> n_sharedUV = lookupUV != null ? new List <int>() : null; for (int i = 0; i < wound.Count; i++) { n_vertices.Add(vertices[wound[i].a]); n_shared.Add(lookup[wound[i].a]); if (lookupUV != null) { int uv; if (lookupUV.TryGetValue(wound[i].a, out uv)) { n_sharedUV.Add(uv); } else { n_sharedUV.Add(-1); } } } // now insert the new points on the nearest edge for (int i = 0; i < points.Length; i++) { int index = -1; float best = Mathf.Infinity; Vector3 p = points[i]; int vc = n_vertices.Count; for (int n = 0; n < vc; n++) { Vector3 v = n_vertices[n].position; Vector3 w = n_vertices[(n + 1) % vc].position; float dist = Math.DistancePointLineSegment(p, v, w); if (dist < best) { best = dist; index = n; } } Vertex left = n_vertices[index], right = n_vertices[(index + 1) % vc]; float x = (p - left.position).sqrMagnitude; float y = (p - right.position).sqrMagnitude; Vertex insert = Vertex.Mix(left, right, x / (x + y)); n_vertices.Insert((index + 1) % vc, insert); n_shared.Insert((index + 1) % vc, -1); if (n_sharedUV != null) { n_sharedUV.Insert((index + 1) % vc, -1); } } List <int> triangles; try { Triangulation.TriangulateVertices(n_vertices, out triangles, false); } catch { Debug.Log("Failed triangulating face after appending vertices."); return(null); } FaceRebuildData data = new FaceRebuildData(); data.face = new Face(triangles.ToArray(), face.submeshIndex, new AutoUnwrapSettings(face.uv), face.smoothingGroup, face.textureGroup, -1, face.manualUV); data.vertices = n_vertices; data.sharedIndexes = n_shared; data.sharedIndexesUV = n_sharedUV; FaceRebuildData.Apply(new List <FaceRebuildData>() { data }, vertices, faces, lookup, lookupUV); var newFace = data.face; mesh.SetVertices(vertices); mesh.faces = faces; mesh.SetSharedVertices(lookup); mesh.SetSharedTextures(lookupUV); // check old normal and make sure this new face is pointing the same direction Vector3 oldNrm = Math.Normal(mesh, face); Vector3 newNrm = Math.Normal(mesh, newFace); if (Vector3.Dot(oldNrm, newNrm) < 0) { newFace.Reverse(); } mesh.DeleteFace(face); return(newFace); }