Пример #1
0
        /**
         * Returns true if bounds overlap.
         */
        public bool Intersects(pb_Bounds2D bounds)
        {
            Vector2 dist = this.center - bounds.center;
            Vector2 size = this.size + bounds.size;

            return(Mathf.Abs(dist.x) * 2f < size.x &&
                   Mathf.Abs(dist.y) * 2f < size.y);
        }
Пример #2
0
        private static Vector2[] ApplyUVSettings(Vector2[] uvs, pb_UV uvSettings)
        {
            int len = uvs.Length;

            switch (uvSettings.fill)
            {
            case pb_UV.Fill.Tile:
                break;

            case pb_UV.Fill.Fit:
                uvs = NormalizeUVs(uvs);
                break;

            case pb_UV.Fill.Stretch:
                uvs = StretchUVs(uvs);
                break;
            }

            // if(uvSettings.justify != pb_UV.Justify.None)
            //  uvs = JustifyUVs(uvs, uvSettings.justify);

            // Apply transform last, so that fill and justify don't override it.
            pb_Bounds2D bounds = new pb_Bounds2D(uvs);

            if (!uvSettings.useWorldSpace)
            {
                for (int i = 0; i < uvs.Length; i++)
                {
                    uvs[i] -= (bounds.center - bounds.extents);
                }
            }

            bounds = new pb_Bounds2D(uvs);

            for (int i = 0; i < uvs.Length; i++)
            {
                uvs[i] = uvs[i].ScaleAroundPoint(bounds.center, uvSettings.scale);
                uvs[i] = uvs[i].RotateAroundPoint(bounds.center, uvSettings.rotation);
            }


            for (int i = 0; i < len; i++)
            {
                float u = uvs[i].x, v = uvs[i].y;

                if (uvSettings.flipU)
                {
                    u = -u;
                }

                if (uvSettings.flipV)
                {
                    v = -v;
                }

                if (!uvSettings.swapUV)
                {
                    uvs[i] = new Vector2(u, v);
                }
                else
                {
                    uvs[i] = new Vector2(v, u);
                }
            }

            bounds = new pb_Bounds2D(uvs);

            uvSettings.localPivot = bounds.center;    // uvSettings.useWorldSpace ? bounds.center : bounds.extents;
            uvSettings.localSize  = bounds.size;

            for (int i = 0; i < uvs.Length; i++)
            {
                uvs[i] -= uvSettings.offset;
            }

            return(uvs);
        }
