/** * This method assumes that the split selection edges share a common face and have already been sanity checked. Will return * the variables necessary to compose a new face from the split, or null if the split is invalid. */ private static bool SplitFace_Internal(SplitSelection splitSelection, out pb_Face[] splitFaces, out Vector3[][] splitVertices, out int[][] splitSharedIndices) { splitFaces = null; splitVertices = null; splitSharedIndices = null; pb_Object pb = splitSelection.pb; // we'll be using this a lot pb_Face face = splitSelection.face; // likewise int[] indices = face.distinctIndices; pb_IntArray[] sharedIndices = pb.sharedIndices; int[] sharedIndex = new int[indices.Length]; for(int i = 0; i < indices.Length; i++) sharedIndex[i] = sharedIndices.IndexOf(indices[i]); // First order of business is to translate the face to 2D plane. Vector3[] verts = pb.GetVertices(face.distinctIndices); Vector3 projAxis = pb_Math.GetProjectionAxis( pb_Math.Normal(pb.GetVertices(face.indices))).ToVector3(); Vector2[] plane = pb_Math.VerticesTo2DPoints(verts, projAxis); // Split points Vector3 splitPointA_3d = splitSelection.pointA; Vector3 splitPointB_3d = splitSelection.pointB; Vector2 splitPointA_2d = pb_Math.VerticesTo2DPoints( new Vector3[1] { splitPointA_3d }, projAxis )[0]; Vector2 splitPointB_2d = pb_Math.VerticesTo2DPoints( new Vector3[1] { splitPointB_3d }, projAxis )[0]; List<Vector3> v_polyA = new List<Vector3>(); // point in object space List<Vector2> v_polyA_2d = new List<Vector2>(); // point in 2d space - used to triangulate List<Vector3> v_polyB = new List<Vector3>(); // point in object space List<Vector2> v_polyB_2d = new List<Vector2>(); // point in 2d space - used to triangulate List<int> i_polyA = new List<int>(); // sharedIndices array index List<int> i_polyB = new List<int>(); // sharedIndices array index List<int> nedgeA = new List<int>(); List<int> nedgeB = new List<int>(); // Sort points into two separate polygons for(int i = 0; i < indices.Length; i++) { // is this point (a) a vertex to split or (b) on the negative or positive side of this split line if( (splitSelection.aIsVertex && splitSelection.indexA == indices[i]) || (splitSelection.bIsVertex && splitSelection.indexB == indices[i]) ) { v_polyA.Add( verts[i] ); v_polyB.Add( verts[i] ); v_polyA_2d.Add( plane[i] ); v_polyB_2d.Add( plane[i] ); i_polyA.Add( sharedIndex[i] ); i_polyB.Add( sharedIndex[i] ); } else { // split points across the division line Vector2 perp = pb_Math.Perpendicular(splitPointB_2d, splitPointA_2d); Vector2 origin = (splitPointA_2d + splitPointB_2d) / 2f; if( Vector2.Dot(perp, plane[i]-origin) > 0 ) { v_polyA.Add(verts[i]); v_polyA_2d.Add(plane[i]); i_polyA.Add(sharedIndex[i]); } else { v_polyB.Add(verts[i]); v_polyB_2d.Add(plane[i]); i_polyB.Add(sharedIndex[i]); } } } if(!splitSelection.aIsVertex) { v_polyA.Add( splitPointA_3d ); v_polyA_2d.Add( splitPointA_2d ); v_polyB.Add( splitPointA_3d ); v_polyB_2d.Add( splitPointA_2d ); i_polyA.Add(-1); i_polyB.Add(-1); // neg 1 because it's a new vertex point nedgeA.Add(v_polyA.Count); nedgeB.Add(v_polyB.Count); } if(!splitSelection.bIsVertex) { v_polyA.Add( splitPointB_3d ); v_polyA_2d.Add( splitPointB_2d ); v_polyB.Add( splitPointB_3d ); v_polyB_2d.Add( splitPointB_2d ); i_polyA.Add(-1); i_polyB.Add(-1); // neg 1 because it's a new vertex point nedgeA.Add(v_polyA.Count); nedgeB.Add(v_polyB.Count); } if(v_polyA_2d.Count < 3 || v_polyB_2d.Count < 3) { splitFaces = null; splitVertices = null; splitSharedIndices = null; return false; } // triangulate new polygons int[] t_polyA = Delauney.Triangulate(v_polyA_2d).ToIntArray(); int[] t_polyB = Delauney.Triangulate(v_polyB_2d).ToIntArray(); if(t_polyA.Length < 3 || t_polyB.Length < 3) return false; // figure out the face normals for the new faces and check to make sure they match the original face Vector2[] pln = pb_Math.VerticesTo2DPoints( pb.GetVertices(face.indices), projAxis ); Vector3 nrm = Vector3.Cross( pln[2] - pln[0], pln[1] - pln[0]); Vector3 nrmA = Vector3.Cross( v_polyA_2d[ t_polyA[2] ]-v_polyA_2d[ t_polyA[0] ], v_polyA_2d[ t_polyA[1] ]-v_polyA_2d[ t_polyA[0] ] ); Vector3 nrmB = Vector3.Cross( v_polyB_2d[ t_polyB[2] ]-v_polyB_2d[ t_polyB[0] ], v_polyB_2d[ t_polyB[1] ]-v_polyB_2d[ t_polyB[0] ] ); if(Vector3.Dot(nrm, nrmA) < 0) System.Array.Reverse(t_polyA); if(Vector3.Dot(nrm, nrmB) < 0) System.Array.Reverse(t_polyB); // triangles, material, pb_UV, smoothing group, shared index pb_Face faceA = new pb_Face( t_polyA, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.color); pb_Face faceB = new pb_Face( t_polyB, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.color); splitFaces = new pb_Face[2] { faceA, faceB }; splitVertices = new Vector3[2][] { v_polyA.ToArray(), v_polyB.ToArray() }; splitSharedIndices = new int[2][] { i_polyA.ToArray(), i_polyB.ToArray() }; return true; }
/** * This method assumes that the split selection edges share a common face and have already been sanity checked. Will return * the variables necessary to compose a new face from the split, or null if the split is invalid. */ private static bool SplitFace_Internal(SplitSelection splitSelection, out pb_Face[] splitFaces, out Vector3[][] splitVertices, out Color[][] splitColors, out Vector2[][] splitUVs, out int[][] splitSharedIndices) { splitFaces = null; splitVertices = null; splitColors = null; splitUVs = null; splitSharedIndices = null; pb_Object pb = splitSelection.pb; // we'll be using this a lot pb_Face face = splitSelection.face; // likewise int[] indices = face.distinctIndices; pb_IntArray[] sharedIndices = pb.sharedIndices; int[] sharedIndex = new int[indices.Length]; for (int i = 0; i < indices.Length; i++) { sharedIndex[i] = sharedIndices.IndexOf(indices[i]); } // First order of business is to translate the face to 2D plane. Vector3[] verts = pb.GetVertices(face.distinctIndices); Color[] colors = pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices); Vector2[] uvs = pb.GetUVs(face.distinctIndices); Vector3 projAxis = pb_Math.ProjectionAxisToVector(pb_Math.VectorToProjectionAxis(pb_Math.Normal(pb, face))); Vector2[] plane = pb_Math.PlanarProject(verts, projAxis); // Split points Vector3 splitPointA_3d = splitSelection.pointA; Vector3 splitPointB_3d = splitSelection.pointB; Vector2 splitPointA_uv = splitSelection.aIsVertex ? pb.uv[splitSelection.indexA[0]] : (pb.uv[splitSelection.indexA[0]] + pb.uv[splitSelection.indexA[1]]) / 2f; Vector2 splitPointB_uv = splitSelection.bIsVertex ? pb.uv[splitSelection.indexB[0]] : (pb.uv[splitSelection.indexB[0]] + pb.uv[splitSelection.indexB[1]]) / 2f; Vector2 splitPointA_2d = pb_Math.PlanarProject(new Vector3[1] { splitPointA_3d }, projAxis)[0]; Vector2 splitPointB_2d = pb_Math.PlanarProject(new Vector3[1] { splitPointB_3d }, projAxis)[0]; List <Vector3> v_polyA = new List <Vector3>(); // point in object space List <Vector3> v_polyB = new List <Vector3>(); // point in object space List <Color> c_polyA = new List <Color>(); List <Color> c_polyB = new List <Color>(); List <Vector2> v_polyB_2d = new List <Vector2>(); // point in 2d space - used to triangulate List <Vector2> v_polyA_2d = new List <Vector2>(); // point in 2d space - used to triangulate List <Vector2> u_polyA = new List <Vector2>(); List <Vector2> u_polyB = new List <Vector2>(); List <int> i_polyA = new List <int>(); // sharedIndices array index List <int> i_polyB = new List <int>(); // sharedIndices array index List <int> nedgeA = new List <int>(); List <int> nedgeB = new List <int>(); // Sort points into two separate polygons for (int i = 0; i < indices.Length; i++) { // is this point (a) a vertex to split or (b) on the negative or positive side of this split line if ((splitSelection.aIsVertex && splitSelection.indexA[0] == indices[i]) || (splitSelection.bIsVertex && splitSelection.indexB[0] == indices[i])) { v_polyA.Add(verts[i]); v_polyB.Add(verts[i]); u_polyA.Add(uvs[i]); u_polyB.Add(uvs[i]); v_polyA_2d.Add(plane[i]); v_polyB_2d.Add(plane[i]); i_polyA.Add(sharedIndex[i]); i_polyB.Add(sharedIndex[i]); c_polyA.Add(colors[i]); c_polyB.Add(colors[i]); } else { // split points across the division line Vector2 perp = pb_Math.Perpendicular(splitPointB_2d, splitPointA_2d); Vector2 origin = (splitPointA_2d + splitPointB_2d) / 2f; if (Vector2.Dot(perp, plane[i] - origin) > 0) { v_polyA.Add(verts[i]); v_polyA_2d.Add(plane[i]); u_polyA.Add(uvs[i]); i_polyA.Add(sharedIndex[i]); c_polyA.Add(colors[i]); } else { v_polyB.Add(verts[i]); v_polyB_2d.Add(plane[i]); u_polyB.Add(uvs[i]); i_polyB.Add(sharedIndex[i]); c_polyB.Add(colors[i]); } } } if (!splitSelection.aIsVertex) { v_polyA.Add(splitPointA_3d); v_polyA_2d.Add(splitPointA_2d); u_polyA.Add(splitPointA_uv); i_polyA.Add(-1); c_polyA.Add(splitSelection.colorA); v_polyB.Add(splitPointA_3d); v_polyB_2d.Add(splitPointA_2d); u_polyB.Add(splitPointA_uv); i_polyB.Add(-1); // neg 1 because it's a new vertex point c_polyB.Add(splitSelection.colorA); nedgeA.Add(v_polyA.Count); nedgeB.Add(v_polyB.Count); } // PLACE if (!splitSelection.bIsVertex) { v_polyA.Add(splitPointB_3d); v_polyA_2d.Add(splitPointB_2d); u_polyA.Add(splitPointB_uv); i_polyA.Add(-1); c_polyB.Add(splitSelection.colorB); v_polyB.Add(splitPointB_3d); v_polyB_2d.Add(splitPointB_2d); u_polyB.Add(splitPointB_uv); i_polyB.Add(-1); // neg 1 because it's a new vertex point c_polyB.Add(splitSelection.colorB); nedgeA.Add(v_polyA.Count); nedgeB.Add(v_polyB.Count); } if (v_polyA_2d.Count < 3 || v_polyB_2d.Count < 3) { splitFaces = null; splitVertices = null; splitSharedIndices = null; return(false); } // triangulate new polygons int[] t_polyA = Delaunay.Triangulate(v_polyA_2d).ToIntArray(); int[] t_polyB = Delaunay.Triangulate(v_polyB_2d).ToIntArray(); if (t_polyA.Length < 3 || t_polyB.Length < 3) { return(false); } // figure out the face normals for the new faces and check to make sure they match the original face Vector2[] pln = pb_Math.PlanarProject(pb.GetVertices(face.indices), projAxis); Vector3 nrm = Vector3.Cross(pln[2] - pln[0], pln[1] - pln[0]); Vector3 nrmA = Vector3.Cross(v_polyA_2d[t_polyA[2]] - v_polyA_2d[t_polyA[0]], v_polyA_2d[t_polyA[1]] - v_polyA_2d[t_polyA[0]]); Vector3 nrmB = Vector3.Cross(v_polyB_2d[t_polyB[2]] - v_polyB_2d[t_polyB[0]], v_polyB_2d[t_polyB[1]] - v_polyB_2d[t_polyB[0]]); if (Vector3.Dot(nrm, nrmA) < 0) { System.Array.Reverse(t_polyA); } if (Vector3.Dot(nrm, nrmB) < 0) { System.Array.Reverse(t_polyB); } // triangles, material, pb_UV, smoothing group, shared index pb_Face faceA = new pb_Face(t_polyA, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.manualUV); pb_Face faceB = new pb_Face(t_polyB, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.manualUV); splitFaces = new pb_Face[2] { faceA, faceB }; splitVertices = new Vector3[2][] { v_polyA.ToArray(), v_polyB.ToArray() }; splitColors = new Color[2][] { c_polyA.ToArray(), c_polyB.ToArray() }; splitUVs = new Vector2[2][] { u_polyA.ToArray(), u_polyB.ToArray() }; splitSharedIndices = new int[2][] { i_polyA.ToArray(), i_polyB.ToArray() }; return(true); }