public static void ExtrudePolygonOld(Polygon sourcePolygon, out Polygon[] outputPolygons, out Quaternion rotation) { float extrusionDistance = 1; Polygon newPolygon = sourcePolygon.DeepCopy(); newPolygon.UniqueIndex = -1; newPolygon.Flip(); Vector3 normal = sourcePolygon.Plane.normal; Polygon oppositePolygon = sourcePolygon.DeepCopy(); oppositePolygon.UniqueIndex = -1; Vertex[] vertices = oppositePolygon.Vertices; for (int i = 0; i < vertices.Length; i++) { vertices[i].Position += normal; } oppositePolygon.SetVertices(vertices); Polygon[] brushSides = new Polygon[sourcePolygon.Vertices.Length]; for (int i = 0; i < newPolygon.Vertices.Length; i++) { Vertex vertex1 = newPolygon.Vertices[i].DeepCopy(); Vertex vertex2 = newPolygon.Vertices[(i + 1) % newPolygon.Vertices.Length].DeepCopy(); Vector2 uvDelta = vertex2.UV - vertex1.UV; float sourceDistance = Vector3.Distance(vertex1.Position, vertex2.Position); Vector2 rotatedUVDelta = uvDelta.Rotate(90) * (extrusionDistance / sourceDistance); Vertex vertex3 = vertex1.DeepCopy(); vertex3.Position += normal * extrusionDistance; vertex3.UV += rotatedUVDelta; Vertex vertex4 = vertex2.DeepCopy(); vertex4.Position += normal * extrusionDistance; vertex4.UV += rotatedUVDelta; Vertex[] newVertices = new Vertex[] { vertex1, vertex2, vertex4, vertex3 }; brushSides[i] = new Polygon(newVertices, sourcePolygon.Material, false, false); brushSides[i].Flip(); brushSides[i].ResetVertexNormals(); } List <Polygon> polygons = new List <Polygon>(); polygons.Add(newPolygon); polygons.Add(oppositePolygon); polygons.AddRange(brushSides); outputPolygons = polygons.ToArray(); rotation = Quaternion.identity; }
public static Polygon[] GenerateCylinder(int sideCount = 20) { Polygon[] polygons = new Polygon[sideCount * 3]; float angleDelta = Mathf.PI * 2 / sideCount; for (int i = 0; i < sideCount; i++) { polygons[i] = new Polygon(new Vertex[] { new Vertex(new Vector3(Mathf.Sin(i * angleDelta), -1, Mathf.Cos(i * angleDelta)), new Vector3(Mathf.Sin(i * angleDelta), 0, Mathf.Cos(i * angleDelta)), new Vector2(i * (1f / sideCount), 0)), new Vertex(new Vector3(Mathf.Sin((i + 1) * angleDelta), -1, Mathf.Cos((i + 1) * angleDelta)), new Vector3(Mathf.Sin((i + 1) * angleDelta), 0, Mathf.Cos((i + 1) * angleDelta)), new Vector2((i + 1) * (1f / sideCount), 0)), new Vertex(new Vector3(Mathf.Sin((i + 1) * angleDelta), 1, Mathf.Cos((i + 1) * angleDelta)), new Vector3(Mathf.Sin((i + 1) * angleDelta), 0, Mathf.Cos((i + 1) * angleDelta)), new Vector2((i + 1) * (1f / sideCount), 1)), new Vertex(new Vector3(Mathf.Sin(i * angleDelta), 1, Mathf.Cos(i * angleDelta)), new Vector3(Mathf.Sin(i * angleDelta), 0, Mathf.Cos(i * angleDelta)), new Vector2(i * (1f / sideCount), 1)), }, null, false, false); } Vertex capCenterVertex = new Vertex(new Vector3(0, 1, 0), Vector3.up, new Vector2(0, 0)); for (int i = 0; i < sideCount; i++) { Vertex vertex1 = new Vertex(new Vector3(Mathf.Sin(i * angleDelta), 1, Mathf.Cos(i * angleDelta)), Vector3.up, new Vector2(Mathf.Sin(i * angleDelta), Mathf.Cos(i * angleDelta))); Vertex vertex2 = new Vertex(new Vector3(Mathf.Sin((i + 1) * angleDelta), 1, Mathf.Cos((i + 1) * angleDelta)), Vector3.up, new Vector2(Mathf.Sin((i + 1) * angleDelta), Mathf.Cos((i + 1) * angleDelta))); Vertex[] capVertices = new Vertex[] { vertex1, vertex2, capCenterVertex.DeepCopy() }; polygons[sideCount + i] = new Polygon(capVertices, null, false, false); } capCenterVertex = new Vertex(new Vector3(0, -1, 0), Vector3.down, new Vector2(0, 0)); for (int i = 0; i < sideCount; i++) { Vertex vertex1 = new Vertex(new Vector3(Mathf.Sin(i * -angleDelta), -1, Mathf.Cos(i * -angleDelta)), Vector3.down, new Vector2(Mathf.Sin(i * angleDelta), Mathf.Cos(i * angleDelta))); Vertex vertex2 = new Vertex(new Vector3(Mathf.Sin((i + 1) * -angleDelta), -1, Mathf.Cos((i + 1) * -angleDelta)), Vector3.down, new Vector2(Mathf.Sin((i + 1) * angleDelta), Mathf.Cos((i + 1) * angleDelta))); Vertex[] capVertices = new Vertex[] { vertex1, vertex2, capCenterVertex.DeepCopy() }; polygons[sideCount * 2 + i] = new Polygon(capVertices, null, false, false); } return(polygons); }
/// <summary> /// Adapted from GetUVForPosition /// </summary> public static Vertex GetVertexForPosition(Vertex vertex1, Vertex vertex2, Vertex vertex3, Vector3 newPosition) { Vector3 pos1 = vertex1.Position; Vector3 pos2 = vertex2.Position; Vector3 pos3 = vertex3.Position; //Plane plane = new Plane(pos1,pos2,pos3); // TODO Is it safe to replace this with the polygon Plane property? //Vector3 planePoint = MathHelper.ClosestPointOnPlane(newPosition, plane); Vector3 planePoint = newPosition; // calculate vectors from point f to vertices p1, p2 and p3: Vector3 f1 = pos1 - planePoint; Vector3 f2 = pos2 - planePoint; Vector3 f3 = pos3 - planePoint; // calculate the areas (parameters order is essential in this case): Vector3 va = Vector3.Cross(pos1 - pos2, pos1 - pos3); // main triangle cross product Vector3 va1 = Vector3.Cross(f2, f3); // p1's triangle cross product Vector3 va2 = Vector3.Cross(f3, f1); // p2's triangle cross product Vector3 va3 = Vector3.Cross(f1, f2); // p3's triangle cross product float a = va.magnitude; // main triangle area // calculate barycentric coordinates with sign: float a1 = va1.magnitude / a * Mathf.Sign(Vector3.Dot(va, va1)); float a2 = va2.magnitude / a * Mathf.Sign(Vector3.Dot(va, va2)); float a3 = va3.magnitude / a * Mathf.Sign(Vector3.Dot(va, va3)); Vertex vertex = vertex1.DeepCopy(); // Interpolate normal and UV based on the barycentric coordinates vertex.Normal = vertex1.Normal * a1 + vertex2.Normal * a2 + vertex3.Normal * a3; vertex.UV = vertex1.UV * a1 + vertex2.UV * a2 + vertex3.UV * a3; // Interpolate the color, slightly more complex as need to implicit cast from Color32 to Color and back for interpolation Color color1 = vertex1.Color; Color color2 = vertex1.Color; Color color3 = vertex1.Color; vertex.Color = color1 * a1 + color2 * a2 + color3 * a3; return(vertex); }
/// <summary> /// Generates a cone of height and radius 2. If the <see cref="sideCount"/> is 3, generates a triangular-based pyramid. /// </summary> /// <param name="sideCount">Side count for the cone (if 3, generates a triangular-based pyramid.).</param> /// <returns>Polygons to be supplied to a brush.</returns> public static Polygon[] GenerateCone(int sideCount = 20) { Polygon[] polygons = new Polygon[sideCount * 2]; // the cone generator will create a slightly distorted off-center output for 3 sides. // if the user sets the side count to 3 we will generate a triangular-based pyramid. if (sideCount == 3) { polygons = new Polygon[sideCount + 1]; polygons[0] = new Polygon(new Vertex[] { new Vertex(new Vector3(0, -1, -1), new Vector3(0.8402f, 0.2425f, -0.4851f), new Vector2(0.0000f, 0.0000f)), new Vertex(new Vector3(0, 1, 0), new Vector3(0.8402f, 0.2425f, -0.4851f), new Vector2(0.5000f, 1.0000f)), new Vertex(new Vector3(1, -1, 1), new Vector3(0.8402f, 0.2425f, -0.4851f), new Vector2(1.0000f, 0.0000f)), }, null, false, false); polygons[1] = new Polygon(new Vertex[] { new Vertex(new Vector3(1, -1, 1), new Vector3(-0.0000f, 0.2425f, 0.9701f), new Vector2(0.0000f, 0.0000f)), new Vertex(new Vector3(0, 1, 0), new Vector3(-0.0000f, 0.2425f, 0.9701f), new Vector2(0.5000f, 1.0000f)), new Vertex(new Vector3(-1, -1, 1), new Vector3(-0.0000f, 0.2425f, 0.9701f), new Vector2(1.0000f, 0.0000f)), }, null, false, false); polygons[2] = new Polygon(new Vertex[] { new Vertex(new Vector3(-1, -1, 1), new Vector3(-0.8402f, 0.2425f, -0.4851f), new Vector2(0.0000f, 0.0000f)), new Vertex(new Vector3(0, 1, 0), new Vector3(-0.8402f, 0.2425f, -0.4851f), new Vector2(0.5000f, 1.0000f)), new Vertex(new Vector3(0, -1, -1), new Vector3(-0.8402f, 0.2425f, -0.4851f), new Vector2(1.0000f, 0.0000f)), }, null, false, false); polygons[3] = new Polygon(new Vertex[] { new Vertex(new Vector3(0, -1, -1), Vector3.down, new Vector2(0.0000f, 0.0000f)), new Vertex(new Vector3(1, -1, 1), Vector3.down, new Vector2(1.0000f, 1.0000f)), new Vertex(new Vector3(-1, -1, 1), Vector3.down, new Vector2(1.0000f, 0.0000f)), }, null, false, false); return(polygons); } float angleDelta = Mathf.PI * 2 / sideCount; for (int i = 0; i < sideCount; i++) { Vector3 normal = new Vector3(Mathf.Sin((i + 0.5f) * angleDelta), 0, Mathf.Cos((i + 0.5f) * angleDelta)); polygons[i] = new Polygon(new Vertex[] { new Vertex(new Vector3(Mathf.Sin(i * angleDelta), -1, Mathf.Cos(i * angleDelta)), normal, new Vector2(i * (1f / sideCount), 0)), new Vertex(new Vector3(Mathf.Sin((i + 1) * angleDelta), -1, Mathf.Cos((i + 1) * angleDelta)), normal, new Vector2((i + 1) * (1f / sideCount), 0)), new Vertex(new Vector3(0, 1, 0), normal, new Vector2((((i + 1) * (1f / sideCount)) + (i * (1f / sideCount))) / 2.0f, 1.0f)), }, null, false, false); } Vertex capCenterVertex = new Vertex(new Vector3(0, -1, 0), Vector3.down, new Vector2(0, 0)); for (int i = 0; i < sideCount; i++) { Vertex vertex1 = new Vertex(new Vector3(Mathf.Sin(i * -angleDelta), -1, Mathf.Cos(i * -angleDelta)), Vector3.down, new Vector2(Mathf.Sin(i * angleDelta), Mathf.Cos(i * angleDelta))); Vertex vertex2 = new Vertex(new Vector3(Mathf.Sin((i + 1) * -angleDelta), -1, Mathf.Cos((i + 1) * -angleDelta)), Vector3.down, new Vector2(Mathf.Sin((i + 1) * angleDelta), Mathf.Cos((i + 1) * angleDelta))); Vertex[] capVertices = new Vertex[] { vertex1, vertex2, capCenterVertex.DeepCopy() }; polygons[sideCount + i] = new Polygon(capVertices, null, false, false); } return(polygons); }
/// <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); }
public static void ExtrudePolygon(Polygon sourcePolygon, out Polygon[] outputPolygons, out Quaternion rotation) { float extrusionDistance = 1; Polygon basePolygon = sourcePolygon.DeepCopy(); basePolygon.UniqueIndex = -1; rotation = Quaternion.LookRotation(basePolygon.Plane.normal); Quaternion cancellingRotation = Quaternion.Inverse(rotation); Vertex[] vertices = basePolygon.Vertices; // Vector3 offsetPosition = vertices[0].Position; for (int i = 0; i < vertices.Length; i++) { // vertices[i].Position -= offsetPosition; vertices[i].Position = cancellingRotation * vertices[i].Position; vertices[i].Normal = cancellingRotation * vertices[i].Normal; } // Vector3 newOffsetPosition = vertices[0].Position; // Vector3 delta = newOffsetPosition - offsetPosition; // for (int i = 0; i < vertices.Length; i++) // { // vertices[i].Position += delta; // } basePolygon.SetVertices(vertices); Vector3 normal = basePolygon.Plane.normal; Polygon oppositePolygon = basePolygon.DeepCopy(); oppositePolygon.UniqueIndex = -1; basePolygon.Flip(); vertices = oppositePolygon.Vertices; for (int i = 0; i < vertices.Length; i++) { vertices[i].Position += normal; } oppositePolygon.SetVertices(vertices); Polygon[] brushSides = new Polygon[sourcePolygon.Vertices.Length]; for (int i = 0; i < basePolygon.Vertices.Length; i++) { Vertex vertex1 = basePolygon.Vertices[i].DeepCopy(); Vertex vertex2 = basePolygon.Vertices[(i + 1) % basePolygon.Vertices.Length].DeepCopy(); Vector2 uvDelta = vertex2.UV - vertex1.UV; float sourceDistance = Vector3.Distance(vertex1.Position, vertex2.Position); Vector2 rotatedUVDelta = uvDelta.Rotate(90) * (extrusionDistance / sourceDistance); Vertex vertex3 = vertex1.DeepCopy(); vertex3.Position += normal * extrusionDistance; vertex3.UV += rotatedUVDelta; Vertex vertex4 = vertex2.DeepCopy(); vertex4.Position += normal * extrusionDistance; vertex4.UV += rotatedUVDelta; Vertex[] newVertices = new Vertex[] { vertex1, vertex2, vertex4, vertex3 }; brushSides[i] = new Polygon(newVertices, sourcePolygon.Material, false, false); brushSides[i].Flip(); brushSides[i].ResetVertexNormals(); } List <Polygon> polygons = new List <Polygon>(); polygons.Add(basePolygon); polygons.Add(oppositePolygon); polygons.AddRange(brushSides); outputPolygons = polygons.ToArray(); }
/// <summary> /// Creates a brush by extruding a supplied polygon by a specified extrusion distance. /// </summary> /// <param name="sourcePolygon">Source polygon, typically transformed into world space.</param> /// <param name="extrusionDistance">Extrusion distance, this is the height (or depth) of the created geometry perpendicular to the source polygon.</param> /// <param name="outputPolygons">Output brush polygons.</param> /// <param name="rotation">The rotation to be supplied to the new brush transform.</param> public static void ExtrudePolygon(Polygon sourcePolygon, float extrusionDistance, out Polygon[] outputPolygons, out Quaternion rotation) { bool flipped = false; if (extrusionDistance < 0) { sourcePolygon.Flip(); extrusionDistance = -extrusionDistance; flipped = true; } // Create base polygon Polygon basePolygon = sourcePolygon.DeepCopy(); basePolygon.UniqueIndex = -1; rotation = Quaternion.LookRotation(basePolygon.Plane.normal); Quaternion cancellingRotation = Quaternion.Inverse(rotation); Vertex[] vertices = basePolygon.Vertices; for (int i = 0; i < vertices.Length; i++) { vertices[i].Position = cancellingRotation * vertices[i].Position; vertices[i].Normal = cancellingRotation * vertices[i].Normal; } basePolygon.SetVertices(vertices); // Create the opposite polygon by duplicating the base polygon, offsetting and flipping Vector3 normal = basePolygon.Plane.normal; Polygon oppositePolygon = basePolygon.DeepCopy(); oppositePolygon.UniqueIndex = -1; basePolygon.Flip(); vertices = oppositePolygon.Vertices; for (int i = 0; i < vertices.Length; i++) { vertices[i].Position += normal * extrusionDistance; // vertices[i].UV.x *= -1; // Flip UVs } oppositePolygon.SetVertices(vertices); // Now create each of the brush side polygons Polygon[] brushSides = new Polygon[sourcePolygon.Vertices.Length]; for (int i = 0; i < basePolygon.Vertices.Length; i++) { Vertex vertex1 = basePolygon.Vertices[i].DeepCopy(); Vertex vertex2 = basePolygon.Vertices[(i + 1) % basePolygon.Vertices.Length].DeepCopy(); // Create new UVs for the sides, otherwise we'll get distortion float sourceDistance = Vector3.Distance(vertex1.Position, vertex2.Position); float uvDistance = Vector2.Distance(vertex1.UV, vertex2.UV); float uvScale = sourceDistance / uvDistance; vertex1.UV = Vector2.zero; if (flipped) { vertex2.UV = new Vector2(-sourceDistance / uvScale, 0); } else { vertex2.UV = new Vector2(sourceDistance / uvScale, 0); } Vector2 uvDelta = vertex2.UV - vertex1.UV; Vector2 rotatedUVDelta = uvDelta.Rotate(90) * (extrusionDistance / sourceDistance); Vertex vertex3 = vertex1.DeepCopy(); vertex3.Position += normal * extrusionDistance; vertex3.UV += rotatedUVDelta; Vertex vertex4 = vertex2.DeepCopy(); vertex4.Position += normal * extrusionDistance; vertex4.UV += rotatedUVDelta; Vertex[] newVertices = new Vertex[] { vertex1, vertex2, vertex4, vertex3 }; brushSides[i] = new Polygon(newVertices, sourcePolygon.Material, false, false); brushSides[i].Flip(); brushSides[i].ResetVertexNormals(); } List <Polygon> polygons = new List <Polygon>(); polygons.Add(basePolygon); polygons.Add(oppositePolygon); polygons.AddRange(brushSides); outputPolygons = polygons.ToArray(); }