/**
	 *	\brief
	 *	param sharedIndex An optional array that sets the new pb_Face indices to use the _sharedIndices array.
	 *	\returns The newly appended pb_Face.
	 */
	public static pb_Face AppendFace(this pb_Object pb, Vector3[] v, pb_Face face)
	{
		int[] shared = new int[v.Length];
		for(int i = 0; i < v.Length; i++)
			shared[i] = -1;
		return pb.AppendFace(v, face, shared);
	}
	public static void Extrude(this pb_Object pb, pb_Face[] faces, float extrudeDistance)
	{
		if(faces == null || faces.Length < 1)
			return;

		pb_IntArray[] sharedIndices = pb.GetSharedIndices();

		Vector3[] localVerts = pb.vertices;
		Vector3[] oNormals = pb.msh.normals;

		pb_Edge[] perimeterEdges = pb.GetPerimeterEdges(faces);

		if(perimeterEdges == null || perimeterEdges.Length < 3)
		{
			Debug.LogWarning("No perimeter edges found.  Try deselecting and reselecting this object and trying again.");
			return;
		}

		pb_Face[] edgeFaces = new pb_Face[perimeterEdges.Length];	// can't assume faces and perimiter edges will be 1:1 - so calculate perimeters then extrace face information
		int[] allEdgeIndices = new int[perimeterEdges.Length * 2];
		int c = 0;
		for(int i = 0; i < perimeterEdges.Length; i++)
		{
			// wtf does this do
			edgeFaces[i] = faces[0];
			foreach(pb_Face face in faces)
				if(face.edges.Contains(perimeterEdges[i]))
					edgeFaces[i] = face;

			allEdgeIndices[c++] = perimeterEdges[i].x;
			allEdgeIndices[c++] = perimeterEdges[i].y;
		}

		List<pb_Edge> extrudedIndices = new List<pb_Edge>();

		/// build out new faces around edges
		for(int i = 0; i < perimeterEdges.Length; i++)
		{
			pb_Edge edge = perimeterEdges[i];
			pb_Face face = edgeFaces[i];

			// Averages the normals using only vertices that are on the edge
			Vector3 xnorm = Vector3.zero;
			Vector3 ynorm = Vector3.zero;

			// don't bother getting vertex normals if not auto-extruding
			if(extrudeDistance > Mathf.Epsilon)
			{
				xnorm = Norm( edge.x, sharedIndices, allEdgeIndices, oNormals );
				ynorm = Norm( edge.y, sharedIndices, allEdgeIndices, oNormals );
			}

			int x_sharedIndex = sharedIndices.IndexOf(edge.x);
			int y_sharedIndex = sharedIndices.IndexOf(edge.y);

			pb_Face newFace = pb.AppendFace(
				new Vector3[4]
				{
					localVerts [ edge.x ],
					localVerts [ edge.y ],
					localVerts [ edge.x ] + xnorm.normalized * extrudeDistance,
					localVerts [ edge.y ] + ynorm.normalized * extrudeDistance
				},
				new pb_Face( 
					new int[6] {0, 1, 2, 1, 3, 2 },			// indices
					face.material,							// material
					new pb_UV(face.uv),						// UV material
					face.smoothingGroup,					// smoothing group
					-1,										// texture group
					-1,										// uv element group
					face.colors[0] ),						// colors
				new int[4] { x_sharedIndex, y_sharedIndex, -1, -1 });

			extrudedIndices.Add(new pb_Edge(x_sharedIndex, newFace.indices[2]));
			extrudedIndices.Add(new pb_Edge(y_sharedIndex, newFace.indices[4]));
		}

		// merge extruded vertex indices with each other
		pb_IntArray[] si = pb.sharedIndices;	// leave the sharedIndices copy alone since we need the un-altered version later
		for(int i = 0; i < extrudedIndices.Count; i++)
		{
			int val = extrudedIndices[i].x;
			for(int n = 0; n < extrudedIndices.Count; n++)
			{
				if(n == i)
					continue;

				if(extrudedIndices[n].x == val)
				{
					pb_IntArrayUtility.MergeSharedIndices(ref si, extrudedIndices[n].y, extrudedIndices[i].y);
					break;
				}
			}
		}

		// Move extruded faces to top
		localVerts = pb.vertices;
		Dictionary<int, int> remappedTexGroups = new Dictionary<int, int>();
		foreach(pb_Face f in faces)
		{
			// Remap texture groups
			if(f.textureGroup > 0)
			{
				if(remappedTexGroups.ContainsKey(f.textureGroup))
				{
					f.textureGroup = remappedTexGroups[f.textureGroup];
				}
				else
				{
					int newTexGroup = pb.UnusedTextureGroup();
					remappedTexGroups.Add(f.textureGroup, newTexGroup);
					f.textureGroup = newTexGroup;
				}
			}

			int[] distinctIndices = f.distinctIndices;

			foreach(int ind in distinctIndices)
			{
				int oldIndex = si.IndexOf(ind);
				for(int i = 0; i < extrudedIndices.Count; i++)
				{
					if(oldIndex == extrudedIndices[i].x)
					{
						pb_IntArrayUtility.MergeSharedIndices(ref si, extrudedIndices[i].y, ind);
						break;
					}
				}
			}
		}

		// this is a separate loop cause the one above this must completely merge all sharedindices prior to 
		// checking the normal averages
		foreach(pb_Face f in faces)
		{
			foreach(int ind in f.distinctIndices)
			{
				Vector3 norm = Norm( ind, si, allEdgeIndices, oNormals );
				localVerts[ind] += norm.normalized * extrudeDistance;
			}
		}

		pb.SetSharedIndices(si);
		pb.SetVertices(localVerts);
		pb.RebuildFaceCaches();
	}
		public static bool Bridge(this pb_Object pb, pb_Edge a, pb_Edge b, bool enforcePerimiterEdgesOnly)
		{
			pb_IntArray[] sharedIndices = pb.GetSharedIndices();

			// Check to see if a face already exists
			if(enforcePerimiterEdgesOnly)
			{
				if( pbMeshUtils.GetConnectedFaces(pb, a).Count > 1 || pbMeshUtils.GetConnectedFaces(pb, b).Count > 1 )
				{
					Debug.LogWarning("Both edges are not on perimeter!  You may turn off this Bridging restriction in Preferences/ProBuilder/Bridge Perimiter Edges Only");
					return false;
				}
			}
			else
			{
				foreach(pb_Face face in pb.faces)
				{
					if(face.edges.IndexOf(a, sharedIndices) >= 0 && face.edges.IndexOf(b, sharedIndices) >= 0)
					{
						Debug.LogWarning("Face already exists between these two edges!");
						return false;
					}
				}
			}

			Vector3[] verts = pb.vertices;
			Vector3[] v;
			int[] s;
			pb_UV uvs = new pb_UV();
			Color32 color = (Color32)Color.white;
			Material mat = pb_Constant.DefaultMaterial;

			// Get material and UV stuff from the first edge face 
			foreach(pb_Face face in pb.faces)
			{
				if(face.edges.Contains(a))	
				{
					uvs = new pb_UV(face.uv);
					mat = face.material;
					color = face.colors[0];
					break;
				}
			}

			// Bridge will form a triangle
			if( a.Contains(b.x, sharedIndices) || a.Contains(b.y, sharedIndices) )
			{
				v = new Vector3[3];
				s = new int[3];

				bool axbx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.x) > -1;
				bool axby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.y) > -1;
				
				bool aybx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.x) > -1;
				bool ayby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.y) > -1;
				
				if(axbx)
				{	
					v[0] = verts[a.x];
					s[0] = sharedIndices.IndexOf(a.x);
					v[1] = verts[a.y];
					s[1] = sharedIndices.IndexOf(a.y);
					v[2] = verts[b.y];
					s[2] = sharedIndices.IndexOf(b.y);
				}
				else
				if(axby)
				{
					v[0] = verts[a.x];
					s[0] = sharedIndices.IndexOf(a.x);
					v[1] = verts[a.y];
					s[1] = sharedIndices.IndexOf(a.y);
					v[2] = verts[b.x];
					s[2] = sharedIndices.IndexOf(b.x);
				}
				else
				if(aybx)
				{
					v[0] = verts[a.y];
					s[0] = sharedIndices.IndexOf(a.y);
					v[1] = verts[a.x];
					s[1] = sharedIndices.IndexOf(a.x);
					v[2] = verts[b.y];
					s[2] = sharedIndices.IndexOf(b.y);
				}
				else
				if(ayby)
				{
					v[0] = verts[a.y];
					s[0] = sharedIndices.IndexOf(a.y);
					v[1] = verts[a.x];
					s[1] = sharedIndices.IndexOf(a.x);
					v[2] = verts[b.x];
					s[2] = sharedIndices.IndexOf(b.x);
				}

				pb.AppendFace(
					v,
					new pb_Face( axbx || axby ? new int[3] {2, 1, 0} : new int[3] {0, 1, 2}, mat, uvs, 0, -1, -1, color ),
					s);

				pb.RebuildFaceCaches();
				pb.Refresh();

				return true;
			}

			// Else, bridge will form a quad

			v = new Vector3[4];
			s = new int[4]; // shared indices index to add to

			v[0] = verts[a.x];
			s[0] = sharedIndices.IndexOf(a.x);
			v[1] = verts[a.y];
			s[1] = sharedIndices.IndexOf(a.y);

			Vector3 nrm = Vector3.Cross( verts[b.x]-verts[a.x], verts[a.y]-verts[a.x] ).normalized;
			Vector2[] planed = pb_Math.VerticesTo2DPoints( new Vector3[4] {verts[a.x], verts[a.y], verts[b.x], verts[b.y] }, nrm );

			Vector2 ipoint = Vector2.zero;
			bool interescts = pb_Math.GetLineSegmentIntersect(planed[0], planed[2], planed[1], planed[3], ref ipoint);

			if(!interescts)
			{
				v[2] = verts[b.x];
				s[2] = sharedIndices.IndexOf(b.x);
				v[3] = verts[b.y];
				s[3] = sharedIndices.IndexOf(b.y);
			}
			else
			{
				v[2] = verts[b.y];
				s[2] = sharedIndices.IndexOf(b.y);
				v[3] = verts[b.x];
				s[3] = sharedIndices.IndexOf(b.x);
			}

			pb.AppendFace(
				v,
				new pb_Face( new int[6] {2, 1, 0, 2, 3, 1 }, mat, uvs, 0, -1, -1, color ),
				s);

			pb.RebuildFaceCaches();

			return true;
		}
	/**
	 *	Edge extrusion override
	 */
	public static pb_Edge[] Extrude(this pb_Object pb, pb_Edge[] edges, float extrudeDistance, bool enforcePerimiterEdgesOnly)
	{
		pb_IntArray[] sharedIndices = pb.sharedIndices;

		List<pb_Edge> validEdges = new List<pb_Edge>();
		List<pb_Face> edgeFaces = new List<pb_Face>();
		
		foreach(pb_Edge e in edges)
		{
			int faceCount = 0;
			pb_Face fa = null;
			foreach(pb_Face f in pb.faces)
			{
				if(f.edges.IndexOf(e, sharedIndices) > -1)
				{
					fa = f;
					if(++faceCount > 1)
						break;
				}

			}

			if(!enforcePerimiterEdgesOnly || faceCount < 2)
			{
				validEdges.Add(e);
				edgeFaces.Add(fa);
			}
		}

		if(validEdges.Count < 1)
			return null;

		Vector3[] localVerts = pb.vertices;
		Vector3[] oNormals = pb.msh.normals;

		int[] allEdgeIndices = new int[validEdges.Count * 2];
		int c = 0;	// har har har
		for(int i = 0; i < validEdges.Count; i++)
		{
			allEdgeIndices[c++] = validEdges[i].x;
			allEdgeIndices[c++] = validEdges[i].y;
		}

		List<pb_Edge> extrudedIndices = new List<pb_Edge>();
		List<pb_Edge> newEdges = new List<pb_Edge>();		// used to set the editor selection to the newly created edges

		/// build out new faces around validEdges

		for(int i = 0; i < validEdges.Count; i++)
		{
			pb_Edge edge = validEdges[i];
			pb_Face face = edgeFaces[i];

			// Averages the normals using only vertices that are on the edge
			Vector3 xnorm = Norm( edge.x, sharedIndices, allEdgeIndices, oNormals );
			Vector3 ynorm = Norm( edge.y, sharedIndices, allEdgeIndices, oNormals );

			int x_sharedIndex = sharedIndices.IndexOf(edge.x);
			int y_sharedIndex = sharedIndices.IndexOf(edge.y);

			pb_Face newFace = pb.AppendFace(
				new Vector3[4]
				{
					localVerts [ edge.x ],
					localVerts [ edge.y ],
					localVerts [ edge.x ] + xnorm.normalized * extrudeDistance,
					localVerts [ edge.y ] + ynorm.normalized * extrudeDistance
				},
				new pb_Face( new int[6] {2, 1, 0, 2, 3, 1 }, face.material, new pb_UV(), 0, -1, -1, face.colors[0] ),
				new int[4] { x_sharedIndex, y_sharedIndex, -1, -1 });

			newEdges.Add(new pb_Edge(newFace.indices[3], newFace.indices[4]));

			extrudedIndices.Add(new pb_Edge(x_sharedIndex, newFace.indices[3]));
			extrudedIndices.Add(new pb_Edge(y_sharedIndex, newFace.indices[4]));
		}

		sharedIndices = pb.sharedIndices;

		// merge extruded vertex indices with each other
		for(int i = 0; i < extrudedIndices.Count; i++)
		{
			int val = extrudedIndices[i].x;
			for(int n = 0; n < extrudedIndices.Count; n++)
			{
				if(n == i)
					continue;

				if(extrudedIndices[n].x == val)
				{
					pb_IntArrayUtility.MergeSharedIndices(ref sharedIndices, extrudedIndices[n].y, extrudedIndices[i].y);
					break;
				}
			}
		}

		pb.SetSharedIndices(sharedIndices);
		pb.RebuildFaceCaches();
		
		return newEdges.ToArray();
	}
