Ejemplo n.º 1
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, 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);
        }
Ejemplo n.º 2
0
    public static bool HiddenFace(pb_Object pb, pb_Face q, float dist)
    {
        // Grab the face normal
        Vector3 dir = pb_Math.Normal(pb.VerticesInWorldSpace(q.indices));

        // If casting from the center of the plane hits, chekc the rest of the points for collisions
        Vector3 orig = pb.transform.TransformPoint(pb_Math.Average(pb.GetVertices(q)));

        bool hidden = true;
        Transform hitObj = RaycastFaceCheck(orig, dir, dist, null);
        if(hitObj != null)
        {
            Vector3[] v = pb.VerticesInWorldSpace(q.indices);
            for(int i = 0; i < v.Length; i++)
            {
                if(null == RaycastFaceCheck(v[i], dir, dist, hitObj))
                {
                    hidden = false;
                    break;
                }
            }
        }
        else
            hidden = false;

        return hidden;
    }
Ejemplo n.º 3
0
    // breaks a pb_object into a zillion* faces
    public static GameObject[] ExplodeObject(pb_Object pb)
    {
        // disable 'ze donor
        pb.gameObject.SetActive(false);

        GameObject[] pieces = new GameObject[pb.faces.Length];

        // extract mesh and material information for every face, and assign it to a gameobject
        for (int i = 0; i < pieces.Length; i++)
        {
            Mesh m = new Mesh();
            m.vertices  = pb.GetVertices(pb.faces[i]);
            m.triangles = new int[6] {
                0, 1, 2, 1, 3, 2
            };
            m.normals = pb.GetNormals(pb.faces[i]);
            m.uv      = pb.GetUVs(pb.faces[i]);
            m.RecalculateBounds();

            GameObject go = new GameObject();
            go.transform.position      = pb.transform.position + pb_Math.PlaneNormal(m.vertices).normalized * .3f;
            go.transform.localRotation = pb.transform.localRotation;

            go.AddComponent <MeshFilter>().sharedMesh       = m;
            go.AddComponent <MeshRenderer>().sharedMaterial = pb.GetMaterial(pb.faces[i]);

            pieces[i] = go;
        }

        return(pieces);
    }
Ejemplo n.º 4
0
	// breaks a pb_object into a zillion* faces
	public static GameObject[] ExplodeObject(pb_Object pb)
	{
		// disable 'ze donor
		pb.gameObject.SetActive(false);
		
		GameObject[] pieces = new GameObject[pb.faces.Length];
		
		// extract mesh and material information for every face, and assign it to a gameobject
		for(int i = 0; i < pieces.Length; i++)
		{
			Mesh m = new Mesh();
			m.vertices 	= pb.GetVertices(pb.faces[i]);
			m.triangles	= new int[6] {0,1,2, 1,3,2};
			m.normals  	= pb.GetNormals(pb.faces[i]);
			m.uv	  	= pb.GetUVs(pb.faces[i]);
			m.RecalculateBounds();

			GameObject go = new GameObject();
			go.transform.position = pb.transform.position + pb_Math.PlaneNormal(m.vertices).normalized * .3f;
			go.transform.localRotation = pb.transform.localRotation;
			
			go.AddComponent<MeshFilter>().sharedMesh = m;
			go.AddComponent<MeshRenderer>().sharedMaterial = pb.GetMaterial(pb.faces[i]);

			pieces[i] = go;
		}

		return pieces;
	}
Ejemplo n.º 5
0
    public static bool HiddenFace(pb_Object pb, pb_Face q, float dist)
    {
        // Grab the face normal
        Vector3 dir = pb_Math.Normal(pb.VerticesInWorldSpace(q.indices));

        // If casting from the center of the plane hits, chekc the rest of the points for collisions
        Vector3 orig = pb.transform.TransformPoint(pb_Math.Average(pb.GetVertices(q)));

        bool      hidden = true;
        Transform hitObj = RaycastFaceCheck(orig, dir, dist, null);

        if (hitObj != null)
        {
            Vector3[] v = pb.VerticesInWorldSpace(q.indices);
            for (int i = 0; i < v.Length; i++)
            {
                if (null == RaycastFaceCheck(v[i], dir, dist, hitObj))
                {
                    hidden = false;
                    break;
                }
            }
        }
        else
        {
            hidden = false;
        }

        return(hidden);
    }
Ejemplo n.º 6
0
        /**
         * Returns requested vertices in world space coordinates.
         */
        public static Vector3[] VerticesInWorldSpace(this pb_Object pb, int[] indices)
        {
            if (indices == null)
            {
                Debug.LogWarning("indices == null -> VerticesInWorldSpace");
            }

            Vector3[] worldPoints = pb.GetVertices(indices);

            for (int i = 0; i < worldPoints.Length; i++)
            {
                worldPoints[i] = pb.transform.TransformPoint(worldPoints[i]);
            }

            return(worldPoints);
        }
Ejemplo n.º 7
0
        /**
         * Projects UVs for each face using the closest normal on a box.
         */
        public static void ProjectFacesBox(pb_Object pb, pb_Face[] faces)
        {
            Vector2[] uv = pb.uv;

            Dictionary <ProjectionAxis, List <pb_Face> > sorted = new Dictionary <ProjectionAxis, List <pb_Face> >();

            for (int i = 0; i < faces.Length; i++)
            {
                Vector3        nrm  = pb_Math.Normal(pb, faces[i]);
                ProjectionAxis axis = pb_Math.VectorToProjectionAxis(nrm);

                if (sorted.ContainsKey(axis))
                {
                    sorted[axis].Add(faces[i]);
                }
                else
                {
                    sorted.Add(axis, new List <pb_Face>()
                    {
                        faces[i]
                    });
                }

                // clean up UV stuff - no shared UV indices and remove element group
                faces[i].elementGroup = -1;
            }

            foreach (KeyValuePair <ProjectionAxis, List <pb_Face> > kvp in sorted)
            {
                int[] distinct = pb_Face.AllTrianglesDistinct(kvp.Value.ToArray());

                Vector2[] uvs = pb_Math.PlanarProject(pb.GetVertices(distinct), pb_Math.ProjectionAxisToVector(kvp.Key), kvp.Key);

                for (int n = 0; n < distinct.Length; n++)
                {
                    uv[distinct[n]] = uvs[n];
                }

                SplitUVs(pb, distinct);
            }

            /* and set the msh uv array using the new coordintaes */
            pb.SetUV(uv);

            pb.ToMesh();
            pb.Refresh();
        }
Ejemplo n.º 8
0
        /**
         * Attempt to figure out the winding order the passed face.  Note that
         * this may return WindingOrder.Unknown.
         */
        public static WindingOrder GetWindingOrder(this pb_Object pb, pb_Face face)
        {
            Vector2[] p = pb_Math.PlanarProject(pb.GetVertices(face.edges.AllTriangles()), pb_Math.Normal(pb, face));

            float sum = 0f;

            // http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
            for (int i = 0; i < p.Length; i++)
            {
                Vector2 a = p[i];
                Vector2 b = i < p.Length - 1 ? p[i + 1] : p[0];

                sum += ((b.x - a.x) * (b.y + a.y));
            }

            return(sum == 0f ? WindingOrder.Unknown : (sum >= 0f ? WindingOrder.Clockwise : WindingOrder.CounterClockwise));
        }
	/**
	 *	Inserts a split from each selected vertex to the center of the face
	 */
	private static bool PokeFace_Internal(pb_Object pb, pb_Face face, int[] indices_nonFaceSpecific,
		out pb_Face[] splitFaces,
		out Vector3[][] splitVertices,
		out int[][] splitSharedIndices)
	{
		splitFaces = null;
		splitVertices = null;
		splitSharedIndices = null;

		pb_IntArray[] sharedIndices = pb.sharedIndices;

		///** Sort index array such that it only uses indices local to the passed face
		int[] indices = new int[indices_nonFaceSpecific.Length];
		int[] dist_ind_si = new int[face.distinctIndices.Length];

		// figure out sharedIndices index of distinct Indices
		for(int i = 0; i < face.distinctIndices.Length; i++)
			dist_ind_si[i] = sharedIndices.IndexOf(face.distinctIndices[i]);

		// now do the same for non-face specific indices, assigning matching groups
		for(int i = 0; i < indices.Length; i++)
		{
			int ind = System.Array.IndexOf(dist_ind_si, sharedIndices.IndexOf(indices_nonFaceSpecific[i]));
			if(ind < 0) return false;

			indices[i] = face.distinctIndices[ind];
		}
		///** Sort index array such that it only uses indices local to the passed face

		Vector3 cen3d = pb_Math.Average(pb.GetVertices(face));
		
		Vector3[] verts 	= pb.GetVertices(face.distinctIndices);
		Vector3 nrm 		= pb_Math.Normal(pb.GetVertices(face.indices));
		Vector2[] plane 	= pb_Math.VerticesTo2DPoints(verts, nrm);
		Vector2[] indPlane 	= pb_Math.VerticesTo2DPoints(pb.GetVertices(indices), nrm);
		Vector2 cen2d 		= pb_Math.VerticesTo2DPoints( new Vector3[1] { cen3d }, nrm)[0];

		// Get the directions from which to segment this face
		Vector2[] dividers = new Vector2[indices.Length];
		for(int i = 0; i < indices.Length; i++)
			dividers[i] = (indPlane[i] - cen2d).normalized;

		List<Vector2>[] quadrants2d = new List<Vector2>[indices.Length];
		List<Vector3>[] quadrants3d = new List<Vector3>[indices.Length];
		List<int>[]		sharedIndex = new List<int>[indices.Length];

		for(int i = 0; i < quadrants2d.Length; i++)
		{
			quadrants2d[i] = new List<Vector2>(1) { cen2d };
			quadrants3d[i] = new List<Vector3>(1) { cen3d };
			sharedIndex[i] = new List<int>(1) { -2 };		// any negative value less than -1 will be treated as a new group
		}

		for(int i = 0; i < face.distinctIndices.Length; i++)
		{
			// if this index is a divider, it needs to belong to the leftmost and 
			// rightmost quadrant
			int indexInPokeVerts = System.Array.IndexOf(indices, face.distinctIndices[i]);
			int ignore = -1;
			if( indexInPokeVerts > -1)
			{	
				// Add vert to this quadrant
				quadrants2d[indexInPokeVerts].Add(plane[i]);
				quadrants3d[indexInPokeVerts].Add(verts[i]);
				sharedIndex[indexInPokeVerts].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));

				// And also the one closest counter clockwise
				ignore = indexInPokeVerts;
			}

			Vector2 dir = (plane[i]-cen2d).normalized;	// plane corresponds to distinctIndices
			float largestClockwiseDistance = 0f;
			int quad = -1;
			for(int j = 0; j < dividers.Length; j++)
			{
				if(j == ignore) continue;	// this is a dividing vertex - ignore

				float dist = Vector2.Angle(dividers[j], dir);
				if( Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f )
					dist = 360f - dist;

				if(dist > largestClockwiseDistance)
				{
					largestClockwiseDistance = dist;
					quad = j;
				}
			}

			quadrants2d[quad].Add(plane[i]);
			quadrants3d[quad].Add(verts[i]);
			sharedIndex[quad].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));
		}

		int len = quadrants2d.Length;

		// Triangulate
		int[][] tris = new int[len][];
		for(int i = 0; i < len; i++)
		{
			tris[i] = Delauney.Triangulate(quadrants2d[i]).ToIntArray();
			
			if(tris[i].Length < 3)
				return false;

			// todo - check that face normal is correct
		}

		splitFaces 		= new pb_Face[len];
		splitVertices 	= new Vector3[len][];
		splitSharedIndices 	= new int[len][];

		for(int i = 0; i < len; i++)
		{
			// triangles, material, pb_UV, smoothing group, shared index
			splitFaces[i] = new pb_Face(tris[i], face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, -1, face.color);
			splitVertices[i] = quadrants3d[i].ToArray();
			splitSharedIndices[i] = sharedIndex[i].ToArray();
		}

		return true;
	}
