using System.Collections.Generic; using System.Linq; using UnityEngine; namespace Metamesh { public class GoldbergBuilder { public class GoldbergVertexDataOption { public float size = 1; public float sizeX = 1; public float sizeY = 1; public float sizeZ = 1; }; public class GoldbergCreationOption : GoldbergVertexDataOption { public int m; public int n; } public class VertexData { public List vertices; public List indices; public List normals; public List uvs; public List barycentrics; } private static VertexData CreateGoldbergVertexData(GoldbergVertexDataOption options, PolyhedronData goldbergData) { var size = options.size; var sizeX = options.sizeX;// || size || 1; var sizeY = options.sizeY;// || size || 1; var sizeZ = options.sizeZ;// || size || 1; var positions = new List(); var indices = new List(); var normals = new List(); var uvs = new List(); var barycentrics = new List(); var minX = float.MaxValue; var maxX = float.MinValue; var minY = float.MaxValue; var maxY = float.MinValue; for (var v = 0; v < goldbergData.vertex.Count; v++) { minX = Mathf.Min(minX, goldbergData.vertex[v].x * sizeX); maxX = Mathf.Max(maxX, goldbergData.vertex[v].x * sizeX); minY = Mathf.Min(minY, goldbergData.vertex[v].y * sizeY); maxY = Mathf.Max(maxY, goldbergData.vertex[v].y * sizeY); } var index = 0; for (var f = 0; f < goldbergData.face.Count; f++) { var verts = goldbergData.face[f]; if (verts.Any(v => v >= goldbergData.vertex.Count)) { Debug.LogWarning($"Polygon#{f} has some index > {goldbergData.vertex.Count}"); continue; } var a = goldbergData.vertex[verts[0]]; var b = goldbergData.vertex[verts[2]]; var c = goldbergData.vertex[verts[1]]; var ba = b - a; var ca = c - a; var norm = Vector3.Cross(ca, ba).normalized; var x = verts.Average(v => goldbergData.vertex[v].x); var y = verts.Average(v => goldbergData.vertex[v].y); var z = verts.Average(v => goldbergData.vertex[v].z); var centroid = new Vector3(x, y, z); var rot = Quaternion.FromToRotation(norm, Vector3.up); var mtx = Matrix4x4.TRS(Vector3.zero, rot, Vector3.one); var right = mtx.MultiplyVector(a - centroid); var angle = Vector2.SignedAngle(new Vector2(right.x, right.z), Vector2.right) * Mathf.Deg2Rad; for (var v = 0; v < verts.Count; v++) { normals.Add(norm); var pdata = goldbergData.vertex[verts[v]]; var pos = pdata;//new Vector3(pdata.x * sizeX, pdata.y * sizeY, pdata.z * sizeZ); positions.Add(pos); var vCoord = (pdata[1] * sizeY - minY) / (maxY - minY); uvs.Add(new Vector3((pdata[0] * sizeX - minX) / (maxX - minX), vCoord, f)); var dir = mtx.MultiplyVector(pos - centroid); var braycentric = new Vector2(dir.x, dir.z).Rotate(angle).normalized * 0.5f; barycentrics.Add(new Vector4(braycentric.x, braycentric.y, verts.Count, f)); } for (var v = 0; v < verts.Count - 2; v++) { indices.AddRange(new int[] { index, index + v + 1, index + v + 2 }); } index += verts.Count; } return new VertexData() { vertices = positions, indices = indices, normals = normals, uvs = uvs, barycentrics = barycentrics, }; } public static VertexData CreateGoldberg(GoldbergCreationOption options) { var size = options.size; var sizeX = options.sizeX;// || size || 1; var sizeY = options.sizeY;// || size || 1; var sizeZ = options.sizeZ;// || size || 1; var m = options.m;// || 1; var n = options.n;// || 0; if (n > m) { (n, m) = (m, n); Debug.LogWarning("n > m therefore m and n swapped"); } var primTri = new PrimaryIsoTriangle(); primTri.Build(m, n); var geodesicData = GeodesicData.BuildGeodesicData(primTri); var goldbergData = geodesicData.ToGoldbergPolyhedronData(); /* var nbSharedFaces = geodesicData.sharedNodes; var nbUnsharedFaces = geodesicData.poleNodes; var adjacentFaces = geodesicData.adjacentFaces; var nbFaces = nbSharedFaces + nbUnsharedFaces; var nbFacesAtPole = (nbUnsharedFaces - 12) / 12; var faceCenters = geodesicData.vertex.Keys.Select(v => v * size).ToArray(); var faceColors = geodesicData.vertex.Keys.Select(_ => Color.white).ToArray(); */ var vertexData = CreateGoldbergVertexData(options, goldbergData); return vertexData; } } }