Пример #5
0
	/**
	 *	Given a face and a point, this will add a vertex to the pb_Object and retriangulate the face.
	 */
	public static bool AppendVerticesToFace(this pb_Object pb, pb_Face face, Vector3[] points, Color[] addColors, out pb_Face newFace)
	{
		if(!face.IsValid())
		{
			newFace = face;
			return false;
		}

		// First order of business - project face to 2d
		int[] distinctIndices = face.distinctIndices;
		Vector3[] verts = pb.GetVertices(distinctIndices);
		Color[] cols = pbUtil.ValuesWithIndices(pb.colors, distinctIndices);
		Vector2[] uvs = new Vector2[distinctIndices.Length+points.Length];
		System.Array.Copy(pb.GetUVs(distinctIndices), 0, uvs, 0, distinctIndices.Length);

		// Add the new point
		Vector3[] t_verts = new Vector3[verts.Length + points.Length];
		System.Array.Copy(verts, 0, t_verts, 0, verts.Length);
		System.Array.Copy(points, 0, t_verts, verts.Length, points.Length);
		verts = t_verts;

		// Add the new color
		Color[] t_col = new Color[cols.Length + addColors.Length];
		System.Array.Copy(cols, 0, t_col, 0, cols.Length);
		System.Array.Copy(addColors, 0, t_col, cols.Length, addColors.Length);
		cols = t_col;

		// Get the face normal before modifying the vertex array
		Vector3 nrm = pb_Math.Normal(pb.GetVertices(face.indices));
		Vector3 projAxis = pb_Math.ProjectionAxisToVector( pb_Math.VectorToProjectionAxis(nrm) );
		
		// Project
		List<Vector2> plane = new List<Vector2>(pb_Math.PlanarProject(verts, projAxis));

		// Save the sharedIndices index for each distinct vertex
		pb_IntArray[] sharedIndices = pb.sharedIndices;
		int[] sharedIndex = new int[distinctIndices.Length+points.Length];
		for(int i = 0; i < distinctIndices.Length; i++)
			sharedIndex[i] = sharedIndices.IndexOf(distinctIndices[i]);
		
		for(int i = distinctIndices.Length; i < distinctIndices.Length+points.Length; i++)
			sharedIndex[i] = -1;	// add the new vertex to it's own sharedIndex

		// Triangulate the face with the new point appended
		int[] tris = Delaunay.Triangulate(plane).ToIntArray();
		
		// Check to make sure the triangulated face is facing the same direction, and flip if not
		Vector3 del = Vector3.Cross( verts[tris[2]] - verts[tris[0]], verts[tris[1]]-verts[tris[0]]).normalized;
		if(Vector3.Dot(nrm, del) > 0)
			System.Array.Reverse(tris);
		
		// Build the new face
		pb_Face triangulated_face = new pb_Face(tris, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, -1, face.manualUV);

		/**
		 * Attempt to figure out where the new UV point(s) should go (if auto uv'ed face)
		 */
		if(triangulated_face.manualUV)
		{
			for(int n = distinctIndices.Length; n < uvs.Length; n++)
			{
				// these are the two vertices that are split by the new vertex
				int[] adjacent_vertex = System.Array.FindAll(triangulated_face.edges, x => x.Contains(n)).Select(x => x.x != n ? x.x : x.y).ToArray();

				if(adjacent_vertex.Length == 2)
				{
					uvs[n] = (uvs[adjacent_vertex[0]] + uvs[adjacent_vertex[1]])/2f;
				}
				else
				{
					Debug.LogWarning("Failed to find appropriate UV coordinate for new vertex point.  Setting face to AutoUV.");
					triangulated_face.manualUV = false;
				}
			}
		}

		// Compose new face
		newFace = pb.AppendFace(verts, cols, uvs, triangulated_face, sharedIndex);

		// And delete the old
		pb.DeleteFace(face);	

		return true;
	}
	/**
	 *	Given a face and a point, this will add a vertex to the pb_Object and retriangulate the face.
	 */
	public static bool AppendVerticesToFace(this pb_Object pb, pb_Face face, List<Vector3> points, out pb_Face newFace)
	{
		if(!face.isValid())
		{
			newFace = face;
			return false;
		}

		// First order of business - project face to 2d
		int[] distinctIndices = face.distinctIndices;
		Vector3[] verts = pb.GetVertices(distinctIndices);

		// Get the face normal before modifying the vertex array
		Vector3 nrm = pb_Math.Normal(pb.GetVertices(face.indices));
		Vector3 projAxis = pb_Math.GetProjectionAxis(nrm).ToVector3();
		
		// Add the new point
		Vector3[] t_verts = new Vector3[verts.Length + points.Count];
		System.Array.Copy(verts, 0, t_verts, 0, verts.Length);
		System.Array.Copy(points.ToArray(), 0, t_verts, verts.Length, points.Count);

		verts = t_verts;

		// Project
		List<Vector2> plane = new List<Vector2>(pb_Math.VerticesTo2DPoints(verts, projAxis));

		// Save the sharedIndices index for each distinct vertex
		pb_IntArray[] sharedIndices = pb.sharedIndices;
		int[] sharedIndex = new int[distinctIndices.Length+points.Count];
		for(int i = 0; i < distinctIndices.Length; i++)
			sharedIndex[i] = sharedIndices.IndexOf(distinctIndices[i]);
		
		for(int i = distinctIndices.Length; i < distinctIndices.Length+points.Count; i++)
			sharedIndex[i] = -1;	// add the new vertex to it's own sharedIndex

		// Triangulate the face with the new point appended
		int[] tris = Delauney.Triangulate(plane).ToIntArray();

		// Check to make sure the triangulated face is facing the same direction, and flip if not
		Vector3 del = Vector3.Cross( verts[tris[2]] - verts[tris[0]], verts[tris[1]]-verts[tris[0]]).normalized;
		if(Vector3.Dot(nrm, del) > 0) System.Array.Reverse(tris);

		// Compose new face
		newFace = pb.AppendFace(verts, new pb_Face(tris, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, -1, face.color), sharedIndex);

		// And delete the old
		pb.DeleteFace(face);	

		return true;
	}