Ejemplo n.º 10
0
		void DrawStats(pb_Object pb)
		{
			StringBuilder sb = new StringBuilder();

			Handles.BeginGUI();

			if(edgeInfo)
			foreach(pb_Edge f in pb.SelectedEdges)
			{
				Vector2 cen = HandleUtility.WorldToGUIPoint( pb.transform.TransformPoint((pb.vertices[f.x] + pb.vertices[f.y])/ 2f) );
				GUIContent gc = new GUIContent(f.ToString(), "");
				DrawSceneLabel(gc, cen);
			}

			/**
			 * SHARED INDICES
			 */
			// foreach(pb_IntArray arr in pb.sharedIndices)
			// {
			// 	Vector2 cen = HandleUtility.WorldToGUIPoint( pb.transform.TransformPoint(pb.vertices[arr[0]]) );
							
			// 	GUI.Label(new Rect(cen.x, cen.y, 200, 200), ((int[])arr).ToFormattedString("\n"));
			// }

			if(faceInfo)
			foreach(pb_Face f in pb.SelectedFaces)
			{
				Vector2 cen = HandleUtility.WorldToGUIPoint( pb.transform.TransformPoint( pb_Math.Average( pb.GetVertices(f.distinctIndices) ) ) );
				
				GUIContent gc = new GUIContent("Face: " + f.ToString(), "");

				if(smoothingGroupInfo || elementGroupInfo || textureGroupInfo)
					gc.text += "\nGroups:";

				if(smoothingGroupInfo)
					gc.text += "\nSmoothing: " + f.smoothingGroup;
				if(elementGroupInfo)
					gc.text += "\nElement: " + f.elementGroup;
				if(textureGroupInfo)
					gc.text += "\nTexture: " + f.textureGroup;

				DrawSceneLabel(gc, cen);
			}

			// sb.AppendLine(f.ToString() + ", ");


			// foreach(pb_Face face in pb.SelectedFaces)
			// 	sb.AppendLine(face.colors.ToFormattedString("\n") + "\n");

			// sb.AppendLine("\n");

			// foreach(pb_IntArray si in pb.sharedIndices)
			// {
			// 	sb.AppendLine(si.array.ToFormattedString(", "));
			// }

			// sb.AppendLine("\n");

			// if(vertexInfo)
			// {
			// 	try
			// 	{
			// 		Camera cam = SceneView.lastActiveSceneView.camera;
			// 		Vector3[] normals = pb.msh.normals;
			// 		int index = 0;
			// 		foreach(pb_IntArray arr in pb.sharedIndices)
			// 		{
			// 			Vector3 v = pb.transform.TransformPoint(pb.vertices[arr[0]] + normals[arr[0]] * .01f);

			// 			if(!pb_HandleUtility.PointIsOccluded(cam, pb, v))
			// 			{
			// 				Vector2 cen = HandleUtility.WorldToGUIPoint( v );
							
			// 				GUIContent gc = new GUIContent(index++ + ": " + arr.array.ToFormattedString(", "), "");

			// 				DrawSceneLabel(gc, cen);
			// 			}
			// 		}
			// 	} catch { /* do not care */; }
			// }

			Handles.EndGUI();

			Handles.BeginGUI();
			{
				GUI.Label(new Rect(10, 10, 400, 800), sb.ToString());
			}
			Handles.EndGUI();
		}
