예제 #1
0
	/**
	 * If any of the faces in @selection are AutoUV and in a texture group, this 
	 * augments the texture group buddies to the selection and returns it.
	 */
	private pb_Face[] SelectTextureGroups(pb_Object pb, pb_Face[] selection)
	{	
		List<int> texGroups = selection.Select(x => x.textureGroup).Where(x => x > 0).Distinct().ToList();
		pb_Face[] sel = System.Array.FindAll(pb.faces, x => !x.manualUV && texGroups.Contains(x.textureGroup));

		return selection.Union(sel).ToArray();
	}
예제 #2
0
	/**
	 * If selection contains faces that are part of a texture group, and not all of those group faces are in the selection,
	 * return a pb_Face[] of that entire group so that we can show the user some indication of that groupage.
	 */
	private List<pb_Face[]> GetIncompleteTextureGroups(pb_Object pb, pb_Face[] selection)
	{
		// get distinct list of all selected texture groups
		List<int> groups = selection.Select(x => x.textureGroup).Where(x => x > 0).Distinct().ToList();
		List<pb_Face[]> incompleteGroups = new List<pb_Face[]>(); 
		
		// figure out how many 
		for(int i = 0; i < groups.Count; i++)
		{
			pb_Face[] whole_group = System.Array.FindAll(pb.faces, x => !x.manualUV && groups[i] == x.textureGroup);
			int inSelection = System.Array.FindAll(selection, x => x.textureGroup == groups[i]).Length;

			if(inSelection != whole_group.Length)
				incompleteGroups.Add(whole_group);
		}

		return incompleteGroups;
	}
