// extrude section (2D) into a 3D mesh
        public static Mesh Extrude(Section section, float h)
        {
            Vector3[] vtx;
            int[]     tri;
            Mesh      mesh = new Mesh();

            Polygon poly = PolyTool.Clean(SectTool.ToPoly(section));

            //center = PolyTool.Centroid (poly);
            poly = PolyTool.Recenter(poly, new Vector2(0, 0));

            List <Vector3> ptbottom = poly.Select(v => new Vector3(v.x, TerrainAt(v), v.y)).ToList();
            List <Vector3> pttop    = poly.Select(v => new Vector3(v.x, TerrainAt(v) + h, v.y)).ToList();

            List <int> idxbottom = Triangulate(poly);
            List <int> idxtop    = idxbottom.Select(x => x + poly.Count).ToList();

            idxbottom.Reverse();

            List <int> idxside = new List <int> ();

            for (int i = 0; i < poly.Count; i++)
            {
                idxside.Add(i);
                idxside.Add((i + 1) % poly.Count);
                idxside.Add(i + poly.Count);

                idxside.Add((i + 1) % poly.Count);
                idxside.Add((i + 1) % poly.Count + poly.Count);
                idxside.Add(i + poly.Count);
            }
            List <Vector3> allpts = new List <Vector3> ();

            allpts.AddRange(ptbottom);
            allpts.AddRange(pttop);

            List <int> alltris = new List <int> ();

            alltris.AddRange(idxbottom);
            alltris.AddRange(idxtop);
            alltris.AddRange(idxside);

            vtx = allpts.ToArray();
            tri = alltris.ToArray();

            mesh.vertices  = vtx;
            mesh.triangles = tri;

            return(mesh);
        }