Ejemplo n.º 11
0
        // todo - there's a lot of duplicate code between this and poke face.

        /**
         *	Inserts a vertex at the center of each edge, then connects the new vertices to another new
         *	vertex placed at the center of the face.
         */
        // internal method - so it's allow to be messy, right?
        private static bool SubdivideFace_Internal(pb_Object pb, EdgeConnection edgeConnection,
                                                   out Vector3?[] appendedVertices,
                                                   out pb_Face[] splitFaces,
                                                   out Vector3[][] splitVertices,
                                                   out int[][] splitSharedIndices)
        {
            splitFaces         = null;
            splitVertices      = null;
            splitSharedIndices = null;
            appendedVertices   = new Vector3?[edgeConnection.edges.Count];

            // cache all the things
            pb_Face face = edgeConnection.face;

            pb_IntArray[] sharedIndices = pb.sharedIndices;
            Vector3[]     vertices      = pb.vertices;

            List <Vector3> edgeCenters3d = new List <Vector3>();  //pb.GetVertices(edgeConnection.face));

            // filter duplicate edges
            int        u = 0;
            List <int> usedEdgeIndices = new List <int>();

            foreach (pb_Edge edge in edgeConnection.edges)
            {
                int ind = face.edges.IndexOf(edge, sharedIndices);
                if (!usedEdgeIndices.Contains(ind))
                {
                    Vector3 cen = (vertices[edge.x] + vertices[edge.y]) / 2f;
                    edgeCenters3d.Add(cen);
                    usedEdgeIndices.Add(ind);
                    appendedVertices[u] = cen;
                }
                else
                {
                    appendedVertices[u] = null;
                }

                u++;
            }

            // now we have all the vertices of the old face, plus the new edge center vertices

            Vector3[] verts3d = pb.GetVertices(face.distinctIndices);
            Vector3   nrm     = pb_Math.Normal(pb.GetVertices(face.indices));

            Vector2[] verts2d       = pb_Math.VerticesTo2DPoints(verts3d, nrm);
            Vector2[] edgeCenters2d = pb_Math.VerticesTo2DPoints(edgeCenters3d.ToArray(), nrm);

            Vector3 cen3d = pb_Math.Average(verts3d);
            Vector2 cen2d = pb_Math.VerticesTo2DPoints(new Vector3[1] {
                cen3d
            }, nrm)[0];

            // Get the directions from which to segment this face
            Vector2[] dividers = new Vector2[edgeCenters2d.Length];
            for (int i = 0; i < edgeCenters2d.Length; i++)
            {
                dividers[i] = (edgeCenters2d[i] - cen2d).normalized;
            }

            List <Vector2>[] quadrants2d = new List <Vector2> [edgeCenters2d.Length];
            List <Vector3>[] quadrants3d = new List <Vector3> [edgeCenters2d.Length];
            List <int>[]     sharedIndex = new List <int> [edgeCenters2d.Length];

            for (int i = 0; i < quadrants2d.Length; i++)
            {
                quadrants2d[i] = new List <Vector2>(1)
                {
                    cen2d
                };
                quadrants3d[i] = new List <Vector3>(1)
                {
                    cen3d
                };
                sharedIndex[i] = new List <int>(1)
                {
                    -2
                };                                                              // any negative value less than -1 will be treated as a new group
            }

            // add the divisors
            for (int i = 0; i < edgeCenters2d.Length; i++)
            {
                quadrants2d[i].Add(edgeCenters2d[i]);
                quadrants3d[i].Add(edgeCenters3d[i]);
                sharedIndex[i].Add(-1);         // -(i+2) to group new vertices in AppendFace

                // and add closest in the counterclockwise direction
                Vector2 dir = (edgeCenters2d[i] - cen2d).normalized;
                float   largestClockwiseDistance = 0f;
                int     quad = -1;
                for (int j = 0; j < dividers.Length; j++)
                {
                    if (j == i)
                    {
                        continue;                       // this is a dividing vertex - ignore
                    }
                    float dist = Vector2.Angle(dividers[j], dir);
                    if (Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f)
                    {
                        dist = 360f - dist;
                    }

                    if (dist > largestClockwiseDistance)
                    {
                        largestClockwiseDistance = dist;
                        quad = j;
                    }
                }

                quadrants2d[quad].Add(edgeCenters2d[i]);
                quadrants3d[quad].Add(edgeCenters3d[i]);
                sharedIndex[quad].Add(-1);
            }

            // distribute the existing vertices
            for (int i = 0; i < face.distinctIndices.Length; i++)
            {
                Vector2 dir = (verts2d[i] - cen2d).normalized;          // plane corresponds to distinctIndices
                float   largestClockwiseDistance = 0f;
                int     quad = -1;
                for (int j = 0; j < dividers.Length; j++)
                {
                    float dist = Vector2.Angle(dividers[j], dir);
                    if (Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f)
                    {
                        dist = 360f - dist;
                    }

                    if (dist > largestClockwiseDistance)
                    {
                        largestClockwiseDistance = dist;
                        quad = j;
                    }
                }

                quadrants2d[quad].Add(verts2d[i]);
                quadrants3d[quad].Add(verts3d[i]);
                sharedIndex[quad].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));
            }

            int len = quadrants2d.Length;

            // Triangulate
            int[][] tris = new int[len][];
            for (int i = 0; i < len; i++)
            {
                if (quadrants2d[i].Count < 3)
                {
                    Debug.LogError("Insufficient points to triangulate - bailing on subdivide operation.  This is probably due to a concave face, or maybe the compiler just doesn't like you today.  50/50 odds really.");
                    return(false);
                }

                tris[i] = Delauney.Triangulate(quadrants2d[i]).ToIntArray();

                Vector3[] nrm_check = new Vector3[3]
                {
                    quadrants3d[i][tris[i][0]],
                    quadrants3d[i][tris[i][1]],
                    quadrants3d[i][tris[i][2]]
                };

                if (Vector3.Dot(nrm, pb_Math.Normal(nrm_check)) < 0)
                {
                    System.Array.Reverse(tris[i]);
                }
            }

            splitFaces         = new pb_Face[len];
            splitVertices      = new Vector3[len][];
            splitSharedIndices = new int[len][];

            for (int i = 0; i < len; i++)
            {
                // triangles, material, pb_UV, smoothing group, shared index
                splitFaces[i]         = new pb_Face(tris[i], face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.color);
                splitVertices[i]      = quadrants3d[i].ToArray();
                splitSharedIndices[i] = sharedIndex[i].ToArray();
            }

            return(true);
        }
	// todo - there's a lot of duplicate code between this and poke face.
	/**
	 *	Inserts a vertex at the center of each edge, then connects the new vertices to another new
	 *	vertex placed at the center of the face.
	 */
	// internal method - so it's allow to be messy, right?
	private static bool SubdivideFace_Internal(pb_Object pb, EdgeConnection edgeConnection, 
		out Vector3?[] appendedVertices,	
		out pb_Face[] splitFaces,
		out Vector3[][] splitVertices,
		out int[][] splitSharedIndices)
	{
		splitFaces = null;
		splitVertices = null;
		splitSharedIndices = null;
		appendedVertices = new Vector3?[edgeConnection.edges.Count];

		// cache all the things
		pb_Face face = edgeConnection.face;
		pb_IntArray[] sharedIndices = pb.sharedIndices;
		Vector3[] vertices = pb.vertices;

		List<Vector3> edgeCenters3d = new List<Vector3>();//pb.GetVertices(edgeConnection.face));
		
		// filter duplicate edges
		int u = 0;
		List<int> usedEdgeIndices = new List<int>();
		foreach(pb_Edge edge in edgeConnection.edges)
		{
			int ind = face.edges.IndexOf(edge, sharedIndices);
			if(!usedEdgeIndices.Contains(ind))
			{
				Vector3 cen = (vertices[edge.x] + vertices[edge.y]) / 2f;
				edgeCenters3d.Add(cen);
				usedEdgeIndices.Add(ind);
				appendedVertices[u] = cen;
			}
			else
				appendedVertices[u] = null;

			u++;
		}

		// now we have all the vertices of the old face, plus the new edge center vertices

		Vector3[] verts3d = pb.GetVertices(face.distinctIndices);
		Vector3 nrm = pb_Math.Normal(pb.GetVertices(face.indices));

		Vector2[] verts2d = pb_Math.VerticesTo2DPoints(verts3d, nrm);
		Vector2[] edgeCenters2d = pb_Math.VerticesTo2DPoints(edgeCenters3d.ToArray(), nrm);
		
		Vector3 cen3d = pb_Math.Average(verts3d);
		Vector2 cen2d = pb_Math.VerticesTo2DPoints( new Vector3[1] { cen3d }, nrm)[0];

		// Get the directions from which to segment this face
		Vector2[] dividers = new Vector2[edgeCenters2d.Length];
		for(int i = 0; i < edgeCenters2d.Length; i++)
			dividers[i] = (edgeCenters2d[i] - cen2d).normalized;

		List<Vector2>[] quadrants2d = new List<Vector2>[edgeCenters2d.Length];
		List<Vector3>[] quadrants3d = new List<Vector3>[edgeCenters2d.Length];
		List<int>[]		sharedIndex = new List<int>[edgeCenters2d.Length];

		for(int i = 0; i < quadrants2d.Length; i++)
		{
			quadrants2d[i] = new List<Vector2>(1) { cen2d };
			quadrants3d[i] = new List<Vector3>(1) { cen3d };
			sharedIndex[i] = new List<int>(1) { -2 };		// any negative value less than -1 will be treated as a new group
		}

		// add the divisors
		for(int i = 0; i < edgeCenters2d.Length; i++)
		{
			quadrants2d[i].Add(edgeCenters2d[i]);
			quadrants3d[i].Add(edgeCenters3d[i]);
			sharedIndex[i].Add(-1);	// -(i+2) to group new vertices in AppendFace

			// and add closest in the counterclockwise direction
			Vector2 dir = (edgeCenters2d[i]-cen2d).normalized;
			float largestClockwiseDistance = 0f;
			int quad = -1;
			for(int j = 0; j < dividers.Length; j++)
			{
				if(j == i) continue;	// this is a dividing vertex - ignore

				float dist = Vector2.Angle(dividers[j], dir);
				if( Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f )
					dist = 360f - dist;

				if(dist > largestClockwiseDistance)
				{
					largestClockwiseDistance = dist;
					quad = j;
				}
			}

			quadrants2d[quad].Add(edgeCenters2d[i]);
			quadrants3d[quad].Add(edgeCenters3d[i]);
			sharedIndex[quad].Add(-1);
		}

		// distribute the existing vertices
		for(int i = 0; i < face.distinctIndices.Length; i++)
		{
			Vector2 dir = (verts2d[i]-cen2d).normalized;	// plane corresponds to distinctIndices
			float largestClockwiseDistance = 0f;
			int quad = -1;
			for(int j = 0; j < dividers.Length; j++)
			{
				float dist = Vector2.Angle(dividers[j], dir);
				if( Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f )
					dist = 360f - dist;

				if(dist > largestClockwiseDistance)
				{
					largestClockwiseDistance = dist;
					quad = j;
				}
			}

			quadrants2d[quad].Add(verts2d[i]);
			quadrants3d[quad].Add(verts3d[i]);
			sharedIndex[quad].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));
		}

		int len = quadrants2d.Length;

		// Triangulate
		int[][] tris = new int[len][];
		for(int i = 0; i < len; i++)
		{
			if(quadrants2d[i].Count < 3)
			{
				Debug.LogError("Insufficient points to triangulate - bailing on subdivide operation.  This is probably due to a concave face, or maybe the compiler just doesn't like you today.  50/50 odds really.");
				return false;
			}
		
			tris[i] = Delauney.Triangulate(quadrants2d[i]).ToIntArray();
			
			Vector3[] nrm_check = new Vector3[3]
			{
				quadrants3d[i][tris[i][0]],
				quadrants3d[i][tris[i][1]],
				quadrants3d[i][tris[i][2]]
			};

			if( Vector3.Dot(nrm, pb_Math.Normal(nrm_check)) < 0 )
				System.Array.Reverse(tris[i]);
		}

		splitFaces 		= new pb_Face[len];
		splitVertices 	= new Vector3[len][];
		splitSharedIndices 	= new int[len][];

		for(int i = 0; i < len; i++)
		{
			// triangles, material, pb_UV, smoothing group, shared index
			splitFaces[i] = new pb_Face(tris[i], face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.color);
			splitVertices[i] = quadrants3d[i].ToArray();
			splitSharedIndices[i] = sharedIndex[i].ToArray();
		}

		return true;
	}