예제 #3
0
	/**
	 * Extrudes passed faces on their normal axis using extrudeDistance.
	 */
	public static bool Extrude(this pb_Object pb, pb_Face[] faces, float extrudeDistance, bool extrudeAsGroup, out pb_Face[] appendedFaces)
	{
		appendedFaces = null;

		if(faces == null || faces.Length < 1)
			return false;

		pb_IntArray[] sharedIndices = pb.GetSharedIndices();
		Dictionary<int, int> lookup = sharedIndices.ToDictionary();

		Vector3[] localVerts = pb.vertices;

		pb_Edge[][] perimeterEdges = extrudeAsGroup ? new pb_Edge[1][] { pbMeshUtils.GetPerimeterEdges(pb, lookup, faces).ToArray() } : faces.Select(x => x.edges).ToArray();

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

		pb_Face[][] edgeFaces = new pb_Face[perimeterEdges.Length][];	// can't assume faces and perimiter edges will be 1:1 - so calculate perimeters then extract face information
		int[][] allEdgeIndices = new int[perimeterEdges.Length][];
		int c = 0;

		for(int i = 0; i < perimeterEdges.Length; i++)
		{
			c = 0;
			allEdgeIndices[i] = new int[perimeterEdges[i].Length * 2];
			edgeFaces[i] = new pb_Face[perimeterEdges[i].Length];

			for(int n = 0; n < perimeterEdges[i].Length; n++)
			{
				// gets the faces associated with each perimeter edge
				foreach(pb_Face face in faces)
				{
					if(face.edges.Contains(perimeterEdges[i][n]))
					{
						edgeFaces[i][n] = face;
						break;
					}
				}

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

		List<pb_Edge>[] extrudedIndices = new List<pb_Edge>[perimeterEdges.Length];
		Vector3[] normals = pb.msh.normals;

		List<Vector3[]> append_vertices = new List<Vector3[]>();
		List<Color[]> append_color = new List<Color[]>();
		List<Vector2[]> append_uv = new List<Vector2[]>();
		List<pb_Face> append_face = new List<pb_Face>();
		List<int[]> append_shared = new List<int[]>();

		/// build out new faces around edges
		
		for(int i = 0; i < perimeterEdges.Length; i++)
		{
			extrudedIndices[i] = new List<pb_Edge>();

			for(int n = 0; n < perimeterEdges[i].Length; n++)
			{
				pb_Edge edge = perimeterEdges[i][n];
				pb_Face face = edgeFaces[i][n];

				// 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( Mathf.Abs(extrudeDistance) > Mathf.Epsilon)
				{
					if( !extrudeAsGroup )
					{
						xnorm = pb_Math.Normal( localVerts[face.indices[0]], localVerts[face.indices[1]], localVerts[face.indices[2]] );
						ynorm = xnorm;					
					}
					else
					{
						xnorm = Norm(sharedIndices[lookup[edge.x]], allEdgeIndices[i], normals );
						ynorm = Norm(sharedIndices[lookup[edge.y]], allEdgeIndices[i], normals );
					}
				}

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

				// this could be condensed to a single call with an array of new faces
				append_vertices.Add( new Vector3[]
					{
						localVerts [ edge.x ],
						localVerts [ edge.y ],
						localVerts [ edge.x ] + xnorm.normalized * extrudeDistance,
						localVerts [ edge.y ] + ynorm.normalized * extrudeDistance
					});

				append_color.Add( new Color[]
					{	
						pb.colors[ edge.x ],
						pb.colors[ edge.y ],
						pb.colors[ edge.x ],
						pb.colors[ edge.y ]
					});

				append_uv.Add( new Vector2[4] );

				append_face.Add( 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
						false)									// manualUV flag
						);

				append_shared.Add( new int[4]
					{
						x_sharedIndex,
						y_sharedIndex,
						-1,
						-1 
					});

				extrudedIndices[i].Add(new pb_Edge(x_sharedIndex, -1));
				extrudedIndices[i].Add(new pb_Edge(y_sharedIndex, -1));
			}
		}

		appendedFaces = pb.AppendFaces( append_vertices.ToArray(), append_color.ToArray(), append_uv.ToArray(), append_face.ToArray(), append_shared.ToArray() );

		// x = shared index, y = triangle (only known once faces are appended to pb_Object)
		for(int i = 0, f = 0; i < extrudedIndices.Length; i++)
		{
			for(int n = 0; n < extrudedIndices[i].Count; n+=2)
			{
				extrudedIndices[i][n+0].y = appendedFaces[f].indices[2];
				extrudedIndices[i][n+1].y = appendedFaces[f++].indices[4];
			}
		}

		pb_IntArray[] si = pb.sharedIndices;	// leave the sharedIndices copy alone since we need the un-altered version later
		Dictionary<int, int> welds = si.ToDictionary();

		// Weld side-wall top vertices together, both grouped and non-grouped need this.
		for(int f = 0; f < extrudedIndices.Length; f++)
		{
			for(int i = 0; i < extrudedIndices[f].Count-1; i++)
			{
				int val = extrudedIndices[f][i].x;
				for(int n = i+1; n < extrudedIndices[f].Count; n++)
				{
					if(extrudedIndices[f][n].x == val)
					{
						welds[extrudedIndices[f][i].y] = welds[extrudedIndices[f][n].y];
						break;
					}
				}
			}
		}

		localVerts = pb.vertices;

		// Remove smoothing and texture group flags
		foreach(pb_Face f in faces)
		{
			f.SetSmoothingGroup(-1);
			f.textureGroup = -1;
		}

		if(extrudeAsGroup)
		{
			foreach(pb_Face f in faces)
			{
				int[] distinctIndices = f.distinctIndices;

				// Merge in-group face seams
				foreach(int ind in distinctIndices)
				{
					int oldIndex = si.IndexOf(ind);

					for(int n = 0; n < allEdgeIndices.Length; n++)
					{
						for(int i = 0; i < extrudedIndices[n].Count; i++)
						{
							if(oldIndex == extrudedIndices[n][i].x)
							{
								welds[ind] = welds[extrudedIndices[n][i].y];
								break;
							}
						}
					}
				}
			}
		}
		else
		/**
		 * If extruding as separate faces, weld each face to the tops of the bridging faces
		 */
		{
			// Dictionary<int, int> hold = si.ToDictionary();

			for(int i = 0; i < edgeFaces.Length; i++)
			{
				foreach(int n in pb_Face.AllTrianglesDistinct(edgeFaces[i]))
				{
					int old_si_index = lookup[n];
					int match = extrudedIndices[i].FindIndex(x => x.x == old_si_index);

					if(match < 0)
						continue;
					
					int match_tri_index = extrudedIndices[i][match].y;

					if(welds.ContainsKey(match_tri_index))
					{
						welds[n] = welds[match_tri_index];
					}
				}
			}

		}
		
		si = welds.ToSharedIndices();


		pb.SplitUVs(pb_Face.AllTriangles(faces));
		
		/**
		 * Move the inside faces to the top of the extrusion
		 *
		 * This is a separate loop cause the one above this must completely merge all sharedindices prior to 
		 * checking the normal averages
		 *
		 */
		Vector3 norm = Vector3.zero;
		int[] allIndices = pb_Face.AllTrianglesDistinct(faces);
		foreach(pb_Face f in faces)
		{
			if(!extrudeAsGroup)
			{
				norm = pb_Math.Normal( localVerts[f.indices[0]], localVerts[f.indices[1]], localVerts[f.indices[2]]);
			}

			foreach(int ind in f.distinctIndices)
			{
				if(extrudeAsGroup)
					norm = Norm( sharedIndices[lookup[ind]], allIndices, normals );

				localVerts[ind] += norm.normalized * extrudeDistance;
			}
		}

		// Test the winding of the first pulled face, and reverse if it's ccw
		if(pb.GetWindingOrder(faces[0]) == WindingOrder.CounterClockwise)
		{
			foreach(pb_Face face in appendedFaces)
				face.ReverseIndices();
		}

		pb.SetSharedIndices(si);
		pb.SetVertices(localVerts);


		return true;
	}