Пример #7
0
		public static bool Bridge(this pb_Object pb, pb_Edge a, pb_Edge b, bool enforcePerimiterEdgesOnly)
		{
			pb_IntArray[] sharedIndices = pb.GetSharedIndices();
			Dictionary<int, int> lookup = sharedIndices.ToDictionary();

			// Check to see if a face already exists
			if(enforcePerimiterEdgesOnly)
			{
				if( pbMeshUtils.GetNeighborFaces(pb, a).Count > 1 || pbMeshUtils.GetNeighborFaces(pb, b).Count > 1 )
				{
					return false;
				}
			}

			foreach(pb_Face face in pb.faces)
			{
				if(face.edges.IndexOf(a, lookup) >= 0 && face.edges.IndexOf(b, lookup) >= 0)
				{
					Debug.LogWarning("Face already exists between these two edges!");
					return false;
				}
			}
		
			Vector3[] verts = pb.vertices;
			Vector3[] v;
			Color[] c;
			int[] s;
			pb_UV uvs = new pb_UV();
			Material mat = pb_Constant.DefaultMaterial;

			// Get material and UV stuff from the first edge face 
			foreach(pb_Face face in pb.faces)
			{
				if(face.edges.Contains(a))	
				{
					uvs = new pb_UV(face.uv);
					mat = face.material;
					break;
				}
			}

			// Bridge will form a triangle
			if( a.Contains(b.x, sharedIndices) || a.Contains(b.y, sharedIndices) )
			{
				v = new Vector3[3];
				c = new Color[3];
				s = new int[3];

				bool axbx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.x) > -1;
				bool axby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.y) > -1;
				
				bool aybx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.x) > -1;
				bool ayby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.y) > -1;
				
				if(axbx)
				{	
					v[0] = verts[a.x];
					c[0] = pb.colors[a.x];
					s[0] = sharedIndices.IndexOf(a.x);
					v[1] = verts[a.y];
					c[1] = pb.colors[a.y];
					s[1] = sharedIndices.IndexOf(a.y);
					v[2] = verts[b.y];
					c[2] = pb.colors[b.y];
					s[2] = sharedIndices.IndexOf(b.y);
				}
				else
				if(axby)
				{
					v[0] = verts[a.x];
					c[0] = pb.colors[a.x];
					s[0] = sharedIndices.IndexOf(a.x);
					v[1] = verts[a.y];
					c[1] = pb.colors[a.y];
					s[1] = sharedIndices.IndexOf(a.y);
					v[2] = verts[b.x];
					c[2] = pb.colors[b.x];
					s[2] = sharedIndices.IndexOf(b.x);
				}
				else
				if(aybx)
				{
					v[0] = verts[a.y];
					c[0] = pb.colors[a.y];
					s[0] = sharedIndices.IndexOf(a.y);
					v[1] = verts[a.x];
					c[1] = pb.colors[a.x];
					s[1] = sharedIndices.IndexOf(a.x);
					v[2] = verts[b.y];
					c[2] = pb.colors[b.y];
					s[2] = sharedIndices.IndexOf(b.y);
				}
				else
				if(ayby)
				{
					v[0] = verts[a.y];
					c[0] = pb.colors[a.y];
					s[0] = sharedIndices.IndexOf(a.y);
					v[1] = verts[a.x];
					c[1] = pb.colors[a.x];
					s[1] = sharedIndices.IndexOf(a.x);
					v[2] = verts[b.x];
					c[2] = pb.colors[b.x];
					s[2] = sharedIndices.IndexOf(b.x);
				}

				pb.AppendFace(
					v,
					c,
					new Vector2[v.Length],
					new pb_Face( axbx || axby ? new int[3] {2, 1, 0} : new int[3] {0, 1, 2}, mat, uvs, 0, -1, -1, false ),
					s);

				return true;
			}

			// Else, bridge will form a quad

			v = new Vector3[4];
			c = new Color[4];
			s = new int[4]; // shared indices index to add to

			v[0] = verts[a.x];
			c[0] = pb.colors[a.x];
			s[0] = sharedIndices.IndexOf(a.x);
			v[1] = verts[a.y];
			c[1] = pb.colors[a.y];
			s[1] = sharedIndices.IndexOf(a.y);

			Vector3 nrm = Vector3.Cross( verts[b.x]-verts[a.x], verts[a.y]-verts[a.x] ).normalized;
			Vector2[] planed = pb_Math.PlanarProject( new Vector3[4] {verts[a.x], verts[a.y], verts[b.x], verts[b.y] }, nrm );

			Vector2 ipoint = Vector2.zero;
			bool interescts = pb_Math.GetLineSegmentIntersect(planed[0], planed[2], planed[1], planed[3], ref ipoint);

			if(!interescts)
			{
				v[2] = verts[b.x];
				c[2] = pb.colors[b.x];
				s[2] = sharedIndices.IndexOf(b.x);
				v[3] = verts[b.y];
				c[3] = pb.colors[b.y];
				s[3] = sharedIndices.IndexOf(b.y);
			}
			else
			{
				v[2] = verts[b.y];
				c[2] = pb.colors[b.y];
				s[2] = sharedIndices.IndexOf(b.y);
				v[3] = verts[b.x];
				c[3] = pb.colors[b.x];
				s[3] = sharedIndices.IndexOf(b.x);
			}

			pb.AppendFace(
				v,
				c,
				new Vector2[v.Length],
				new pb_Face( new int[6] {2, 1, 0, 2, 3, 1 }, mat, uvs, 0, -1, -1, false ),
				s);

			return true;
		}