Ejemplo n.º 13
0
        /**
         * Attempts to insert new edges connecting the center of all passed edges.
         */
        public static bool ConnectEdges(this pb_Object pb, pb_Edge[] edges, out pb_Edge[] newEdges)
        {
            // pb_Profiler profiler = new pb_Profiler();

            // profiler.BeginSample("Con nectEdges");

            int len = edges.Length;
            List <pb_EdgeConnection> splits = new List <pb_EdgeConnection>();
            Dictionary <int, int>    lookup = pb.sharedIndices.ToDictionary();

            // profiler.BeginSample("Split Edges");
            for (int i = 0; i < len; i++)
            {
                List <pb_Face> neighbors = pbMeshUtils.GetNeighborFaces(pb, edges[i]);

                foreach (pb_Face face in neighbors)
                {
                    if (!splits.Contains((pb_EdgeConnection)face))
                    {
                        List <pb_Edge> faceEdges = new List <pb_Edge>();
                        foreach (pb_Edge e in edges)
                        {
                            int localEdgeIndex = face.edges.IndexOf(e, lookup);
                            if (localEdgeIndex > -1)
                            {
                                faceEdges.Add(face.edges[localEdgeIndex]);
                            }
                        }

                        if (faceEdges.Count > 1)
                        {
                            splits.Add(new pb_EdgeConnection(face, faceEdges));
                        }
                    }
                }
            }
            // profiler.EndSample();

            Vector3[] vertices = pb.GetVertices(pb_EdgeConnection.AllTriangles(splits).Distinct().ToArray());


            pb_Face[] faces;
            bool      success = ConnectEdges(pb, splits, out faces);

            // profiler.BeginSample("Find New Edges");
            if (success)
            {
                /**
                 * Get the newly created Edges so that we can return them.
                 */
                List <pb_Edge> nedges = new List <pb_Edge>();

                for (int i = 0; i < faces.Length; i++)
                {
                    for (int n = 0; n < faces[i].edges.Length; n++)
                    {
                        if (pb_Math.ContainsApprox(vertices, pb.vertices[faces[i].edges[n].x], .001f) ||
                            pb_Math.ContainsApprox(vertices, pb.vertices[faces[i].edges[n].y], .001f))
                        {
                            continue;
                        }
                        else
                        {
                            nedges.Add(faces[i].edges[n]);
                        }
                    }
                }
                newEdges = nedges.ToArray();
            }
            else
            {
                newEdges = null;
            }
            // profiler.EndSample();

            // profiler.EndSample();
            // Debug.Log(profiler.ToString());

            return(success);
        }
Ejemplo n.º 14
0
        /**
         *	Inserts a vertex at the center of each edge, then connects the new vertices to another new
         *	vertex placed at the center of the face.
         */
        private static bool SubdivideFace_Internal(pb_Object pb, pb_EdgeConnection pb_edgeConnection,
                                                   out DanglingVertex?[] appendedVertices,
                                                   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;
            appendedVertices   = new DanglingVertex?[pb_edgeConnection.edges.Count];

            // cache all the things
            pb_Face face = pb_edgeConnection.face;
            Dictionary <int, int> sharedIndices = pb.sharedIndices.ToDictionary();

            Vector3[] vertices = pb.vertices;
            Vector2[] uvs      = pb.uv;

            List <Vector2> edgeCentersUV  = new List <Vector2>();
            List <Vector3> edgeCenters3d  = new List <Vector3>();
            List <Color>   edgeCentersCol = new List <Color>();

            // filter duplicate edges
            int        u = 0;
            List <int> usedEdgeIndices = new List <int>();

            foreach (pb_Edge edge in pb_edgeConnection.edges)
            {
                int ind = face.edges.IndexOf(edge, sharedIndices);
                if (!usedEdgeIndices.Contains(ind))
                {
                    Vector3 cen = (vertices[edge.x] + vertices[edge.y]) / 2f;

                    appendedVertices[u] = new DanglingVertex(cen, (pb.colors[edge.x] + pb.colors[edge.y]) / 2f);

                    edgeCenters3d.Add(cen);
                    edgeCentersUV.Add((uvs[edge.x] + uvs[edge.y]) / 2f);
                    edgeCentersCol.Add((pb.colors[edge.x] + pb.colors[edge.y]) / 2f);

                    usedEdgeIndices.Add(ind);
                }
                else
                {
                    appendedVertices[u] = null;
                }

                u++;
            }

            // now we have all the vertices of the old face, plus the new edge center vertices
            Vector3 nrm = pb_Math.Normal(pb.GetVertices(face.indices));

            Vector3[] verts3d = pb.GetVertices(face.distinctIndices);
            Vector2[] faceUVs = pb.GetUVs(face.distinctIndices);
            Color[]   colors  = pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices);

            Vector2[] verts2d       = pb_Math.PlanarProject(verts3d, nrm);
            Vector2[] edgeCenters2d = pb_Math.PlanarProject(edgeCenters3d.ToArray(), nrm);

            Vector3 cen3d = pb_Math.Average(verts3d);
            Vector2 cenUV = pb_Bounds2D.Center(faceUVs);

            Vector2 cen2d = pb_Math.PlanarProject(new Vector3[1] {
                cen3d
            }, nrm)[0];

            // Get the directions from which to segment this face
            Vector2[] dividers = new Vector2[edgeCenters2d.Length];
            for (int i = 0; i < edgeCenters2d.Length; i++)
            {
                dividers[i] = (edgeCenters2d[i] - cen2d).normalized;
            }

            List <Vector2>[] quadrants2d  = new List <Vector2> [edgeCenters2d.Length];
            List <Vector3>[] quadrants3d  = new List <Vector3> [edgeCenters2d.Length];
            List <Vector2>[] quadrantsUV  = new List <Vector2> [edgeCenters2d.Length];
            List <Color>[]   quadrantsCol = new List <Color> [edgeCenters2d.Length];

            List <int>[] sharedIndex = new List <int> [edgeCenters2d.Length];

            for (int i = 0; i < quadrants2d.Length; i++)
            {
                quadrants2d[i] = new List <Vector2>(1)
                {
                    cen2d
                };
                quadrants3d[i] = new List <Vector3>(1)
                {
                    cen3d
                };
                quadrantsUV[i] = new List <Vector2>(1)
                {
                    cenUV
                };
                quadrantsCol[i] = new List <Color>(1)
                {
                    pb_Math.Average(pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices))
                };

                sharedIndex[i] = new List <int>(1)
                {
                    -2
                };                                                              // any negative value less than -1 will be treated as a new group
            }

            // add the divisors
            for (int i = 0; i < edgeCenters2d.Length; i++)
            {
                quadrants2d[i].Add(edgeCenters2d[i]);
                quadrants3d[i].Add(edgeCenters3d[i]);
                quadrantsUV[i].Add(edgeCentersUV[i]);
                quadrantsCol[i].Add(edgeCentersCol[i]);

                sharedIndex[i].Add(-1);

                // and add closest in the counterclockwise direction
                Vector2 dir = (edgeCenters2d[i] - cen2d).normalized;
                float   largestClockwiseDistance = 0f;
                int     quad = -1;
                for (int j = 0; j < dividers.Length; j++)
                {
                    if (j == i)
                    {
                        continue;                       // this is a dividing vertex - ignore
                    }
                    float dist = Vector2.Angle(dividers[j], dir);
                    if (Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f)
                    {
                        dist = 360f - dist;
                    }

                    if (dist > largestClockwiseDistance)
                    {
                        largestClockwiseDistance = dist;
                        quad = j;
                    }
                }

                quadrants2d[quad].Add(edgeCenters2d[i]);
                quadrants3d[quad].Add(edgeCenters3d[i]);
                quadrantsUV[quad].Add(edgeCentersUV[i]);
                quadrantsCol[quad].Add(edgeCentersCol[i]);

                sharedIndex[quad].Add(-1);
            }

            // distribute the existing vertices
            for (int i = 0; i < face.distinctIndices.Length; i++)
            {
                Vector2 dir = (verts2d[i] - cen2d).normalized;          // plane corresponds to distinctIndices
                float   largestClockwiseDistance = 0f;
                int     quad = -1;
                for (int j = 0; j < dividers.Length; j++)
                {
                    float dist = Vector2.Angle(dividers[j], dir);
                    if (Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f)
                    {
                        dist = 360f - dist;
                    }

                    if (dist > largestClockwiseDistance)
                    {
                        largestClockwiseDistance = dist;
                        quad = j;
                    }
                }

                quadrants2d[quad].Add(verts2d[i]);
                quadrants3d[quad].Add(verts3d[i]);
                quadrantsUV[quad].Add(faceUVs[i]);
                quadrantsCol[quad].Add(colors[i]);

                sharedIndex[quad].Add(sharedIndices[face.distinctIndices[i]]);
            }

            int len = quadrants2d.Length;

            // Triangulate
            int[][] tris = new int[len][];
            for (int i = 0; i < len; i++)
            {
                if (quadrants2d[i].Count < 3)
                {
                    Debug.LogError("Insufficient points to triangulate.  Exit subdivide operation.  This is probably due to a concave face.");
                    return(false);
                }

                tris[i] = Delaunay.Triangulate(quadrants2d[i]).ToIntArray();

                if (tris[i].Length < 3)         ///< #521
                {
                    return(false);
                }

                if (Vector3.Dot(nrm, pb_Math.Normal(quadrants3d[i][tris[i][0]], quadrants3d[i][tris[i][1]], quadrants3d[i][tris[i][2]])) < 0)
                {
                    System.Array.Reverse(tris[i]);
                }
            }

            splitFaces         = new pb_Face[len];
            splitVertices      = new Vector3[len][];
            splitColors        = new Color[len][];
            splitUVs           = new Vector2[len][];
            splitSharedIndices = new int[len][];

            for (int i = 0; i < len; i++)
            {
                // triangles, material, pb_UV, smoothing group, shared index
                splitFaces[i]    = new pb_Face(tris[i], face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.manualUV);
                splitVertices[i] = quadrants3d[i].ToArray();
                splitColors[i]   = quadrantsCol[i].ToArray();
                splitUVs[i]      = quadrantsUV[i].ToArray();

                splitSharedIndices[i] = sharedIndex[i].ToArray();
            }

            return(true);
        }