Пример #3
0
	public static bool GeneratePolygonCrosshatch(Vector2[] polygon, float scale, Color color, int lineSpacing, ref Texture2D texture)
	#endif
	{
		#if PB_DEBUG
		profiler.BeginSample("GeneratePolygonCrosshatch");
		#endif

		pb_Bounds2D bounds = new pb_Bounds2D(polygon);

		Vector2 offset = bounds.center - bounds.extents;

		/// shift polygon to origin 0,0
		for(int i = 0; i < polygon.Length; i++)
		{
			polygon[i] -= offset;
			polygon[i] *= scale;
		}

		bounds.center -= offset;
		bounds.size *= scale;

		int width = (int)(bounds.size.x);
		int height = (int)(bounds.size.y);

		if(width <= 0 || height <= 0)
			return false;

		#if PB_DEBUG
		profiler.BeginSample("Allocate Texture");
		#endif

		if(texture == null)
		{
			texture = new Texture2D(width, height, TextureFormat.ARGB32, false);
			texture.filterMode = FilterMode.Point;
			texture.wrapMode = TextureWrapMode.Clamp;
		}
		else
		{
			if(texture.width != width || texture.height != height)
				texture.Resize(width, height, TextureFormat.ARGB32, false);
		}

		#if PB_DEBUG
		profiler.EndSample();
		profiler.BeginSample("Fill Clear");
		#endif

		Color[] colors = new Color[width*height];
		List<int> intersects = new List<int>();

		for(int i = 0; i < width*height; i++)
			colors[i] = Color.clear;

		#if PB_DEBUG
		profiler.EndSample();
		#endif

		/**
		 *	Horizontal lines
		 */
		for(int h = 0; h < height/lineSpacing; h++)
		{	
			int y = (h*lineSpacing);
			intersects.Clear();

			#if PB_DEBUG
			profiler.BeginSample("Find Intersections");
			#endif

			Vector2 start = new Vector2(bounds.center.x - bounds.size.x, y);
			Vector2 end = new Vector2(bounds.center.x + bounds.size.x, y);

			for(int i = 0; i < polygon.Length; i+=2)
			{
				Vector2 intersect = Vector2.zero;

				if( pb_Math.GetLineSegmentIntersect(polygon[i], polygon[i+1], start, end, ref intersect) )
					intersects.Add((int)intersect.x);
			}

			intersects = intersects.Distinct().ToList();
			intersects.Sort();

			#if PB_DEBUG
			profiler.EndSample();
			profiler.BeginSample("Fill Color");
			#endif

			for(int i = 0; i < intersects.Count-1; i++)
			{
				// can't just use Dot product because we the winding order isn't consistent
				if( pb_Math.PointInPolygon(polygon, new Vector2(intersects[i]+2, y)) )
				{
					for(int n = intersects[i]; n < intersects[i+1]; n++)
					{
						colors[ ((height-1)-y) * width + n] = color;
					}
				}
			}

			#if PB_DEBUG
			profiler.EndSample();
			#endif
		}

		/**
		 *	Vertical lines
		 */
		if(lineSpacing > 1)
		{
			for(int w = 0; w < width/lineSpacing; w++)
			{	
				int x = (w*lineSpacing);

				intersects.Clear();

				Vector2 start = new Vector2(x, bounds.center.y - bounds.size.y);
				Vector2 end = new Vector2(x, bounds.center.y + bounds.size.y);

				for(int i = 0; i < polygon.Length; i+=2)
				{
					Vector2 intersect = Vector2.zero;
					if( pb_Math.GetLineSegmentIntersect(polygon[i], polygon[i+1], start, end, ref intersect) )
						intersects.Add((int)intersect.y);
				}

				intersects = intersects.Distinct().ToList();
				intersects.Sort();

				for(int i = 0; i < intersects.Count-1; i++)
				{
					if(pb_Math.PointInPolygon(polygon, new Vector2(x, intersects[i]+2)))
					{
						for(int y = intersects[i]; y < intersects[i+1]; y++)
						{	
							colors[ ((height-1)-y) * width + x] = color;
						}
					}
				}
			}
		}

		#if PB_DEBUG
		profiler.BeginSample("SetPixels");
		#endif
	
		texture.SetPixels(colors);
		texture.Apply(false);
		
		#if PB_DEBUG
		profiler.EndSample();
		profiler.EndSample();
		#endif

		return true;
	}
Пример #4
0
	/**
	 * Attempts to translate, rotate, and scale @points to match @target as closely as possible.
	 * Only points[0, target.Length] coordinates are used in the matching process - points[target.Length, points.Length]
	 * are just along for the ride.
	 */
	public static pb_Transform2D MatchCoordinates(Vector2[] points, Vector2[] target)
	{
		int length = points.Length < target.Length ? points.Length : target.Length;

		pb_Bounds2D t_bounds = new pb_Bounds2D(target, length); // only match the bounds of known matching points

		// move points to the center of target
		Vector2 translation = t_bounds.center - pb_Bounds2D.Center(points, length);

		Vector2[] transformed = new Vector2[points.Length];
		for(int i = 0; i < points.Length; i++)
			transformed[i] = points[i] + translation;

		// rotate to match target points
		Vector2 target_angle = target[1]-target[0], transform_angle = transformed[1]-transformed[0];

		float angle = Vector2.Angle(target_angle, transform_angle);
		float dot = Vector2.Dot( pb_Math.Perpendicular(target_angle), transform_angle);

		if(dot < 0) angle = 360f - angle;

		for(int i = 0; i < points.Length; i++)
			transformed[i] = transformed[i].RotateAroundPoint(t_bounds.center, angle);

		// and lastly scale
		pb_Bounds2D p_bounds = new pb_Bounds2D(transformed, length);
		Vector2 scale = t_bounds.size.DivideBy(p_bounds.size);

		// for(int i = 0; i < points.Length; i++)
		// 	transformed[i] = transformed[i].ScaleAroundPoint(t_bounds.center, scale);

		return new pb_Transform2D(translation, angle, scale);
	}
