void TranslateToUnity(VoronoiMesh2 voronoi) { regions = new List <GraphLinked.Cell>(); //deflatedCells = new List<Cell>(); frontier = new List <Vector3>(); foreach (VoronoiRegion <Vertex2> region in voronoi.Regions) { float margin = Random.Range(0.1f, 0.5f); bool valid = true; foreach (DelaunayCell <Vertex2> ce in region.Cells) { if (!bounds.Contains(new Vector3(ce.CircumCenter.X, 0, ce.CircumCenter.Y))) { valid = false; break; } } if (!valid) { foreach (DelaunayCell <Vertex2> ce in region.Cells) { //invalid.Add(new Vector3(ce.CircumCenter.X, 0, ce.CircumCenter.Y)); foreach (var si in ce.Simplex.Vertices) { frontier.Add(new Vector3(si.X, 0, si.Y)); } } continue; } Vector3 centroid = Vector3.zero; IList <VoronoiEdge <Vertex2> > edges = region.Edges; valid = Sort(edges); if (!valid) { continue; } // List<Vector3> contour = new List<Vector3>(); List <GraphLinked.Node> contour = new List <GraphLinked.Node>(); foreach (VoronoiEdge <Vertex2> e in edges) { Vertex2 v0 = e.From.CircumCenter; Vector3 p0 = new Vector3(v0.X, 0, v0.Y); Vertex2 v1 = e.To.CircumCenter; Vector3 p1 = new Vector3(v1.X, 0, v1.Y); centroid += p0; var nodeFrom = city.AddNode(p0, false); var nodeNext = city.AddNode(p1, false); contour.Add(nodeFrom); var link = city.AddLink(nodeFrom, nodeNext); } GraphLinked.Cell cell = new GraphLinked.Cell(contour); regions.Add(cell); } }
void GizmosCell(GraphLinked.Cell cell, Vector3 position, bool center = false) { Vector3 centroid = cell.Center + position; var contour = cell.localContour; for (int c = 0; c < contour.Count; ++c) { Vector3 p0 = contour[c] + centroid; Vector3 p1 = contour[(c + 1) % contour.Count] + centroid; Gizmos.DrawLine(p0, p1); } if (center) { Gizmos.DrawCube(centroid, Vector3.one * 0.005f * size); for (int c = 0; c < contour.Count; ++c) { Vector3 p0 = contour[c] + centroid; Gizmos.DrawLine(p0, centroid); } } }
public void Generate(GraphLinked.Cell cell, float floorHeight = 10, float margin = 0) { Vector2 windowScale = Vector2.one * 10; var contour = cell.localContour; Vector3[] points; if (margin > 0) { List <Vector3> pointList = new List <Vector3>(); for (int i = 0; i < contour.Count; ++i) { Vector3 from = contour[i]; Vector3 to = contour[(i + 1) % contour.Count]; pointList.Add(Vector3.Lerp(from, to, margin)); pointList.Add(Vector3.Lerp(from, to, 1 - margin)); } points = pointList.ToArray(); } else { points = contour.ToArray(); } handedness = cell.Handness(); if (filter == null) { filter = GetComponent <MeshFilter>(); } Mesh mesh = filter.mesh; if (mesh != null) { mesh.Clear(); } List <Vector3> vertices = new List <Vector3>(); List <int> triangles = new List <int>(); List <Vector3> normals = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); // CONTOUR int contourCount = points.Length; for (int h = 0; h <= height; ++h) { for (int i = 0; i <= contourCount; ++i) { vertices.Add((points[i % contourCount]) + Vector3.up * h * floorHeight); // TODO normalize using distance between vertices if (i % 2 == 0 && h % 2 == 0) { uvs.Add(new Vector2(0, 0)); } else if (i % 2 != 0 && h % 2 == 0) { uvs.Add(new Vector2(windowScale.x, 0)); } else if (i % 2 == 0 && h % 2 != 0) { uvs.Add(new Vector2(0, windowScale.y)); } else if (i % 2 != 0 && h % 2 != 0) { uvs.Add(new Vector2(windowScale.x, windowScale.y)); } } } int levelCount = contourCount + 1; for (int h = 0; h < height; ++h) { for (int i = 0; i < contourCount; ++i) { int idx = i + h * levelCount; triangles.Add(idx); if (flip) { triangles.Add(idx + 1); triangles.Add(idx + levelCount); } else { triangles.Add(idx + levelCount); triangles.Add(idx + 1); } triangles.Add(idx + 1); if (flip) { triangles.Add(idx + levelCount + 1); triangles.Add(idx + levelCount); } else { triangles.Add(idx + levelCount); triangles.Add(idx + levelCount + 1); } } } // ROOF Vector3 centroid = Vector3.zero; for (int i = 0; i <= contourCount; ++i) { Vector3 vertex = (points[i % contourCount]) + Vector3.up * height * floorHeight; vertices.Add(vertex); uvs.Add(new Vector2(0, 0)); if (i != 0) { centroid += vertex; } } centroid /= contourCount; int centroidIdx = vertices.Count; uvs.Add(new Vector2(0, 0)); vertices.Add(centroid); for (int i = 0; i < contourCount; ++i) { int idx = i + (height + 1) * levelCount; triangles.Add(idx); triangles.Add(centroidIdx); triangles.Add(idx + 1); } mesh.vertices = vertices.ToArray(); mesh.triangles = triangles.ToArray(); mesh.uv = uvs.ToArray(); mesh.RecalculateNormals(); collider = GetComponent <MeshCollider>(); if (collider) { collider.sharedMesh = mesh; } }
void Subdivide(int subdivision = 5) { blockContours = new List <GraphLinked.Cell>(); if (subdivision == 1) { foreach (GraphLinked.Cell cell in regions) { blockContours.Add(cell); } } else { blocks = new List <GraphLinked>(); foreach (GraphLinked.Cell region in regions) { GraphLinked regionGraph = region.AsGraph(); blocks.Add(regionGraph); Bounds bounds = region.Bounds; Vector3 delta = bounds.size / subdivision; bool[,] valid = new bool[subdivision + 1, subdivision + 1]; GraphLinked.Node[,] nodes = new GraphLinked.Node[subdivision + 1, subdivision + 1]; for (int x = 0; x <= subdivision; ++x) { float u = x / (float)subdivision * bounds.size.x + bounds.min.x; for (int z = 0; z <= subdivision; ++z) { float v = z / (float)subdivision * bounds.size.z + bounds.min.z; Vector3 point = new Vector3(u, 0, v); if (region.ContainsPoint(point)) { valid[x, z] = true; nodes[x, z] = regionGraph.AddNode(point); } } } // create internal nodes and links, divide shell edges when intersecting them for (int x = 0; x <= subdivision; ++x) { float u = x / (float)subdivision * bounds.size.x + bounds.min.x; for (int z = 0; z <= subdivision; ++z) { float v = z / (float)subdivision * bounds.size.z + bounds.min.z; if (valid[x, z]) { Vector3 fromPosition = new Vector3(u, 0, v); GraphLinked.Node from = nodes[x, z]; // RIGHT int x2 = x + 1; if (x2 > subdivision || !valid[x2, z]) { float u2 = x2 / (float)subdivision * bounds.size.x + bounds.min.x; Vector3 targetPosition = new Vector3(u2, 0, v); regionGraph.SegmentShell(from, targetPosition); } else { regionGraph.AddLink(nodes[x, z], nodes[x2, z]); city.AddLink(city.AddNode(nodes[x, z].position), city.AddNode(nodes[x2, z].position)); } // LEFT x2 = x - 1; if (x2 < 0 || !valid[x2, z]) { float u2 = x2 / (float)subdivision * bounds.size.x + bounds.min.x; Vector3 targetPosition = new Vector3(u2, 0, v); regionGraph.SegmentShell(from, targetPosition); } // no else: intersections with the edge are done only done right-wards // UP int z2 = z + 1; if (z2 > subdivision || !valid[x, z2]) { float v2 = z2 / (float)subdivision * bounds.size.z + bounds.min.z; Vector3 targetPosition = new Vector3(u, 0, v2); regionGraph.SegmentShell(from, targetPosition); } else { regionGraph.AddLink(nodes[x, z], nodes[x, z2]); city.AddLink(city.AddNode(nodes[x, z].position), city.AddNode(nodes[x, z2].position)); } //DOWN z2 = z - 1; if (z2 < 0 || !valid[x, z2]) { float v2 = z2 / (float)subdivision * bounds.size.z + bounds.min.z; Vector3 targetPosition = new Vector3(u, 0, v2); regionGraph.SegmentShell(from, targetPosition); } // no else: intersections with the edge are done only done up-wards } } } for (int x = 0; x <= subdivision - 1; ++x) { for (int z = 0; z <= subdivision - 1; ++z) { if (valid[x, z] && valid[x + 1, z] && valid[x, z + 1] && valid[x + 1, z + 1]) { List <GraphLinked.Node> contour = new List <GraphLinked.Node>(); contour.Add(nodes[x, z]); contour.Add(nodes[x + 1, z]); contour.Add(nodes[x + 1, z + 1]); contour.Add(nodes[x, z + 1]); GraphLinked.Cell subcell = new GraphLinked.Cell(contour); subcell.Parent = region; blockContours.Add(subcell); } } } List <GraphLinked.Link> unused = new List <GraphLinked.Link>(); foreach (var link in regionGraph.segments) { unused.AddRange(link); } // get the cells at the edges regionGraph.ComputeNeighbours(); while (unused.Count > 0) { List <GraphLinked.Link> contour = new List <GraphLinked.Link>(); GraphLinked.Link link = unused[0]; unused.RemoveAt(0); if (link == null) { continue; } contour.Add(link); Queue <List <GraphLinked.Node> > queueNodes = new Queue <List <GraphLinked.Node> >(); Queue <List <GraphLinked.Link> > queueLinks = new Queue <List <GraphLinked.Link> >(); HashSet <GraphLinked.Node> used = new HashSet <GraphLinked.Node>(); var startNodes = new List <GraphLinked.Node>(); used.Add(link.from); startNodes.Add(link.from); startNodes.Add(link.to); queueNodes.Enqueue(startNodes); List <GraphLinked.Link> startLink = new List <GraphLinked.Link>(); startLink.Add(link); queueLinks.Enqueue(startLink); int count = 0; List <GraphLinked.Node> solutionPath = null; List <GraphLinked.Link> solutionLinks = null; var neighbours = regionGraph.ComputeNeighbours(); while (queueNodes.Count > 0 && count < 100 && solutionPath == null) { List <GraphLinked.Node> currentSolution = queueNodes.Dequeue(); List <GraphLinked.Link> currentSolutionLinks = queueLinks.Dequeue(); GraphLinked.Node current = currentSolution[currentSolution.Count - 1]; used.Add(current); foreach (var nextLink in neighbours[current]) { //flips the edge if needed GraphLinked.Node next = current == nextLink.from ? nextLink.to : nextLink.from; // is it a solution? if (currentSolution.Count > 2 && next == link.from) { solutionPath = currentSolution; solutionLinks = currentSolutionLinks; } //no solution, but it can be navigated else if (!used.Contains(next)) { // single option, no need to create new solution if (neighbours[current].Count == 1) { currentSolution.Add(next); queueNodes.Enqueue(currentSolution); currentSolutionLinks.Add(nextLink); queueLinks.Enqueue(currentSolutionLinks); } // more than one edge, create a new solution for each else if (neighbours[current].Count > 1) { var newSolution = new List <GraphLinked.Node>(currentSolution); newSolution.Add(next); queueNodes.Enqueue(newSolution); var newSolutionLinks = new List <GraphLinked.Link>(currentSolutionLinks); newSolutionLinks.Add(nextLink); queueLinks.Enqueue(newSolutionLinks); } } ++count; } } { if (solutionPath != null) { List <GraphLinked.Node> contourCell = new List <GraphLinked.Node>(); foreach (var entry in solutionPath) { if (contourCell.Count == 0 || Vector3.SqrMagnitude(entry.position - contourCell[contourCell.Count - 1].position) > float.Epsilon) { contourCell.Add(entry); } } if (contourCell.Count > 2) { GraphLinked.Cell building = new GraphLinked.Cell(contourCell); if (building.Area > 0) { foreach (var usedLink in solutionLinks) { if (unused.Contains(usedLink)) { unused.Remove(usedLink); } } building.Parent = region; blockContours.Add(building); } } else { string p = ""; foreach (var element in contourCell) { p += element.ToString() + " "; } Debug.LogWarning("path:" + p); } } else { Debug.Log("STATUS:" + (solutionPath != null ? solutionPath.Count.ToString() : "null") + ", in " + count + " steps"); } } } } } /*foreach (Cell building in buildingContours) * { * building.Deflate(0.1f); * }*/ }