Ejemplo n.º 15
0
        /**
         *	Splits face per vertex.
         *	Todo - Could implement more sanity checks - namely testing for edges before sending to Split_Internal.  However,
         *	the split method is smart enough to fail on those cases, so ignore for now.
         */
        public static bool ConnectVertices(this pb_Object pb, List <pb_VertexConnection> vertexConnectionsUnfiltered, out int[] triangles)
        {
            List <pb_VertexConnection> vertexConnections = new List <pb_VertexConnection>();
            List <int> inds = new List <int>();

            int i = 0;

            for (i = 0; i < vertexConnectionsUnfiltered.Count; i++)
            {
                pb_VertexConnection vc = vertexConnectionsUnfiltered[i];
                vc.indices = vc.indices.Distinct().ToList();

                if (vc.isValid)
                {
                    inds.AddRange(vc.indices);
                    vertexConnections.Add(vc);
                }
            }

            if (vertexConnections.Count < 1)
            {
                triangles = null;
                return(false);
            }

            List <Vector3> selectedVertices = pb.GetVertices(pb_VertexConnection.AllTriangles(vertexConnections));

            int len = vertexConnections.Count;

            // new faces will be built from successfull split ops
            List <pb_Face> successfullySplitFaces = new List <pb_Face>();
            List <pb_Face> all_splitFaces         = new List <pb_Face>();

            List <Vector3[]> all_splitVertices = new List <Vector3[]>();
            List <Color[]>   all_splitColors   = new List <Color[]>();
            List <Vector2[]> all_splitUVs      = new List <Vector2[]>();

            List <int[]> all_splitSharedIndices = new List <int[]>();

            bool[] success = new bool[len];

            pb_IntArray[] sharedIndices = pb.sharedIndices;

            i = 0;
            foreach (pb_VertexConnection vc in vertexConnections)
            {
                pb_Face[]   splitFaces    = null;
                Vector3[][] splitVertices = null;
                Color[][]   splitColors   = null;
                Vector2[][] splitUVs;
                int[][]     splitSharedIndices = null;

                if (vc.indices.Count < 3)
                {
                    int indA = vc.face.indices.IndexOf(vc.indices[0], sharedIndices);
                    int indB = vc.face.indices.IndexOf(vc.indices[1], sharedIndices);

                    if (indA < 0 || indB < 0)
                    {
                        success[i] = false;
                        continue;
                    }

                    indA = vc.face.indices[indA];
                    indB = vc.face.indices[indB];

                    success[i] = SplitFace_Internal(
                        new SplitSelection(pb, vc.face, pb.vertices[indA], pb.vertices[indB], pb.colors[indA], pb.colors[indB], true, true, new int[] { indA }, new int[] { indB }),
                        out splitFaces,
                        out splitVertices,
                        out splitColors,
                        out splitUVs,
                        out splitSharedIndices);

                    if (success[i])
                    {
                        successfullySplitFaces.Add(vc.face);
                    }
                }
                else
                {
                    Vector3 pokedVertex;

                    success[i] = PokeFace_Internal(pb, vc.face, vc.indices.ToArray(),
                                                   out pokedVertex,
                                                   out splitFaces,
                                                   out splitVertices,
                                                   out splitColors,
                                                   out splitUVs,
                                                   out splitSharedIndices);

                    if (success[i])
                    {
                        selectedVertices.Add(pokedVertex);
                        successfullySplitFaces.Add(vc.face);
                    }
                }

                if (success[i])
                {
                    int texGroup = pb.UnusedTextureGroup(i + 1);

                    for (int j = 0; j < splitFaces.Length; j++)
                    {
                        splitFaces[j].textureGroup = texGroup;

                        all_splitFaces.Add(splitFaces[j]);
                        all_splitVertices.Add(splitVertices[j]);
                        all_splitColors.Add(splitColors[j]);
                        all_splitUVs.Add(splitUVs[j]);

                        all_splitSharedIndices.Add(splitSharedIndices[j]);
                    }
                }

                i++;
            }

            if (all_splitFaces.Count < 1)
            {
                triangles = null;
                return(false);
            }

            pb_Face[] appendedFaces = pb.AppendFaces(all_splitVertices.ToArray(),
                                                     all_splitColors.ToArray(),
                                                     all_splitUVs.ToArray(),
                                                     all_splitFaces.ToArray(),
                                                     all_splitSharedIndices.ToArray());

            inds.AddRange(pb_Face.AllTriangles(appendedFaces));

            int[] welds;
            pb.WeldVertices(inds.ToArray(), Mathf.Epsilon, out welds);

            pb.DeleteFaces(successfullySplitFaces.ToArray());

            List <int> seltris = new List <int>();

            for (i = 0; i < selectedVertices.Count; i++)
            {
                int ind = System.Array.IndexOf(pb.vertices, selectedVertices[i]);
                if (ind > -1)
                {
                    seltris.Add(ind);
                }
            }

            triangles = seltris.Distinct().ToArray();
            return(true);
        }
Ejemplo n.º 16
0
        /**
         *	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);
        }
Ejemplo n.º 17
0
	/**
	 * Projects UVs for each face using the closest normal on a box.
	 */
	public  static void ProjectFacesBox(pb_Object pb, pb_Face[] faces)
	{
		Vector2[] uv = pb.uv;

		Dictionary<ProjectionAxis, List<pb_Face>> sorted = new Dictionary<ProjectionAxis, List<pb_Face>>();

		for(int i = 0; i < faces.Length; i++)
		{
			Vector3 nrm = pb_Math.Normal(pb, faces[i]);
			ProjectionAxis axis = pb_Math.VectorToProjectionAxis(nrm);

			if(sorted.ContainsKey(axis))
			{
				sorted[axis].Add(faces[i]);
			}
			else
			{
				sorted.Add(axis, new List<pb_Face>() { faces[i] });
			}

			// clean up UV stuff - no shared UV indices and remove element group
			faces[i].elementGroup = -1;
		}

		foreach(KeyValuePair<ProjectionAxis, List<pb_Face>> kvp in sorted)
		{
			int[] distinct = pb_Face.AllTrianglesDistinct(kvp.Value.ToArray());

			Vector2[] uvs = pb_Math.PlanarProject( pb.GetVertices(distinct), pb_Math.ProjectionAxisToVector(kvp.Key), kvp.Key );

			for(int n = 0; n < distinct.Length; n++)
				uv[distinct[n]] = uvs[n];
				
			SplitUVs(pb, distinct);
		}

		/* and set the msh uv array using the new coordintaes */
		pb.SetUV(uv);
		
		pb.ToMesh();
		pb.Refresh();
	}
