public static RenderGeometry CreateIcosidodecahedronGeometry(float size) { RenderGeometry geometry = new RenderGeometry(); float goldenRatio = (1 + Mathf.Sqrt(5)) / 2; float dL = size / 2; float dM = dL / 2; float dS = dM / goldenRatio; float dL2 = Mathf.Lerp(dL, dS * 2, 0.5f); var corners = new Dictionary <IntVector3, Vertex>(); foreach (var keyAndPosition in Combine( VertexSymmetryGroup("100", Key(2, 0, 0), Vec(dL, 0, 0)), VertexSymmetryGroup("211", Key(2, 1, 1), Vec(dL2, dS, dM)))) { corners[keyAndPosition.Key] = geometry.CreateVertex(keyAndPosition.Value); } foreach (IntVector3[] keys in Combine( FaceSymmetryGroup("101", Key(2, 0, 0), Key(2, 1, 1), Key(2, -1, 1)), FaceSymmetryGroup("111", Key(2, 1, 1), Key(1, 2, 1), Key(1, 1, 2)), FaceSymmetryGroup("110", Key(1, 2, 1), Key(2, 1, 1), Key(2, 0, 0), Key(2, 1, -1), Key(1, 2, -1)))) { geometry.CreateFace(keys.Select(key => corners[key]).ToArray()); } return(geometry); }
public static RenderGeometry CreateRhombicuboctahedronGeometry(float size, float ratio) { if (ratio <= 0) { return(CreateCubeGeometry(Vector3.one * size, new int[] { 1, 1, 1 })); } if (ratio >= 1) { return(CreateOctahedronGeometry(size, 1)); } RenderGeometry geometry = new RenderGeometry(); var corners = new Dictionary <IntVector3, Vertex>(); foreach (var keyAndPosition in VertexSymmetryGroup("211", Key(2, 1, 1), Vec(1, 1 - ratio, 1 - ratio) * (size / 2))) { corners[keyAndPosition.Key] = geometry.CreateVertex(keyAndPosition.Value); } foreach (IntVector3[] keys in Combine( FaceSymmetryGroup("100", Key(2, -1, -1), Key(2, 1, -1), Key(2, 1, 1), Key(2, -1, 1)), FaceSymmetryGroup("110", Key(2, 1, -1), Key(1, 2, -1), Key(1, 2, 1), Key(2, 1, 1)), FaceSymmetryGroup("111", Key(2, 1, 1), Key(1, 2, 1), Key(1, 1, 2)))) { geometry.CreateFace(keys.Select(key => corners[key]).ToArray()); } return(geometry); }
public static RenderGeometry CreateCubeFrameGeometry(float size, float ratio) { RenderGeometry geometry = new RenderGeometry(); var corners = new Dictionary <IntVector3, Vertex>(); var lengths = new Dictionary <int, float> { [-2] = -size / 2, [-1] = -size / 2 * ratio, [1] = size / 2 * ratio, [2] = size / 2 }; foreach (int x in lengths.Keys) { foreach (int y in lengths.Keys) { foreach (int z in lengths.Keys) { corners[Key(x, y, z)] = geometry.CreateVertex(new Vector3(lengths[x], lengths[y], lengths[z])); } } } foreach (IntVector3[] keys in Combine( FaceSymmetryGroup("211", Key(2, 1, 1), Key(2, 2, 1), Key(2, 2, 2), Key(2, 1, 2)), FaceSymmetryGroup("210", Key(2, 1, -1), Key(2, 2, -1), Key(2, 2, 1), Key(2, 1, 1)), FaceSymmetryGroup("210", Key(1, 1, -1), Key(2, 1, -1), Key(2, 1, 1), Key(1, 1, 1)))) { geometry.CreateFace(keys.Select(i => corners[i]).ToArray()); } return(geometry); }
public static RenderGeometry CreateCuboctahedronGeometry(float size, float ratio) { if (ratio <= 0) { return(CreateTetrahedronGeometry(size, 1)); } if (ratio >= 1) { RenderGeometry result = CreateTetrahedronGeometry(size, 1); result.ApplyRotation(Quaternion.AngleAxis(90, Vector3.up)); return(result); } RenderGeometry geometry = new RenderGeometry(); var corners = new Dictionary <IntVector3, Vertex>(); foreach (var symmetry in Symmetry.SymmetryGroup("110")) { IntVector3 key = symmetry.Apply(Key(1, 1, 0)); Vector3 position = symmetry.Apply(Vec(1, 1, (1 - ratio * 2) * (symmetry.isNegative ? -1 : 1)) * (size / 2)); corners[key] = geometry.CreateVertex(position); } foreach (IntVector3[] keys in Combine( FaceSymmetryGroup("100", Key(1, 0, -1), Key(1, 1, 0), Key(1, 0, 1), Key(1, -1, 0)), FaceSymmetryGroup("111", Key(1, 1, 0), Key(0, 1, 1), Key(1, 0, 1)))) { geometry.CreateFace(keys.Select(key => corners[key]).ToArray()); } return(geometry); }
private RenderGeometry BuildTileBaseGeometry() { var geometry = new RenderGeometry(); parent.tile.face.edges.ForEach(e => geometry.CreateVertex(e.vertex.p - parent.faceCenter)); geometry.CreateFace(geometry.vertices.ToArray()); new FaceCurving(BASE_CURVATURE).Apply(geometry); return(geometry); }
private RenderGeometry BuildTileBlockGeometry() { var geometry = new RenderGeometry(); parent.tile.face.edges.ForEach(e => geometry.CreateVertex(e.vertex.p - parent.faceCenter)); parent.tile.face.edges.ForEach(e => geometry.CreateVertex(CalculateTileTopVertexPosition(e))); int n = geometry.vertices.Count / 2; for (int i = 0; i < n; i++) { geometry.CreateFace(geometry.vertices[i], geometry.vertices[(i + 1) % n], geometry.vertices[(i + 1) % n + n], geometry.vertices[i + n]); } geometry.CreateFace(Enumerable.Range(n, n).Select(i => geometry.vertices[i]).ToArray()); new FaceMerging(1f).Apply(geometry); new FaceCurving(BLOCK_CURVATURE).Apply(geometry); new EdgeSmoothing(BLOCK_SMOOTH_RADIUS, 10).Apply(geometry); return(geometry); }
public static RenderGeometry CreateRhombicosidodecahedronGeometry(float size, float ratio) { if (ratio <= 0) { return(CreateIcosahedronGeometry(size, 1)); } if (ratio >= 1) { return(CreateDodecahedronGeometry(size)); } RenderGeometry geometry = new RenderGeometry(); float goldenRatio = (1 + Mathf.Sqrt(5)) / 2; float dL = size / 2; float dM = dL / goldenRatio; float dS = dM / goldenRatio; float dLtoM = Mathf.Lerp(dL, dM, ratio); float dLtoS = Mathf.Lerp(dL, dS, ratio); float dMtoL = Mathf.Lerp(dM, dL, ratio); float dMto0 = Mathf.Lerp(dM, 0, ratio); float d0toM = dM * ratio; float d0toS = dS * ratio; var corners = new Dictionary <IntVector3, Vertex>(); foreach (var keyAndPosition in Combine( VertexSymmetryGroup("110", Key(3, 2, 0), Vec(dLtoS, dMtoL, 0)), VertexSymmetryGroup("211", Key(3, 1, 1), Vec(dL, dMto0, d0toS)), VertexSymmetryGroup("211", Key(3, 2, 1), Vec(dLtoM, dM, d0toM)))) { corners[keyAndPosition.Key] = geometry.CreateVertex(keyAndPosition.Value); } foreach (IntVector3[] keys in Combine( FaceSymmetryGroup("101", Key(3, -1, 1), Key(3, 1, 1), Key(2, 0, 3)), FaceSymmetryGroup("111", Key(3, 2, 1), Key(1, 3, 2), Key(2, 1, 3)), FaceSymmetryGroup("110", Key(3, 1, -1), Key(3, 2, -1), Key(3, 2, 0), Key(3, 2, 1), Key(3, 1, 1)), FaceSymmetryGroup("211", Key(3, 1, 1), Key(3, 2, 1), Key(2, 1, 3), Key(2, 0, 3)), FaceSymmetryGroup("100", Key(3, -1, -1), Key(3, 1, -1), Key(3, 1, 1), Key(3, -1, 1)))) { geometry.CreateFace(keys.Select(key => corners[key]).ToArray()); } return(geometry); }
public void Apply(RenderGeometry geometry) { var splitHalfedges = new HashSet <Halfedge>(geometry.halfedges.Where(e => IsValidEdge(e, geometry))); var additionalBoundaryHalfedges = new HashSet <Halfedge>(); var splitVertices = splitHalfedges.Select(e => e.vertex).Distinct().ToArray(); var splitHalfedgeToNewVertexPosition = new Dictionary <Halfedge, Vector3>(); var splitHalfedgeToVertexNormal = new Dictionary <Halfedge, Vector3>(); var splitHalfedgeToPreviousOpposite = new Dictionary <Halfedge, Halfedge>(); var splitVertexToSurroundingSplitHalfedges = new Dictionary <Vertex, Halfedge[]>(); // Precalculates new vertex positions. Memorize old normals and old opposites of split halfedges. foreach (Halfedge edge in splitHalfedges) { Halfedge nextSplitEdge = NextEdgeThat(edge, e => splitHalfedges.Contains(e) || e.isBoundary); if (nextSplitEdge != edge) { splitHalfedgeToNewVertexPosition[edge] = CalculateVertexPosition(edge, nextSplitEdge.opposite, geometry); if (nextSplitEdge.isBoundary) { Halfedge otherEdge = nextSplitEdge.next.opposite; Halfedge otherNextSplitEdge = NextEdgeThat(edge, e => splitHalfedges.Contains(e)); splitHalfedgeToNewVertexPosition[otherEdge] = CalculateVertexPosition(otherEdge, otherNextSplitEdge.opposite, geometry); additionalBoundaryHalfedges.Add(otherEdge); splitHalfedgeToVertexNormal[otherEdge] = geometry.GetEffectiveNormal(otherEdge); } } else { splitHalfedgeToNewVertexPosition[edge] = edge.vertex.p; } splitHalfedgeToVertexNormal[edge] = geometry.GetEffectiveNormal(edge); splitHalfedgeToPreviousOpposite[edge] = edge.opposite; } // Memorize the old connected split halfedges around any given split vertex. foreach (Vertex vertex in splitVertices) { splitVertexToSurroundingSplitHalfedges[vertex] = vertex.edges.Where(e => splitHalfedges.Contains(e) || additionalBoundaryHalfedges.Contains(e)).ToArray(); } // Split the geometry. A pair of halfedges only needs to be split once. foreach (Halfedge edge in splitHalfedges) { if (!edge.opposite.isBoundary) { geometry.DisconnectEdge(edge); } } // Set new vertex positions foreach (Halfedge edge in splitHalfedges.Concat(additionalBoundaryHalfedges)) { edge.vertex.p = splitHalfedgeToNewVertexPosition[edge]; } var vertexNormals = splitHalfedgeToVertexNormal.ToDictionary(entry => entry.Key.vertex, entry => entry.Value); void AddFace(params Vertex[] faceVertices) { Face newFace = geometry.CreateFace(faceVertices.ToArray()); geometry.SetFaceType(newFace, RenderGeometry.FaceType.Smooth); newFace.edges.ForEach(e => geometry.SetNormal(e, vertexNormals[e.vertex])); } // Create one edge face for each split edge. foreach (Halfedge edge in splitHalfedges) { if (!edge.opposite.isBoundary) { continue; } Halfedge otherEdge = splitHalfedgeToPreviousOpposite[edge]; var faceVertices = new List <Vertex>(); AddIfNotPresent(faceVertices, edge.vertex); AddIfNotPresent(faceVertices, edge.prev.vertex); AddIfNotPresent(faceVertices, otherEdge.vertex); AddIfNotPresent(faceVertices, otherEdge.prev.vertex); if (faceVertices.Count >= 3) { AddFace(faceVertices.ToArray()); } } // Create one corner face for each split vertex. foreach (Vertex vertex in splitVertices) { Halfedge[] surroundingSplitHalfedges = splitVertexToSurroundingSplitHalfedges[vertex]; int n = surroundingSplitHalfedges.Length; if (n < 3) { continue; } Vertex[] faceVertices = surroundingSplitHalfedges.Select(e => e.vertex).Reverse().ToArray(); if (n == 3) { AddFace(faceVertices.ToArray()); } else { Vertex faceCenter = geometry.CreateVertex(faceVertices.Average(v => v.p)); vertexNormals[faceCenter] = faceVertices.Average(v => vertexNormals[v]).normalized; for (int i = 0; i < n; i++) { AddFace(faceVertices[i], faceVertices[(i + 1) % n], faceCenter); } } } }
public static RenderGeometry CreateBuildingBlockGeometry(Vector3 size, bool[,,] corners) { RenderGeometry geometry = new RenderGeometry(); bool cornerUsed(IntVector3 key) => corners[(key.x + 1) / 2, (key.y + 1) / 2, (key.z + 1) / 2]; var cornerVerts = new Dictionary <IntVector3, Vertex>(); foreach (IntVector3 key in IntVector3.allTriaxialDirections) { if (cornerUsed(key)) { cornerVerts[key] = geometry.CreateVertex(key * (size / 2)); } } void construct(string symmetryType, IntVector3[] faceKeys, IntVector3[] outsideKeys) { int n = faceKeys.Length; foreach (Symmetry symmetry in Symmetry.SymmetryGroup(symmetryType)) { if (symmetry.Apply(outsideKeys).Any(key => cornerUsed(key))) { continue; } IntVector3[] newFaceKeys = symmetry.Apply(faceKeys); if (newFaceKeys.All(key => cornerUsed(key))) { geometry.CreateFace(newFaceKeys.Select(key => cornerVerts[key]).ToArray()); } else if (n == 4) { for (int i = 0; i < 4; i++) { IntVector3[] subFaceKeys = new[] { newFaceKeys[i], newFaceKeys[(i + 1) % 4], newFaceKeys[(i + 2) % 4] }; if (subFaceKeys.All(key => cornerUsed(key))) { geometry.CreateFace(subFaceKeys.Select(key => cornerVerts[key]).ToArray()); } } } } } construct("100", new[] { Key(1, -1, -1), Key(1, 1, -1), Key(1, 1, 1), Key(1, -1, 1) }, new IntVector3[0]); construct("100", new[] { Key(-1, -1, -1), Key(-1, 1, -1), Key(-1, 1, 1), Key(-1, -1, 1) }, new[] { Key(1, -1, -1), Key(1, 1, -1), Key(1, 1, 1), Key(1, -1, 1) }); construct("110", new[] { Key(-1, 1, -1), Key(-1, 1, 1), Key(1, -1, 1), Key(1, -1, -1) }, new[] { Key(1, 1, -1), Key(1, 1, 1) }); construct("111", new[] { Key(-1, 1, 1), Key(1, -1, 1), Key(1, 1, -1) }, new[] { Key(1, 1, 1) }); construct("111", new[] { Key(1, -1, -1), Key(-1, 1, -1), Key(-1, -1, 1) }, new[] { Key(-1, 1, 1), Key(1, -1, 1), Key(1, 1, -1), Key(1, 1, 1) }); return(geometry); }