Пример #5
0
	/**
	 * Internal because pb_Editor needs to call this sometimes.
	 */
	internal void OnFinishUVModification()
	{	
		pb_Lightmapping.PopGIWorkflowMode();

		modifyingUVs = false;

		if((tool == Tool.Rotate || tool == Tool.Scale) && userPivot)
		{
			selected_canvas_bounds = CanvasSelectionBounds();
			SetHandlePosition(handlePosition_canvas, true);
		}

		if(mode == UVMode.Mixed || mode == UVMode.Auto)
		{
			pbUndo.RegisterCompleteObjectUndo(selection, (tool == Tool.Move ? "Translate UVs" : tool == Tool.Rotate ? "Rotate UVs" : "Scale UVs") );

			foreach(pb_Object pb in selection)
			{
				if(pb.SelectedFaceCount > 0)
				{
					/**
					 * Sort faces into texture groups for re-projection
					 */
					Dictionary<int, List<pb_Face>> textureGroups = new Dictionary<int, List<pb_Face>>();

					int n = -2;
					foreach(pb_Face face in System.Array.FindAll(pb.SelectedFaces, x => !x.manualUV))
					{
						if(textureGroups.ContainsKey(face.textureGroup))
							textureGroups[face.textureGroup].Add(face);
						else
							textureGroups.Add( face.textureGroup > 0 ? face.textureGroup : n--, new List<pb_Face>() {face} );
					}

					foreach(KeyValuePair<int, List<pb_Face>> kvp in textureGroups)
					{
						/**
						 * Rotation - only applies to rotation tool
						 */
						if(tool == Tool.Rotate)
						{
							foreach(pb_Face face in kvp.Value)
							{
								if((face.uv.flipU ^ face.uv.flipV) ^ face.uv.swapUV) 
									uvRotation = -uvRotation;

								face.uv.rotation += uvRotation;
								if(face.uv.rotation > 360f) face.uv.rotation = face.uv.rotation % 360f;
								if(face.uv.rotation < 0f) face.uv.rotation = 360f + (face.uv.rotation % 360f);
							}
						}

						/**
						 * Scale is applied in real-time
						 */

						/**
						 * Reproject because uv.localPivot needs to be accurate for this to work properly
						 */
						foreach(pb_Face face in kvp.Value)
							face.uv.offset = Vector2.zero;

						Vector3 nrm = Vector3.zero;
						foreach(pb_Face face in kvp.Value)
						{
							nrm += pb_Math.Normal( 	pb.vertices[face.indices[0]],
													pb.vertices[face.indices[1]],
													pb.vertices[face.indices[2]] ); 
						}

						nrm /= (float)kvp.Value.Count;

						int[] tris = pb_Face.AllTriangles(kvp.Value).ToArray();

						if(kvp.Value[0].uv.useWorldSpace)
						{
							pb.transform.TransformDirection(nrm);
							pb_UVUtility.PlanarMap( pb.transform.ToWorldSpace(pb.GetVertices(tris)), kvp.Value[0].uv, nrm );
						}
						else
						{
							pb_UVUtility.PlanarMap( pb.GetVertices(tris), kvp.Value[0].uv, nrm );
						}

						foreach(pb_Face face in kvp.Value)
							face.uv.localPivot = kvp.Value[0].uv.localPivot;

						/**
						 * Translation - applies for every tool
						 */
						Vector2 handle = pb_Handle_Utility.GUIToUVPoint(handlePosition_canvas, uvGridSize);
						Vector2 cen = pb_Bounds2D.Center(pb.GetUVs(tris));

						foreach(pb_Face face in kvp.Value)
							face.uv.offset = -((handle - face.uv.localPivot) - (handle-cen));

					}
				}
				else
				{
					FlagSelectedFacesAsManual(pb);
				}
			}
		}
		else if(mode == UVMode.Manual)
		{
			foreach(pb_Object pb in selection)
			{
				if(pb.SelectedFaceIndices.Length > 0)
				{
					foreach(pb_Face face in pb.SelectedFaces)
					{
						face.textureGroup = -1;
						face.manualUV = true;
					}
				}
				else
				{
					FlagSelectedFacesAsManual(pb);
				}
			}

		}

		// Regenerate UV2s
		foreach(pb_Object pb in selection)
		{
			pb.ToMesh();
			pb.Refresh();
			pb.Optimize();
		}
	}