Ejemplo n.º 18
0
        /**
         *	Inserts a split from each selected vertex to the center of the face
         */
        private static bool PokeFace_Internal(pb_Object pb, pb_Face face, int[] indices_nonFaceSpecific,
                                              out Vector3 pokedVertex,
                                              out pb_Face[] splitFaces,
                                              out Vector3[][] splitVertices,
                                              out Color[][] splitColors,
                                              out Vector2[][] splitUVs,
                                              out int[][] splitSharedIndices)
        {
            pokedVertex        = Vector3.zero;
            splitFaces         = null;
            splitVertices      = null;
            splitColors        = null;
            splitUVs           = null;
            splitSharedIndices = null;

            pb_IntArray[] sharedIndices = pb.sharedIndices;

            ///** Sort index array such that it only uses indices local to the passed face
            int[] dist_indices = new int[indices_nonFaceSpecific.Length];
            int[] dist_ind_si  = new int[face.distinctIndices.Length];

            // figure out sharedIndices index of distinct Indices
            for (int i = 0; i < face.distinctIndices.Length; i++)
            {
                dist_ind_si[i] = sharedIndices.IndexOf(face.distinctIndices[i]);
            }

            // now do the same for non-face specific indices, assigning matching groups

            ///** Sort index array such that it only uses indices local to the passed face
            for (int i = 0; i < dist_indices.Length; i++)
            {
                int ind = System.Array.IndexOf(dist_ind_si, sharedIndices.IndexOf(indices_nonFaceSpecific[i]));
                if (ind < 0)
                {
                    return(false);
                }

                dist_indices[i] = face.distinctIndices[ind];
            }

            int[] indices = dist_indices.Distinct().ToArray();

            // throw out splits with less than 2 vertices, or splits composed
            // of a single edge
            switch (indices.Length)
            {
            case 0:
            case 1:
                return(false);

            case 2:
                if (System.Array.IndexOf(face.edges, new pb_Edge(indices[0], indices[1])) > -1)
                {
                    return(false);
                }
                break;

            default:
                break;
            }

            // end triangle sorting

            /**
             *	The general idea here is to project the face into 2d space,
             *	split the 2d points into groups based on the intersecting lines,
             *	then triangulate those groups.  once the groups have been
             *	triangulated, rebuild the 3d vertices using the new groups
             *	(building new verts for seams).
             *
             *	Think like you're cutting a pie... but first the pie is a basketball,
             *	then a pie, then a basketball again.  I'm on a horse.
             */

            Vector3[] verts  = pb.GetVertices(face.distinctIndices);
            Vector2[] uvs    = pb.GetUVs(face.distinctIndices);
            Color[]   colors = pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices);

            Vector2 cenUV = pb_Bounds2D.Center(uvs);
            Vector3 cen3d = pb_Math.Average(verts);

            pokedVertex = cen3d;
            Vector3 nrm      = pb_Math.Normal(pb.GetVertices(face.indices));
            Color   cenColor = pb_Math.Average(colors);

            // this should be cleaned up
            Vector2[] plane    = pb_Math.PlanarProject(verts, nrm);
            Vector2[] indPlane = pb_Math.PlanarProject(pb.GetVertices(indices), nrm);
            Vector2   cen2d    = pb_Math.PlanarProject(new Vector3[1] {
                cen3d
            }, nrm)[0];

            // Get the directions from which to segment this face
            Vector2[] dividers = new Vector2[indices.Length];
            for (int i = 0; i < indices.Length; i++)
            {
                dividers[i] = (indPlane[i] - cen2d).normalized;
            }

            List <Vector2>[] quadrants2d    = new List <Vector2> [indices.Length];
            List <Vector3>[] quadrants3d    = new List <Vector3> [indices.Length];
            List <Vector2>[] quadrantsUV_2d = new List <Vector2> [indices.Length];
            List <Color>[]   quadrantsCol   = new List <Color> [indices.Length];

            List <int>[] sharedIndex = new List <int> [indices.Length];

            for (int i = 0; i < quadrants2d.Length; i++)
            {
                quadrants2d[i] = new List <Vector2>(1)
                {
                    cen2d
                };
                quadrants3d[i] = new List <Vector3>(1)
                {
                    cen3d
                };
                quadrantsUV_2d[i] = new List <Vector2>(1)
                {
                    cenUV
                };
                quadrantsCol[i] = new List <Color>(1)
                {
                    cenColor
                };

                sharedIndex[i] = new List <int>(1)
                {
                    -2
                };                                                              // any negative value less than -1 will be treated as a new group
            }

            for (int i = 0; i < face.distinctIndices.Length; i++)
            {
                // if this index is a divider, it needs to belong to the leftmost and
                // rightmost quadrant
                int indexInPokeVerts = System.Array.IndexOf(indices, face.distinctIndices[i]);
                int ignore           = -1;
                if (indexInPokeVerts > -1)
                {
                    // Add vert to this quadrant
                    quadrants2d[indexInPokeVerts].Add(plane[i]);
                    quadrants3d[indexInPokeVerts].Add(verts[i]);
                    quadrantsUV_2d[indexInPokeVerts].Add(uvs[i]);
                    quadrantsCol[indexInPokeVerts].Add(colors[i]);

                    sharedIndex[indexInPokeVerts].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));

                    // And also the one closest counter clockwise
                    ignore = indexInPokeVerts;
                }

                Vector2 dir = (plane[i] - cen2d).normalized;            // plane corresponds to distinctIndices
                float   largestClockwiseDistance = 0f;
                int     quad = -1;
                for (int j = 0; j < dividers.Length; j++)
                {
                    if (j == ignore)
                    {
                        continue;                               // this is a dividing vertex - ignore
                    }
                    float dist = Vector2.Angle(dividers[j], dir);
                    if (Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f)
                    {
                        dist = 360f - dist;
                    }

                    if (dist > largestClockwiseDistance)
                    {
                        largestClockwiseDistance = dist;
                        quad = j;
                    }
                }

                quadrants2d[quad].Add(plane[i]);
                quadrants3d[quad].Add(verts[i]);
                quadrantsUV_2d[quad].Add(uvs[i]);
                quadrantsCol[quad].Add(colors[i]);

                sharedIndex[quad].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));
            }

            int len = quadrants2d.Length;

            // Triangulate
            int[][] tris = new int[len][];
            for (int i = 0; i < len; i++)
            {
                try {
                    tris[i] = Delaunay.Triangulate(quadrants2d[i]).ToIntArray();

                    if (tris[i] == null || tris[i].Length < 3)
                    {
                        Debug.Log("Fail triangulation");
                        return(false);
                    }
                } catch (System.Exception error) {
                    Debug.LogError("PokeFace internal failed triangulation. Bail!\n" + error);
                    return(false);
                }

                // todo - check that face normal is correct
            }

            splitFaces         = new pb_Face[len];
            splitVertices      = new Vector3[len][];
            splitColors        = new Color[len][];
            splitUVs           = new Vector2[len][];
            splitSharedIndices = new int[len][];

            for (int i = 0; i < len; i++)
            {
                // triangles, material, pb_UV, smoothing group, shared index
                splitFaces[i]    = new pb_Face(tris[i], face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, -1, face.manualUV);
                splitVertices[i] = quadrants3d[i].ToArray();
                splitColors[i]   = quadrantsCol[i].ToArray();
                splitUVs[i]      = quadrantsUV_2d[i].ToArray();

                splitSharedIndices[i] = sharedIndex[i].ToArray();
            }

            return(true);
        }
Ejemplo n.º 19
0
        /**
         *	Inserts a split from each selected vertex to the center of the face
         */
        private static bool PokeFace_Internal(pb_Object pb, pb_Face face, int[] indices_nonFaceSpecific,
                                              out pb_Face[] splitFaces,
                                              out Vector3[][] splitVertices,
                                              out int[][] splitSharedIndices)
        {
            splitFaces         = null;
            splitVertices      = null;
            splitSharedIndices = null;

            pb_IntArray[] sharedIndices = pb.sharedIndices;

            ///** Sort index array such that it only uses indices local to the passed face
            int[] indices     = new int[indices_nonFaceSpecific.Length];
            int[] dist_ind_si = new int[face.distinctIndices.Length];

            // figure out sharedIndices index of distinct Indices
            for (int i = 0; i < face.distinctIndices.Length; i++)
            {
                dist_ind_si[i] = sharedIndices.IndexOf(face.distinctIndices[i]);
            }

            // now do the same for non-face specific indices, assigning matching groups
            for (int i = 0; i < indices.Length; i++)
            {
                int ind = System.Array.IndexOf(dist_ind_si, sharedIndices.IndexOf(indices_nonFaceSpecific[i]));
                if (ind < 0)
                {
                    return(false);
                }

                indices[i] = face.distinctIndices[ind];
            }
            ///** Sort index array such that it only uses indices local to the passed face

            Vector3 cen3d = pb_Math.Average(pb.GetVertices(face));

            Vector3[] verts = pb.GetVertices(face.distinctIndices);
            Vector3   nrm   = pb_Math.Normal(pb.GetVertices(face.indices));

            Vector2[] plane    = pb_Math.VerticesTo2DPoints(verts, nrm);
            Vector2[] indPlane = pb_Math.VerticesTo2DPoints(pb.GetVertices(indices), nrm);
            Vector2   cen2d    = pb_Math.VerticesTo2DPoints(new Vector3[1] {
                cen3d
            }, nrm)[0];

            // Get the directions from which to segment this face
            Vector2[] dividers = new Vector2[indices.Length];
            for (int i = 0; i < indices.Length; i++)
            {
                dividers[i] = (indPlane[i] - cen2d).normalized;
            }

            List <Vector2>[] quadrants2d = new List <Vector2> [indices.Length];
            List <Vector3>[] quadrants3d = new List <Vector3> [indices.Length];
            List <int>[]     sharedIndex = new List <int> [indices.Length];

            for (int i = 0; i < quadrants2d.Length; i++)
            {
                quadrants2d[i] = new List <Vector2>(1)
                {
                    cen2d
                };
                quadrants3d[i] = new List <Vector3>(1)
                {
                    cen3d
                };
                sharedIndex[i] = new List <int>(1)
                {
                    -2
                };                                                              // any negative value less than -1 will be treated as a new group
            }

            for (int i = 0; i < face.distinctIndices.Length; i++)
            {
                // if this index is a divider, it needs to belong to the leftmost and
                // rightmost quadrant
                int indexInPokeVerts = System.Array.IndexOf(indices, face.distinctIndices[i]);
                int ignore           = -1;
                if (indexInPokeVerts > -1)
                {
                    // Add vert to this quadrant
                    quadrants2d[indexInPokeVerts].Add(plane[i]);
                    quadrants3d[indexInPokeVerts].Add(verts[i]);
                    sharedIndex[indexInPokeVerts].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));

                    // And also the one closest counter clockwise
                    ignore = indexInPokeVerts;
                }

                Vector2 dir = (plane[i] - cen2d).normalized;            // plane corresponds to distinctIndices
                float   largestClockwiseDistance = 0f;
                int     quad = -1;
                for (int j = 0; j < dividers.Length; j++)
                {
                    if (j == ignore)
                    {
                        continue;                               // this is a dividing vertex - ignore
                    }
                    float dist = Vector2.Angle(dividers[j], dir);
                    if (Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f)
                    {
                        dist = 360f - dist;
                    }

                    if (dist > largestClockwiseDistance)
                    {
                        largestClockwiseDistance = dist;
                        quad = j;
                    }
                }

                quadrants2d[quad].Add(plane[i]);
                quadrants3d[quad].Add(verts[i]);
                sharedIndex[quad].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));
            }

            int len = quadrants2d.Length;

            // Triangulate
            int[][] tris = new int[len][];
            for (int i = 0; i < len; i++)
            {
                tris[i] = Delauney.Triangulate(quadrants2d[i]).ToIntArray();

                if (tris[i].Length < 3)
                {
                    return(false);
                }

                // todo - check that face normal is correct
            }

            splitFaces         = new pb_Face[len];
            splitVertices      = new Vector3[len][];
            splitSharedIndices = new int[len][];

            for (int i = 0; i < len; i++)
            {
                // triangles, material, pb_UV, smoothing group, shared index
                splitFaces[i]         = new pb_Face(tris[i], face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, -1, face.color);
                splitVertices[i]      = quadrants3d[i].ToArray();
                splitSharedIndices[i] = sharedIndex[i].ToArray();
            }

            return(true);
        }
