Beispiel #1
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);
        }
Beispiel #2
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;
	}