public static bool SplitPolygonAtEdge(Polygon polygon, Edge edge, out Vertex newVertex) { newVertex = null; List <Vertex> vertices = new List <Vertex>(polygon.Vertices); for (int i = 0; i < polygon.Vertices.Length; i++) { Vector3 position1 = polygon.Vertices[i].Position; Vector3 position2 = polygon.Vertices[(i + 1) % polygon.Vertices.Length].Position; if ((edge.Vertex1.Position.EqualsWithEpsilon(position1) && edge.Vertex2.Position.EqualsWithEpsilon(position2)) || (edge.Vertex1.Position.EqualsWithEpsilon(position2) && edge.Vertex2.Position.EqualsWithEpsilon(position1))) { newVertex = Vertex.Lerp(polygon.Vertices[i], polygon.Vertices[(i + 1) % polygon.Vertices.Length], 0.5f); vertices.Insert(i + 1, newVertex); break; } } if (vertices.Count == polygon.Vertices.Length) { // Could not add vertex to adjacent polygon return(false); } polygon.SetVertices(vertices.ToArray()); return(true); }
/// <summary> /// Generates an ico-sphere of radius 2. Unlike a polar-sphere this has a more even distribution of vertices. /// </summary> /// <returns>Polygons to be supplied to a brush.</returns> /// <param name="iterationCount">Number of times the surface is subdivided, values of 1 or 2 are recommended.</param> public static Polygon[] GenerateIcoSphere(int iterationCount) { // Derived from http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html float longestDimension = (1 + Mathf.Sqrt(5f)) / 2f; Vector3 sourceVector = new Vector3(0, 1, longestDimension); // Make the longest dimension 1, so the icosphere fits in a 2,2,2 cube sourceVector.Normalize(); Vertex[] vertices = new Vertex[] { new Vertex(new Vector3(-sourceVector.y, +sourceVector.z, sourceVector.x), Vector3.zero, Vector2.zero), new Vertex(new Vector3(sourceVector.y, +sourceVector.z, sourceVector.x), Vector3.zero, Vector2.zero), new Vertex(new Vector3(-sourceVector.y, -sourceVector.z, sourceVector.x), Vector3.zero, Vector2.zero), new Vertex(new Vector3(sourceVector.y, -sourceVector.z, sourceVector.x), Vector3.zero, Vector2.zero), new Vertex(new Vector3(sourceVector.x, -sourceVector.y, +sourceVector.z), Vector3.zero, Vector2.zero), new Vertex(new Vector3(sourceVector.x, +sourceVector.y, +sourceVector.z), Vector3.zero, Vector2.zero), new Vertex(new Vector3(sourceVector.x, -sourceVector.y, -sourceVector.z), Vector3.zero, Vector2.zero), new Vertex(new Vector3(sourceVector.x, +sourceVector.y, -sourceVector.z), Vector3.zero, Vector2.zero), new Vertex(new Vector3(+sourceVector.z, sourceVector.x, -sourceVector.y), Vector3.zero, Vector2.zero), new Vertex(new Vector3(+sourceVector.z, sourceVector.x, +sourceVector.y), Vector3.zero, Vector2.zero), new Vertex(new Vector3(-sourceVector.z, sourceVector.x, -sourceVector.y), Vector3.zero, Vector2.zero), new Vertex(new Vector3(-sourceVector.z, sourceVector.x, +sourceVector.y), Vector3.zero, Vector2.zero), }; Polygon[] polygons = new Polygon[] { new Polygon(new Vertex[] { vertices[0].DeepCopy(), vertices[1].DeepCopy(), vertices[7].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[0].DeepCopy(), vertices[5].DeepCopy(), vertices[1].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[0].DeepCopy(), vertices[7].DeepCopy(), vertices[10].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[0].DeepCopy(), vertices[10].DeepCopy(), vertices[11].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[0].DeepCopy(), vertices[11].DeepCopy(), vertices[5].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[7].DeepCopy(), vertices[1].DeepCopy(), vertices[8].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[1].DeepCopy(), vertices[5].DeepCopy(), vertices[9].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[10].DeepCopy(), vertices[7].DeepCopy(), vertices[6].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[11].DeepCopy(), vertices[10].DeepCopy(), vertices[2].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[5].DeepCopy(), vertices[11].DeepCopy(), vertices[4].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[3].DeepCopy(), vertices[2].DeepCopy(), vertices[6].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[3].DeepCopy(), vertices[4].DeepCopy(), vertices[2].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[3].DeepCopy(), vertices[6].DeepCopy(), vertices[8].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[3].DeepCopy(), vertices[8].DeepCopy(), vertices[9].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[3].DeepCopy(), vertices[9].DeepCopy(), vertices[4].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[6].DeepCopy(), vertices[2].DeepCopy(), vertices[10].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[2].DeepCopy(), vertices[4].DeepCopy(), vertices[11].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[8].DeepCopy(), vertices[6].DeepCopy(), vertices[7].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[9].DeepCopy(), vertices[8].DeepCopy(), vertices[1].DeepCopy() }, null, false, false), new Polygon(new Vertex[] { vertices[4].DeepCopy(), vertices[9].DeepCopy(), vertices[5].DeepCopy() }, null, false, false), }; // Refine for (int i = 0; i < iterationCount; i++) { Polygon[] newPolygons = new Polygon[polygons.Length * 4]; for (int j = 0; j < polygons.Length; j++) { Vertex a = Vertex.Lerp(polygons[j].Vertices[0], polygons[j].Vertices[1], 0.5f); Vertex b = Vertex.Lerp(polygons[j].Vertices[1], polygons[j].Vertices[2], 0.5f); Vertex c = Vertex.Lerp(polygons[j].Vertices[2], polygons[j].Vertices[0], 0.5f); a.Position = a.Position.normalized; b.Position = b.Position.normalized; c.Position = c.Position.normalized; newPolygons[j * 4 + 0] = new Polygon(new Vertex[] { polygons[j].Vertices[0].DeepCopy(), a.DeepCopy(), c.DeepCopy() }, null, false, false); newPolygons[j * 4 + 1] = new Polygon(new Vertex[] { polygons[j].Vertices[1].DeepCopy(), b.DeepCopy(), a.DeepCopy() }, null, false, false); newPolygons[j * 4 + 2] = new Polygon(new Vertex[] { polygons[j].Vertices[2].DeepCopy(), c.DeepCopy(), b.DeepCopy() }, null, false, false); newPolygons[j * 4 + 3] = new Polygon(new Vertex[] { a.DeepCopy(), b.DeepCopy(), c.DeepCopy() }, null, false, false); } polygons = newPolygons; } for (int i = 0; i < polygons.Length; i++) { bool anyAboveHalf = false; for (int j = 0; j < polygons[i].Vertices.Length; j++) { Vector3 normal = polygons[i].Vertices[j].Position.normalized; polygons[i].Vertices[j].Normal = normal; float piReciprocal = 1f / Mathf.PI; float u = 0.5f - 0.5f * Mathf.Atan2(normal.x, -normal.z) * piReciprocal; float v = 1f - Mathf.Acos(normal.y) * piReciprocal; if (Mathf.Abs(u) < 0.01f || Mathf.Abs(1 - Mathf.Abs(u)) < 0.01f) { if (polygons[i].Plane.normal.x > 0) { u = 0; } else { u = 1; } } if (u > 0.75f) { anyAboveHalf = true; } //Debug.Log(u); polygons[i].Vertices[j].UV = new Vector2(u, v); //const float kOneOverPi = 1.0 / 3.14159265; //float u = 0.5 - 0.5 * atan(N.x, -N.z) * kOneOverPi; //float v = 1.0 - acos(N.y) * kOneOverPi; } if (anyAboveHalf) { for (int j = 0; j < polygons[i].Vertices.Length; j++) { Vector2 uv = polygons[i].Vertices[j].UV; if (uv.x < 0.5f) { uv.x += 1; } polygons[i].Vertices[j].UV = uv; } } } return(polygons); }
public static bool SplitPolygon(Polygon polygon, out Polygon frontPolygon, out Polygon backPolygon, out Vertex newVertex1, out Vertex newVertex2, UnityEngine.Plane clipPlane) { newVertex1 = null; newVertex2 = null; List <Vertex> frontVertices = new List <Vertex>(); List <Vertex> backVertices = new List <Vertex>(); for (int i = 0; i < polygon.vertices.Length; i++) { int previousIndex = i - 1; if (previousIndex < 0) { previousIndex = polygon.vertices.Length - 1; } Vertex currentVertex = polygon.vertices[i]; Vertex previousVertex = polygon.vertices[previousIndex]; PointPlaneRelation currentRelation = ComparePointToPlane(currentVertex.Position, clipPlane); PointPlaneRelation previousRelation = ComparePointToPlane(previousVertex.Position, clipPlane); if (previousRelation == PointPlaneRelation.InFront && currentRelation == PointPlaneRelation.InFront) { // Front add current frontVertices.Add(currentVertex); } else if (previousRelation == PointPlaneRelation.Behind && currentRelation == PointPlaneRelation.InFront) { float interpolant = Edge.IntersectsPlane(clipPlane, previousVertex.Position, currentVertex.Position); Vertex intersection = Vertex.Lerp(previousVertex, currentVertex, interpolant); // Front add intersection, add current frontVertices.Add(intersection); frontVertices.Add(currentVertex); // Back add intersection backVertices.Add(intersection.DeepCopy()); newVertex2 = intersection; } else if (previousRelation == PointPlaneRelation.InFront && currentRelation == PointPlaneRelation.Behind) { // Reverse order here so that clipping remains consistent for either CW or CCW testing float interpolant = Edge.IntersectsPlane(clipPlane, currentVertex.Position, previousVertex.Position); Vertex intersection = Vertex.Lerp(currentVertex, previousVertex, interpolant); // Front add intersection frontVertices.Add(intersection); // Back add intersection, current backVertices.Add(intersection.DeepCopy()); backVertices.Add(currentVertex); newVertex1 = intersection; } else if (previousRelation == PointPlaneRelation.Behind && currentRelation == PointPlaneRelation.Behind) { // Back add current backVertices.Add(currentVertex); } else if (currentRelation == PointPlaneRelation.On) { // Front add current frontVertices.Add(currentVertex); // Back add current backVertices.Add(currentVertex.DeepCopy()); if (previousRelation == PointPlaneRelation.InFront) { newVertex1 = currentVertex; } else if (previousRelation == PointPlaneRelation.Behind) { newVertex2 = currentVertex; } else { // throw new System.Exception("Unhandled polygon configuration"); } } else if (currentRelation == PointPlaneRelation.Behind) { backVertices.Add(currentVertex); } else if (currentRelation == PointPlaneRelation.InFront) { frontVertices.Add(currentVertex); } else { throw new System.Exception("Unhandled polygon configuration"); } } // Debug.Log("done"); frontPolygon = new Polygon(frontVertices.ToArray(), polygon.Material, polygon.ExcludeFromFinal, polygon.UserExcludeFromFinal, polygon.uniqueIndex); backPolygon = new Polygon(backVertices.ToArray(), polygon.Material, polygon.ExcludeFromFinal, polygon.UserExcludeFromFinal, polygon.uniqueIndex); // Because of some floating point issues and some edge cases relating to splitting the tip of a very thin // polygon we can't reliable test that the polygon intersects a plane and will produce two valid pieces // so after splitting we need to do an additional test to check that each polygon is valid. If it isn't // then we mark that polygon as null and return false to indicate the split wasn't entirely successful bool splitNecessary = true; if (frontPolygon.vertices.Length < 3 || frontPolygon.Plane.normal == Vector3.zero) { frontPolygon = null; splitNecessary = false; } if (backPolygon.vertices.Length < 3 || backPolygon.Plane.normal == Vector3.zero) { backPolygon = null; splitNecessary = false; } return(splitNecessary); }