Ejemplo n.º 20
0
        void DrawStats(pb_Object pb)
        {
            StringBuilder sb = new StringBuilder();

            Handles.BeginGUI();

            if (edgeInfo)
            {
                foreach (pb_Edge f in pb.SelectedEdges)
                {
                    Vector2    cen = HandleUtility.WorldToGUIPoint(pb.transform.TransformPoint((pb.vertices[f.x] + pb.vertices[f.y]) / 2f));
                    GUIContent gc  = new GUIContent(f.ToString(), "");
                    DrawSceneLabel(gc, cen);
                }
            }

            /**
             * SHARED INDICES
             */
            // foreach(pb_IntArray arr in pb.sharedIndices)
            // {
            //  Vector2 cen = HandleUtility.WorldToGUIPoint( pb.transform.TransformPoint(pb.vertices[arr[0]]) );

            //  GUI.Label(new Rect(cen.x, cen.y, 200, 200), ((int[])arr).ToFormattedString("\n"));
            // }

            if (faceInfo)
            {
                foreach (pb_Face f in pb.SelectedFaces)
                {
                    Vector2 cen = HandleUtility.WorldToGUIPoint(pb.transform.TransformPoint(pb_Math.Average(pb.GetVertices(f.distinctIndices))));

                    GUIContent gc = new GUIContent("Face: " + f.ToString(), "");

                    if (smoothingGroupInfo || elementGroupInfo || textureGroupInfo)
                    {
                        gc.text += "\nGroups:";
                    }

                    if (smoothingGroupInfo)
                    {
                        gc.text += "\nSmoothing: " + f.smoothingGroup;
                    }
                    if (elementGroupInfo)
                    {
                        gc.text += "\nElement: " + f.elementGroup;
                    }
                    if (textureGroupInfo)
                    {
                        gc.text += "\nTexture: " + f.textureGroup;
                    }

                    DrawSceneLabel(gc, cen);
                }
            }

            // sb.AppendLine(f.ToString() + ", ");


            // foreach(pb_Face face in pb.SelectedFaces)
            //  sb.AppendLine(face.colors.ToFormattedString("\n") + "\n");

            // sb.AppendLine("\n");

            // foreach(pb_IntArray si in pb.sharedIndices)
            // {
            //  sb.AppendLine(si.array.ToFormattedString(", "));
            // }

            // sb.AppendLine("\n");

            // if(vertexInfo)
            // {
            //  try
            //  {
            //      Camera cam = SceneView.lastActiveSceneView.camera;
            //      Vector3[] normals = pb.msh.normals;
            //      int index = 0;
            //      foreach(pb_IntArray arr in pb.sharedIndices)
            //      {
            //          Vector3 v = pb.transform.TransformPoint(pb.vertices[arr[0]] + normals[arr[0]] * .01f);

            //          if(!pb_HandleUtility.PointIsOccluded(cam, pb, v))
            //          {
            //              Vector2 cen = HandleUtility.WorldToGUIPoint( v );

            //              GUIContent gc = new GUIContent(index++ + ": " + arr.array.ToFormattedString(", "), "");

            //              DrawSceneLabel(gc, cen);
            //          }
            //      }
            //  } catch { /* do not care */; }
            // }

            Handles.EndGUI();

            Handles.BeginGUI();
            {
                GUI.Label(new Rect(10, 10, 400, 800), sb.ToString());
            }
            Handles.EndGUI();
        }
Ejemplo n.º 21
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);
        }
Ejemplo n.º 22
0
	/**
	 *	Inserts a split from each selected vertex to the center of the face
	 */
	private static bool PokeFace_Internal(pb_Object pb, pb_Face face, int[] indices_nonFaceSpecific,
		out Vector3 pokedVertex,
		out pb_Face[] splitFaces,
		out Vector3[][] splitVertices,
		out Color[][] splitColors,
		out Vector2[][] splitUVs,
		out int[][] splitSharedIndices)
	{
		pokedVertex = Vector3.zero;
		splitFaces = null;
		splitVertices = null;
		splitColors = null;
		splitUVs = null;
		splitSharedIndices = null;

		pb_IntArray[] sharedIndices = pb.sharedIndices;

		///** Sort index array such that it only uses indices local to the passed face
		int[] dist_indices = new int[indices_nonFaceSpecific.Length];
		int[] dist_ind_si = new int[face.distinctIndices.Length];

		// figure out sharedIndices index of distinct Indices
		for(int i = 0; i < face.distinctIndices.Length; i++)
			dist_ind_si[i] = sharedIndices.IndexOf(face.distinctIndices[i]);

		// now do the same for non-face specific indices, assigning matching groups
		
		///** Sort index array such that it only uses indices local to the passed face
		for(int i = 0; i < dist_indices.Length; i++)
		{
			int ind = System.Array.IndexOf(dist_ind_si, sharedIndices.IndexOf(indices_nonFaceSpecific[i]));
			if(ind < 0) return false;

			dist_indices[i] = face.distinctIndices[ind];
		}

		int[] indices = dist_indices.Distinct().ToArray();

		// throw out splits with less than 2 vertices, or splits composed 
		// of a single edge
		switch(indices.Length)
		{
			case 0:
			case 1:
				return false;

			case 2:
				if( System.Array.IndexOf(face.edges, new pb_Edge(indices[0], indices[1]) ) > -1)
					return false;
				break;
			default:
				break;
		}
		
		// end triangle sorting

		/**
		 *	The general idea here is to project the face into 2d space,
		 *	split the 2d points into groups based on the intersecting lines,
		 *	then triangulate those groups.  once the groups have been 
		 *	triangulated, rebuild the 3d vertices using the new groups
		 *	(building new verts for seams).
		 *	
		 *	Think like you're cutting a pie... but first the pie is a basketball,
		 *	then a pie, then a basketball again.  I'm on a horse.
		 */

		Vector3[] verts 	= pb.GetVertices(face.distinctIndices);
		Vector2[] uvs 		= pb.GetUVs(face.distinctIndices);
		Color[] colors  	= pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices);

		Vector2 cenUV		= pb_Bounds2D.Center(uvs);
		Vector3 cen3d 		= pb_Math.Average(verts);
		pokedVertex 		= cen3d;
		Vector3 nrm 		= pb_Math.Normal(pb.GetVertices(face.indices));
		Color cenColor 		= pb_Math.Average(colors);

		// this should be cleaned up
		Vector2[] plane 	= pb_Math.PlanarProject(verts, nrm);
		Vector2[] indPlane 	= pb_Math.PlanarProject(pb.GetVertices(indices), nrm);
		Vector2 cen2d 		= pb_Math.PlanarProject( new Vector3[1] { cen3d }, nrm)[0];

		// Get the directions from which to segment this face
		Vector2[] dividers = new Vector2[indices.Length];
		for(int i = 0; i < indices.Length; i++)
			dividers[i] = (indPlane[i] - cen2d).normalized;

		List<Vector2>[] quadrants2d 	= new List<Vector2>[indices.Length];
		List<Vector3>[] quadrants3d 	= new List<Vector3>[indices.Length];
		List<Vector2>[] quadrantsUV_2d 	= new List<Vector2>[indices.Length];
		List<Color>[] 	quadrantsCol 	= new List<Color>[indices.Length];

		List<int>[]		sharedIndex = new List<int>[indices.Length];

		for(int i = 0; i < quadrants2d.Length; i++)
		{
			quadrants2d[i] = new List<Vector2>(1) { cen2d };
			quadrants3d[i] = new List<Vector3>(1) { cen3d };
			quadrantsUV_2d[i] = new List<Vector2>(1) { cenUV };
			quadrantsCol[i] = new List<Color>(1) { cenColor };

			sharedIndex[i] = new List<int>(1) { -2 };		// any negative value less than -1 will be treated as a new group
		}

		for(int i = 0; i < face.distinctIndices.Length; i++)
		{
			// if this index is a divider, it needs to belong to the leftmost and 
			// rightmost quadrant
			int indexInPokeVerts = System.Array.IndexOf(indices, face.distinctIndices[i]);
			int ignore = -1;
			if( indexInPokeVerts > -1)
			{	
				// Add vert to this quadrant
				quadrants2d[indexInPokeVerts].Add(plane[i]);
				quadrants3d[indexInPokeVerts].Add(verts[i]);
				quadrantsUV_2d[indexInPokeVerts].Add(uvs[i]);
				quadrantsCol[indexInPokeVerts].Add(colors[i]);

				sharedIndex[indexInPokeVerts].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));

				// And also the one closest counter clockwise
				ignore = indexInPokeVerts;
			}

			Vector2 dir = (plane[i]-cen2d).normalized;	// plane corresponds to distinctIndices
			float largestClockwiseDistance = 0f;
			int quad = -1;
			for(int j = 0; j < dividers.Length; j++)
			{
				if(j == ignore) continue;	// this is a dividing vertex - ignore

				float dist = Vector2.Angle(dividers[j], dir);
				if( Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f )
					dist = 360f - dist;

				if(dist > largestClockwiseDistance)
				{
					largestClockwiseDistance = dist;
					quad = j;
				}
			}

			quadrants2d[quad].Add(plane[i]);
			quadrants3d[quad].Add(verts[i]);
			quadrantsUV_2d[quad].Add(uvs[i]);
			quadrantsCol[quad].Add(colors[i]);

			sharedIndex[quad].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));
		}

		int len = quadrants2d.Length;

		// Triangulate
		int[][] tris = new int[len][];
		for(int i = 0; i < len; i++)
		{
			try {
				tris[i] = Delaunay.Triangulate(quadrants2d[i]).ToIntArray();
			
				if(tris[i] == null || tris[i].Length < 3)
				{
					Debug.Log("Fail triangulation");
					return false;
				}
			} catch (System.Exception error) {
				Debug.LogError("PokeFace internal failed triangulation. Bail!\n" + error);
				return false;
			}

			// todo - check that face normal is correct
		}

		splitFaces 			= new pb_Face[len];
		splitVertices 		= new Vector3[len][];
		splitColors 		= new Color[len][];
		splitUVs 			= new Vector2[len][];
		splitSharedIndices 	= new int[len][];

		for(int i = 0; i < len; i++)
		{
			// triangles, material, pb_UV, smoothing group, shared index
			splitFaces[i] 		= new pb_Face(tris[i], face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, -1, face.manualUV);
			splitVertices[i] 	= quadrants3d[i].ToArray();
			splitColors[i] 		= quadrantsCol[i].ToArray();
			splitUVs[i] 		= quadrantsUV_2d[i].ToArray();

			splitSharedIndices[i] = sharedIndex[i].ToArray();
		}

		return true;
	}
