예제 #1
0
    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);
        }
    }
예제 #2
0
    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);
            }
        }
    }
예제 #3
0
    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;
        }
    }
예제 #4
0
    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);
         * }*/
    }