Пример #6
0
	/**
	 * Refresh only the selected UV coordinates.
	 */
	void RefreshSelectedUVCoordinates()
	{	
		for(int n = 0; n < selection.Length; n++)
		{
			Vector2[] uvs = GetUVs(selection[n], channel);
			
			foreach(int i in distinct_indices[n])
				uvs_canvas_space[n][i] = pb_Handle_Utility.UVToGUIPoint(uvs[i], uvGridSize);
		}

		selected_canvas_bounds = CanvasSelectionBounds();
		handlePosition_canvas = selected_canvas_bounds.center - handlePosition_offset;
	}
Пример #7
0
	/**
	 * If dragRect is null, the selected UV array will be derived using the selected ProBuilder faces.
	 * If it ain't null, selected UVs will be set to the UV coordinates contained within the drag rect.
	 */
	void RefreshUVCoordinates(Rect? dragRect, bool isClick)
	{	
		if(editor == null || selection == null) return;

		#if PB_DEBUG
		profiler.BeginSample("RefreshUVCoordinates");
		#endif

		// Collect drawables
		uvs_canvas_space = new Vector2[selection.Length][];

		// Convert dragrect from Unity GUI space to uv_gui_space
		pb_Bounds2D dragBounds = dragRect != null ? 
			new pb_Bounds2D( GUIToCanvasPoint(((Rect)dragRect).center), new Vector2( ((Rect)dragRect).width, ((Rect)dragRect).height) / uvGraphScale ) :
			new pb_Bounds2D( Vector2.zero, Vector2.zero );

		selectedUVCount   = editor.selectedVertexCount;
		selectedFaceCount = editor.selectedFaceCount;
		// selectedEdgeCount = editor.selectedEdgeCount;

		for(int i = 0; i < selection.Length; i++)
		{
			pb_Object pb = selection[i];

			Vector2[] mshUV = GetUVs(pb, channel);
			int len = mshUV.Length;

			uvs_canvas_space[i] = new Vector2[len];

			for(int j = 0; j < len; j++)
				uvs_canvas_space[i][j] = pb_Handle_Utility.UVToGUIPoint(mshUV[j], uvGridSize);

			// this should probably be separate from RefreshUVCoordinates
			if(dragRect != null)
			{	
				switch(selectionMode)
				{
					case SelectMode.Vertex:
						List<int> selectedTris = new List<int>(pb.SelectedTriangles);

						for(int j = 0; j < len; j++)
						{
							if( dragBounds.ContainsPoint( uvs_canvas_space[i][j] ) )
							{
								int indx = selectedTris.IndexOf(j);

								if(indx > -1)
									selectedTris.RemoveAt(indx);
								else
									selectedTris.Add(j);

								// if this is a click, only do one thing per-click
								if(isClick)
									break;
							}
						}

						pb.SetSelectedTriangles(selectedTris.ToArray());
						break;

					case SelectMode.Edge:
						List<pb_Edge> selectedEdges = new List<pb_Edge>(pb.SelectedEdges);

						for(int n = 0; n < pb.faces.Length; n++)
						{
							for(int p = 0; p < pb.faces[n].edges.Length; p++)
							{
								pb_Edge edge = pb.faces[n].edges[p];

								if( dragBounds.IntersectsLineSegment( uvs_canvas_space[i][edge.x],  uvs_canvas_space[i][edge.y]) )	
								{
									if(!selectedEdges.Contains(edge))
										selectedEdges.Add( edge );
									else
										selectedEdges.Remove( edge );
								}
							}
						}

						pb.SetSelectedEdges(selectedEdges.ToArray());
						break;
				
					/**
					 * Check if any of the faces intersect with the mousedrag rect.
					 */
					case SelectMode.Face:

						HashSet<int> selectedFaces = new HashSet<int>(selection[i].SelectedFaceIndices);
						for(int n = 0; n < pb.faces.Length; n++)
						{
							// Vector2[] uvs = pbUtil.ValuesWithIndices(, pb.faces[n].distinctIndices);
							int[] distinctIndices = pb.faces[n].distinctIndices;

							bool allPointsContained = true;

							for(int t = 0; t < distinctIndices.Length; t++)
							{
								if( ! dragBounds.ContainsPoint(uvs_canvas_space[i][distinctIndices[t]]) )
								{
									allPointsContained = false;
									break;
								}
							}

							// // if(dragBounds.Intersects(faceBounds))
							// for(int t = 0; t < uvs.Length; t++)
							// {
							// 	if(!dragBounds.ContainsPoint(uvs[t]))
							// 	{
							// 		allPointsContained = false;
							// 		break;
							// 	}
							// }

							if(allPointsContained)
							{
								if( selectedFaces.Contains(n) )
										selectedFaces.Remove(n);
									else
										selectedFaces.Add(n);
							}
						}
						selection[i].SetSelectedFaces(selectedFaces.ToArray());

						break;
				}

				editor.UpdateSelection(false);
				SceneView.RepaintAll();
			}
		}

		// figure out what the mode of selected faces is
		if(editor.selectedFaceCount > 0)
		{
			// @todo write a more effecient method for this
			List<bool> manual = new List<bool>();
			for(int i = 0; i < selection.Length; i++)
				manual.AddRange( selection[i].SelectedFaces.Select(x => x.manualUV).ToList() );
			int c = manual.Distinct().Count();
			if(c > 1)
				mode = UVMode.Mixed;
			else if (c > 0)
				mode = manual[0] ? UVMode.Manual : UVMode.Auto;
		}
		else
		{
			mode = UVMode.Manual;
		}

		editor.GetFirstSelectedMaterial(ref preview_material);

		selected_canvas_bounds = CanvasSelectionBounds();
		handlePosition_canvas = selected_canvas_bounds.center - handlePosition_offset;

		#if PB_DEBUG
		profiler.EndSample();
		#endif
	}