Ejemplo n.º 23
0
	/**
	 *	Inserts a vertex at the center of each edge, then connects the new vertices to another new
	 *	vertex placed at the center of the face.
	 */
	private static bool SubdivideFace_Internal(pb_Object pb, pb_EdgeConnection pb_edgeConnection, 
		out DanglingVertex?[] appendedVertices,	
		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;
		appendedVertices 	= new DanglingVertex?[pb_edgeConnection.edges.Count];

		// cache all the things
		pb_Face face = pb_edgeConnection.face;
		Dictionary<int, int> sharedIndices = pb.sharedIndices.ToDictionary();
		Vector3[] vertices = pb.vertices;
		Vector2[] uvs = pb.uv;

		List<Vector2> edgeCentersUV = new List<Vector2>();
		List<Vector3> edgeCenters3d = new List<Vector3>();
		List<Color> edgeCentersCol = new List<Color>();
		
		// filter duplicate edges
		int u = 0;
		List<int> usedEdgeIndices = new List<int>();
		foreach(pb_Edge edge in pb_edgeConnection.edges)
		{
			int ind = face.edges.IndexOf(edge, sharedIndices);
			if(!usedEdgeIndices.Contains(ind))
			{
				Vector3 cen = (vertices[edge.x] + vertices[edge.y]) / 2f;

				appendedVertices[u] = new DanglingVertex(cen, (pb.colors[edge.x] + pb.colors[edge.y]) / 2f);
				
				edgeCenters3d.Add(cen);
				edgeCentersUV.Add( (uvs[edge.x] + uvs[edge.y])/2f );
				edgeCentersCol.Add( (pb.colors[edge.x] + pb.colors[edge.y])/2f );

				usedEdgeIndices.Add(ind);
			}
			else
			{
				appendedVertices[u] = null;
			}

			u++;
		}

		// now we have all the vertices of the old face, plus the new edge center vertices
		Vector3 nrm = pb_Math.Normal(pb.GetVertices(face.indices));

		Vector3[] verts3d = pb.GetVertices(face.distinctIndices);
		Vector2[] faceUVs = pb.GetUVs(face.distinctIndices);
		Color[] colors = pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices);

		Vector2[] verts2d = pb_Math.PlanarProject(verts3d, nrm);
		Vector2[] edgeCenters2d = pb_Math.PlanarProject(edgeCenters3d.ToArray(), nrm);
		
		Vector3 cen3d = pb_Math.Average(verts3d);
		Vector2 cenUV = pb_Bounds2D.Center(faceUVs);

		Vector2 cen2d = pb_Math.PlanarProject( new Vector3[1] { cen3d }, nrm)[0];

		// Get the directions from which to segment this face
		Vector2[] dividers = new Vector2[edgeCenters2d.Length];
		for(int i = 0; i < edgeCenters2d.Length; i++)
			dividers[i] = (edgeCenters2d[i] - cen2d).normalized;

		List<Vector2>[] quadrants2d = new List<Vector2>[edgeCenters2d.Length];
		List<Vector3>[] quadrants3d = new List<Vector3>[edgeCenters2d.Length];
		List<Vector2>[] quadrantsUV = new List<Vector2>[edgeCenters2d.Length];
		List<Color>[] 	quadrantsCol = new List<Color>[edgeCenters2d.Length];

		List<int>[]		sharedIndex = new List<int>[edgeCenters2d.Length];

		for(int i = 0; i < quadrants2d.Length; i++)
		{
			quadrants2d[i] = new List<Vector2>(1) { cen2d };
			quadrants3d[i] = new List<Vector3>(1) { cen3d };			
			quadrantsUV[i] = new List<Vector2>(1) { cenUV };
			quadrantsCol[i] = new List<Color>(1) { pb_Math.Average(pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices)) };

			sharedIndex[i] = new List<int>(1) { -2 };		// any negative value less than -1 will be treated as a new group
		}

		// add the divisors
		for(int i = 0; i < edgeCenters2d.Length; i++)
		{
			quadrants2d[i].Add(edgeCenters2d[i]);
			quadrants3d[i].Add(edgeCenters3d[i]);
			quadrantsUV[i].Add(edgeCentersUV[i]);
			quadrantsCol[i].Add(edgeCentersCol[i]);

			sharedIndex[i].Add(-1);

			// and add closest in the counterclockwise direction
			Vector2 dir = (edgeCenters2d[i]-cen2d).normalized;
			float largestClockwiseDistance = 0f;
			int quad = -1;
			for(int j = 0; j < dividers.Length; j++)
			{
				if(j == i) continue;	// this is a dividing vertex - ignore

				float dist = Vector2.Angle(dividers[j], dir);
				if( Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f )
					dist = 360f - dist;

				if(dist > largestClockwiseDistance)
				{
					largestClockwiseDistance = dist;
					quad = j;
				}
			}

			quadrants2d[quad].Add(edgeCenters2d[i]);
			quadrants3d[quad].Add(edgeCenters3d[i]);
			quadrantsUV[quad].Add(edgeCentersUV[i]);
			quadrantsCol[quad].Add(edgeCentersCol[i]);

			sharedIndex[quad].Add(-1);
		}

		// distribute the existing vertices
		for(int i = 0; i < face.distinctIndices.Length; i++)
		{
			Vector2 dir = (verts2d[i]-cen2d).normalized;	// plane corresponds to distinctIndices
			float largestClockwiseDistance = 0f;
			int quad = -1;
			for(int j = 0; j < dividers.Length; j++)
			{
				float dist = Vector2.Angle(dividers[j], dir);
				if( Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f )
					dist = 360f - dist;

				if(dist > largestClockwiseDistance)
				{
					largestClockwiseDistance = dist;
					quad = j;
				}
			}

			quadrants2d[quad].Add(verts2d[i]);
			quadrants3d[quad].Add(verts3d[i]);
			quadrantsUV[quad].Add(faceUVs[i]);
			quadrantsCol[quad].Add(colors[i]);

			sharedIndex[quad].Add( sharedIndices[face.distinctIndices[i]] );
		}

		int len = quadrants2d.Length;

		// Triangulate
		int[][] tris = new int[len][];
		for(int i = 0; i < len; i++)
		{
			if(quadrants2d[i].Count < 3)
			{
				Debug.LogError("Insufficient points to triangulate.  Exit subdivide operation.  This is probably due to a concave face.");
				return false;
			}
		
			tris[i] = Delaunay.Triangulate(quadrants2d[i]).ToIntArray();

			if(tris[i].Length < 3)	///< #521
				return false;
			
			if( Vector3.Dot(nrm, pb_Math.Normal(quadrants3d[i][tris[i][0]], quadrants3d[i][tris[i][1]], quadrants3d[i][tris[i][2]])) < 0 )
				System.Array.Reverse(tris[i]);
		}

		splitFaces 		= new pb_Face[len];
		splitVertices 	= new Vector3[len][];
		splitColors 	= new Color[len][];
		splitUVs 		= new Vector2[len][];
		splitSharedIndices 	= new int[len][];

		for(int i = 0; i < len; i++)
		{
			// triangles, material, pb_UV, smoothing group, shared index
			splitFaces[i] 			= new pb_Face(tris[i], face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.manualUV);
			splitVertices[i] 		= quadrants3d[i].ToArray();
			splitColors[i] 			= quadrantsCol[i].ToArray();
			splitUVs[i] 			= quadrantsUV[i].ToArray();
			
			splitSharedIndices[i] 	= sharedIndex[i].ToArray();
		}

		return true;
	}