Пример #8
0
	/**
	 *	Edge extrusion override
	 */
	public static bool Extrude(this pb_Object pb, pb_Edge[] edges, float extrudeDistance, bool extrudeAsGroup, bool enableManifoldExtrude, out pb_Edge[] extrudedEdges)
	{
		pb_IntArray[] sharedIndices = pb.sharedIndices;
		Dictionary<int, int> lookup = sharedIndices.ToDictionary();

		List<pb_Edge> validEdges = new List<pb_Edge>();
		List<pb_Face> edgeFaces = new List<pb_Face>();
		
		foreach(pb_Edge e in edges)
		{
			int faceCount = 0;
			pb_Face fa = null;
			foreach(pb_Face f in pb.faces)
			{
				if(f.edges.IndexOf(e, lookup) > -1)
				{
					fa = f;
					if(++faceCount > 1)
						break;
				}

			}

			if(enableManifoldExtrude || faceCount < 2)
			{
				validEdges.Add(e);
				edgeFaces.Add(fa);
			}
		}

		if(validEdges.Count < 1)
		{
			extrudedEdges = null;
			return false;
		}

		Vector3[] localVerts = pb.vertices;
		Vector3[] oNormals = pb.msh.normals;

		int[] allEdgeIndices = new int[validEdges.Count * 2];
		int c = 0;
		for(int i = 0; i < validEdges.Count; i++)
		{
			allEdgeIndices[c++] = validEdges[i].x;
			allEdgeIndices[c++] = validEdges[i].y;
		}

		List<pb_Edge> extrudedIndices = new List<pb_Edge>();
		List<pb_Edge> newEdges = new List<pb_Edge>();		// used to set the editor selection to the newly created edges

		/// build out new faces around validEdges

		for(int i = 0; i < validEdges.Count; i++)
		{
			pb_Edge edge = validEdges[i];
			pb_Face face = edgeFaces[i];

			// Averages the normals using only vertices that are on the edge
			Vector3 xnorm = extrudeAsGroup ? Norm( sharedIndices[lookup[edge.x]], allEdgeIndices, oNormals ) : pb_Math.Normal(pb, face);
			Vector3 ynorm = extrudeAsGroup ? Norm( sharedIndices[lookup[edge.y]], allEdgeIndices, oNormals ) : pb_Math.Normal(pb, face);

			int x_sharedIndex = lookup[edge.x];
			int y_sharedIndex = lookup[edge.y];

			pb_Face newFace = pb.AppendFace(
				new Vector3[4]
				{
					localVerts [ edge.x ],
					localVerts [ edge.y ],
					localVerts [ edge.x ] + xnorm.normalized * extrudeDistance,
					localVerts [ edge.y ] + ynorm.normalized * extrudeDistance
				},
				new Color[4] 
				{
					pb.colors[ edge.x ],
					pb.colors[ edge.y ],
					pb.colors[ edge.x ],
					pb.colors[ edge.y ]
				},
				new Vector2[4],
				new pb_Face( new int[6] {2, 1, 0, 2, 3, 1 }, face.material, new pb_UV(), 0, -1, -1, false ),
				new int[4] { x_sharedIndex, y_sharedIndex, -1, -1 });

			newEdges.Add(new pb_Edge(newFace.indices[3], newFace.indices[4]));

			extrudedIndices.Add(new pb_Edge(x_sharedIndex, newFace.indices[3]));
			extrudedIndices.Add(new pb_Edge(y_sharedIndex, newFace.indices[4]));
		}

		sharedIndices = pb.sharedIndices;

		// merge extruded vertex indices with each other
		if(extrudeAsGroup)
		{
			for(int i = 0; i < extrudedIndices.Count; i++)
			{
				int val = extrudedIndices[i].x;
				for(int n = 0; n < extrudedIndices.Count; n++)
				{
					if(n == i)
						continue;

					if(extrudedIndices[n].x == val)
					{
						pb_IntArrayUtility.MergeSharedIndices(ref sharedIndices, extrudedIndices[n].y, extrudedIndices[i].y);
						break;
					}
				}
			}
		}

		pb.SetSharedIndices(sharedIndices);
		pb.RebuildFaceCaches();
		
		extrudedEdges = newEdges.ToArray();
		return true;
	}