Пример #8
0
		/**
		 * Returns true if bounds overlap.
		 */
		public bool Intersects(pb_Bounds2D bounds)
		{
			Vector2 dist = this.center - bounds.center;
			Vector2 size = this.size + bounds.size;

			return  Mathf.Abs(dist.x) * 2f < size.x && 
					Mathf.Abs(dist.y) * 2f < size.y;
		}
Пример #9
0
	private static Vector2[] ApplyUVSettings(Vector2[] uvs, pb_UV uvSettings)
	{

		int len = uvs.Length;

		switch(uvSettings.fill)
		{
			case pb_UV.Fill.Tile:
				break;
			case pb_UV.Fill.Fit:
				uvs = NormalizeUVs(uvs);
				break;
			case pb_UV.Fill.Stretch:
				uvs = StretchUVs(uvs);
				break;
		}

		// if(uvSettings.justify != pb_UV.Justify.None)
		// 	uvs = JustifyUVs(uvs, uvSettings.justify);

		// Apply transform last, so that fill and justify don't override it.
		pb_Bounds2D bounds = new pb_Bounds2D(uvs);

		if(!uvSettings.useWorldSpace)
			for(int i = 0; i < uvs.Length; i++)
				uvs[i] -= (bounds.center - bounds.extents);

		bounds = new pb_Bounds2D(uvs);

		for(int i = 0; i < uvs.Length; i++)
		{
			uvs[i] = uvs[i].ScaleAroundPoint(bounds.center, uvSettings.scale);			
			uvs[i] = uvs[i].RotateAroundPoint(bounds.center, uvSettings.rotation);
		}


		for(int i = 0; i < len; i++)
		{
			float u = uvs[i].x, v = uvs[i].y;
			
			if(uvSettings.flipU)
				u = -u;

			if(uvSettings.flipV)
				v = -v;

			if(!uvSettings.swapUV)
				uvs[i] = new Vector2(u, v);
			else
				uvs[i] = new Vector2(v, u);
		}
		
		bounds = new pb_Bounds2D(uvs);

		uvSettings.localPivot = bounds.center;// uvSettings.useWorldSpace ? bounds.center : bounds.extents;
		uvSettings.localSize = bounds.size;

		for(int i = 0; i < uvs.Length; i++)
			uvs[i] -= uvSettings.offset;

		return uvs;
	}