Example #2
0
        // generate city instance
        public static GameObject Generate()
        {
            // output gameobject
            GameObject gout = new GameObject();

            gout.name = "CITY";

            // block plans
            List <Section> sections = new List <Section>();
            // building plans
            List <Section> units = new List <Section>();
            // roads
            List <Road> roads = new List <Road> ();

            // city size
            float tsize = 200;

            Section bedrock = SectTool.Box(0, 0, tsize, tsize);

            sections.Add(bedrock);

            // drawing functions

            System.Action <Section, float, string> MkExtrudeSect =
                delegate(Section s, float h, string matname) {
                Vector2    c = PolyTool.Centroid(SectTool.ToPoly(s));
                Mesh       m = MeshMaker.Extrude(s, h);
                GameObject g = MeshMaker.ToObject(m, matname);

                if (!BadVal(c.x))
                {
                    g.transform.position = new Vector3(c.x, 0, c.y);
                }
                g.name             = matname;
                g.transform.parent = gout.transform;
            };

            System.Action <Vector3, Vector3, Quaternion, string> MkCube
                =
                    delegate(Vector3 pos, Vector3 size, Quaternion rot, string matname) {
                GameObject g = GameObject.CreatePrimitive(PrimitiveType.Cube);
                g.transform.localPosition            = pos;
                g.transform.localScale               = size;
                g.transform.localRotation            = rot;
                g.GetComponent <Renderer>().material = MaterialManager.GetMaterialByName(matname);
                g.name             = matname;
                g.transform.parent = gout.transform;
                };

            System.Action <Vector3, Vector3, Quaternion, string> MkBlob =
                delegate(Vector3 pos, Vector3 size, Quaternion rot, string matname) {
                GameObject g = MeshMaker.ToObject(MeshMaker.Blob(size), matname);
                g.transform.localPosition            = pos;
                g.transform.localScale               = size;
                g.transform.localRotation            = rot;
                g.GetComponent <Renderer>().material = MaterialManager.GetMaterialByName(matname);
                g.name             = matname;
                g.transform.parent = gout.transform;
            };

            System.Action <Vector2> MkTree =
                delegate(Vector2 pos) {
                float w = 0.07f * Random.Range(0.8f, 1.5f);
                float h = Random.Range(0.8f, 1.5f);
                MkCube(new Vector3(pos.x, h / 2, pos.y),
                       new Vector3(w, h, w),
                       Quaternion.Euler(new Vector3(
                                            Random.Range(-0.2f, 0.2f),
                                            Random.Range(-0.2f, 0.2f),
                                            Random.Range(-0.2f, 0.2f)
                                            )),
                       "VEGETATION");
                for (int i = 0; i < 5; i++)
                {
                    float r = Random.Range(1f, 2f);
                    MkBlob(new Vector3(pos.x, h, pos.y)
                           + new Vector3(
                               Random.Range(-0.5f, 0.5f),
                               Random.Range(-0.2f, 0.8f),
                               Random.Range(-0.5f, 0.5f)),
                           new Vector3(
                               r, r, r
                               ),
                           Random.rotation,
                           "VEGETATION");
                }
            };
            System.Action <Vector2> MkStreetLight =
                delegate(Vector2 pos) {
                float w = 0.05f;
                float h = 1.2f;
                MkCube(new Vector3(pos.x, h / 2, pos.y),
                       new Vector3(w, h, w),
                       Quaternion.identity,
                       "POLE");
                MkCube(new Vector3(pos.x, h, pos.y),
                       new Vector3(0.1f, 0.15f, 0.1f),
                       Quaternion.identity,
                       "STATIC");
            };
            System.Action <Vector2> MkSign =
                delegate(Vector2 pos) {
                float w = 0.05f;
                float h = 1f;
                MkCube(new Vector3(pos.x, h / 2, pos.y),
                       new Vector3(w, h, w),
                       Quaternion.identity,
                       "POLE");
                for (int i = 0; i < Random.Range(1, 4); i++)
                {
                    MkCube(new Vector3(pos.x, h - i * 0.3f, pos.y + 0.03f),
                           new Vector3(0.24f, 0.24f, 0.02f),
                           Quaternion.identity,
                           "TRAFFIC_SIGN");
                }
            };
            System.Action <Vector2> MkTrafficLight =
                delegate(Vector2 pos) {
                float w = 0.05f;
                float h = 1f;
                MkCube(new Vector3(pos.x, h / 2, pos.y),
                       new Vector3(w, h, w),
                       Quaternion.identity,
                       "POLE");

                MkCube(new Vector3(pos.x, h, pos.y),
                       new Vector3(0.1f, 0.3f, 0.08f),
                       Quaternion.identity,
                       "TRAFFIC_LIGHT");
            };
            System.Action <Vector2> MkTrafficLightBig =
                delegate(Vector2 pos) {
                float      w = 0.05f;
                float      h = 2f;
                float      l = Random.Range(1, 4);
                float      r = Random.Range(0f, Mathf.PI * 2);
                Quaternion R = Quaternion.Euler(new Vector3(0, 90 - r * 180 / Mathf.PI, 0));
                MkCube(new Vector3(pos.x, h / 2, pos.y),
                       new Vector3(w, h, w),
                       Quaternion.identity,
                       "POLE");
                MkCube(new Vector3(pos.x + (l / 2) * Mathf.Cos(r), h, pos.y + (l / 2) * Mathf.Sin(r)),
                       new Vector3(w, w, l),
                       R,
                       "POLE");

                for (float i = 0; i < l; i += 0.5f)
                {
                    if (Random.value < 0.6f || i == 0)
                    {
                        MkCube(new Vector3(pos.x + (l - i) * Mathf.Cos(r), h, pos.y + (l - i) * Mathf.Sin(r)),
                               new Vector3(0.1f, 0.3f, 0.08f),
                               R,
                               "TRAFFIC_LIGHT");
                    }
                    else
                    {
                        MkCube(new Vector3(pos.x + (l - i) * Mathf.Cos(r), h, pos.y + (l - i) * Mathf.Sin(r))
                               + R * new Vector3(0.03f, 0, 0f),
                               new Vector3(0.02f, 0.24f, 0.24f),
                               R,
                               "TRAFFIC_SIGN");
                    }
                }
                for (int i = 0; i < Random.Range(1, 3); i++)
                {
                    MkCube(new Vector3(pos.x, h / 2 - i * 0.3f, pos.y + 0.03f),
                           new Vector3(0.24f, 0.24f, 0.02f),
                           Quaternion.identity,
                           "TRAFFIC_SIGN");
                }
            };

            MeshMaker.Triangulate = PolyTool.QkTriangulate;
            MkExtrudeSect(bedrock, 0.05f, "GROUND");

            for (int i = 0; i < 10; i++)
            {
                List <Edge> edges;
                sections = SectTool.SplitAll(sections, out edges);

                for (int j = 0; j < edges.Count; j++)
                {
                    roads.Add(new Road(edges[j], 6 - (float)i / 2));
                }
            }

            // generate structures along roads
            for (int i = 0; i < roads.Count; i++)
            {
                MeshMaker.Triangulate = PolyTool.TbTriangulate;
                Section s = EdgeTool.Tubify(roads[i].edge, roads[i].width / 2);

                MkExtrudeSect(s, 0.07f, "ROAD");

                Edge e0 = s[0];
                Edge e1 = s[1];

                Section s0 = EdgeTool.Tubify(e0, roads[i].width / 2);
                Section s1 = EdgeTool.Tubify(e1, roads[i].width / 2);
                MkExtrudeSect(s0, 0.06f, "SIDEWALK");
                MkExtrudeSect(s1, 0.06f, "SIDEWALK");

                System.Func <Vector2, bool> isCross = delegate(Vector2 pt) {
                    for (int n = 0; n < roads.Count; n++)
                    {
                        if (roads [n].edge.Count >= 1)
                        {
                            Edge e = roads [n].edge;
                            if (Vector2.Distance(pt, e [0]) < 3 ||
                                Vector2.Distance(pt, e [e.Count - 1]) < 3)
                            {
                                return(true);
                            }
                        }
                    }
                    return(false);
                };

                for (int j = 2; j < Mathf.Max(0, Mathf.Min(e0.Count, e1.Count) - 2); j++)
                {
                    int reso = 24;
                    for (int k = 0; k < reso; k++)
                    {
                        Vector2 p0 = Vector2.Lerp(e0 [j], e0 [j + 1], ((float)k) / reso);
                        Vector2 p1 = Vector2.Lerp(e1 [j], e1 [j + 1], ((float)k) / reso);

                        bool ic0 = isCross(p0);
                        bool ic1 = isCross(p1);

                        if (k % 8 == 0)
                        {
                            if (!ic0)
                            {
                                MkStreetLight(p0);
                            }
                            else if (Random.value < 0.3f)
                            {
                                if (Random.value < 0.5f)
                                {
                                    MkTrafficLightBig(p0);
                                }
                                else
                                {
                                    MkTrafficLight(p0);
                                }
                            }
                            if (!ic1)
                            {
                                MkStreetLight(p1);
                            }
                            else if (Random.value < 0.3f)
                            {
                                if (Random.value < 0.5f)
                                {
                                    MkTrafficLightBig(p1);
                                }
                                else
                                {
                                    MkTrafficLight(p1);
                                }
                            }
                        }
                        else if (k % 8 == 4)
                        {
                            if (!ic0)
                            {
                                MkTree(p0);
                            }
                            if (!ic1)
                            {
                                MkTree(p1);
                            }
                        }
                        else if (Random.value < 0.05f)
                        {
                            if (!ic0)
                            {
                                MkSign(p0);
                            }
                            if (!ic1)
                            {
                                MkSign(p1);
                            }
                        }
                    }
                }
            }

            for (int i = 0; i < sections.Count; i++)
            {
                units.AddRange(SectTool.GridSection(sections [i]));
            }

            for (int i = 0; i < units.Count; i++)
            {
                Vector2 c = PolyTool.Centroid(SectTool.ToPoly(units [i]));

                float d2c = Vector2.Distance(c, new Vector2(tsize / 2, tsize / 2));

                float a = SectTool.EstArea(units [i]);

                float h = Mathf.PerlinNoise(c.x * 0.1f, c.y * 0.1f) * 200 / Mathf.Pow(d2c, 0.5f) / Mathf.Pow(a, 0.5f) + Random.Range(-5.0f, 5.0f);
                MeshMaker.Triangulate = PolyTool.QkTriangulate;
                MkExtrudeSect(units[i], Mathf.Max(h, 1f), "BUILDING");
            }
            for (int i = 0; i < 4000; i++)
            {
                GameObject car = new GameObject();
                car.transform.parent = gout.transform;
                car.AddComponent <Car> ();
                car.GetComponent <Car> ().roads = roads;
            }
            return(gout);
        }