Beispiel #1
0
        void ImportSingle(double originX, double originY)
        {
            string jsonfilename = $" panden_{originX}.0_{originY}.0.json";

            float  tileSize = 1000;
            string filepath = Path.Combine(basefilepath, jsonfilename);

            if (File.Exists(filepath))
            {
                CityModel cm = new CityModel(filepath, jsonfilename);

                var buildings = cm.LoadBuildings(1);

                //type voetpad
                Mesh buildingMesh = CreateCityObjectMesh(cm, "Building", originX, originY, tileSize, null, null, true);


                buildingMesh.uv2 = RDuv2(buildingMesh.vertices, CoordConvert.RDtoUnity(new Vector3RD(originX, originY, 0)), tileSize);
                //  Physics.BakeMesh(buildingMesh.GetInstanceID(), false);

                var lod1name = $"{filePrefix}_{originX}-{originY}-lod1.mesh";

                AssetDatabase.CreateAsset(buildingMesh, Path.Combine(destinationPath, lod1name));
                Debug.Log(lod1name);
            }
        }
        /// <summary>
        /// Load all the large ground tiles from AssetBundles, spawn it in our world, and start filling it with the trees that match the tile
        /// its RD coordinate rectangle. The tiles are named after the RD coordinates in origin at the bottomleft of the tile.
        /// </summary>
        private IEnumerator TraverseTileFiles()
        {
            var info     = new DirectoryInfo(sourceGroundTilesFolder);
            var fileInfo = info.GetFiles();

            var currentFile = 0;

            while (currentFile < fileInfo.Length)
            {
                FileInfo file = fileInfo[currentFile];
                if (!file.Name.Contains(".manifest") && file.Name.Contains("_"))
                {
                    Debug.Log($"Filling tile {currentFile}/{fileInfo.Length} {file.Name}");
                    yield return(new WaitForEndOfFrame());


                    string[] splitted    = file.Name.Split('_');
                    string[] coordinates = splitted[1].Split('-');

                    Vector3RD tileRDCoordinatesBottomLeft = new Vector3RD(double.Parse(coordinates[0]), double.Parse(coordinates[1]), 0);

                    var assetBundleTile = AssetBundle.LoadFromFile(file.FullName);

                    var mesh = assetBundleTile.LoadAllAssets <Mesh>().First();

                    if (mesh.bounds.size == Vector3.zero)
                    {
                        Debug.Log($"mesh bound is zero {file.Name}");
                        currentFile++;
                        continue;
                    }

                    GameObject newTile = new GameObject();
                    newTile.isStatic = true;
                    newTile.name     = file.Name;
                    newTile.AddComponent <MeshFilter>().sharedMesh   = mesh;
                    newTile.AddComponent <MeshCollider>().sharedMesh = mesh;
                    newTile.AddComponent <MeshRenderer>().material   = previewMaterial;
                    newTile.GetComponent <MeshRenderer>().materials  = _terrainMaterials.ToArray();

                    newTile.transform.position = CoordConvert.RDtoUnity(tileRDCoordinatesBottomLeft);

                    GameObject treeRoot = new GameObject();
                    treeRoot.name = file.Name.Replace("terrain", "trees");
                    treeRoot.transform.position = newTile.transform.position;

                    yield return(new WaitForEndOfFrame());                    //Make sure collider is processed

                    // yield return new WaitForSeconds(0.3f);


                    SpawnTreesInTile(treeRoot, tileRDCoordinatesBottomLeft);
                }
                currentFile++;
            }
        }
 private void OnDrawGizmos()
 {
     Gizmos.color = Color.white;
     foreach (var tileList in tileDistances)
     {
         foreach (var tile in tileList)
         {
             Gizmos.DrawWireCube(CoordConvert.RDtoUnity(new Vector3(tile.x + 500, tile.y + 500, 0)), new Vector3(1000, 100, 1000));
         }
     }
 }
 public Vector3 GetUnityPoint(double x, double y, double z)
 {
     if (Config.activeConfiguration.sewerageApiType == SewerageApiType.Amsterdam)
     {
         return(CoordConvert.WGS84toUnity(new Vector3WGS(x, y, z + Config.activeConfiguration.zeroGroundLevelY)));
     }
     else
     {
         return(CoordConvert.RDtoUnity(new Vector3RD(x, y, z + Config.activeConfiguration.zeroGroundLevelY)));
     }
 }
Beispiel #5
0
    //private void HandleInsideTile(TerrainTile terrainTile, int X, int Y)
    // {
    //     if (terrainTile == null)
    //     {
    //         activeTiles--;
    //         return;
    //     }
    //     Debug.Log(X + "-" + Y + " :insideTile");
    //     Vector3WGS centerWGS = TerrainTileCenterWGS(X, Y);
    //     Vector3 centerUnity = CoordConvert.WGS84toUnity(extentWGS.x, extentWGS.y);
    //     centerUnity.y = 0;
    //     Vector3RD[] verticesRD = getVerticesRD(terrainTile, X, Y, centerWGS);
    //     Vector3[] verticesUnity = VerticesRDtoUnity(verticesRD, centerUnity);
    //     int[] triangles = getTriangles(terrainTile);
    //     Mesh newSubMesh = new Mesh();
    //     newSubMesh.vertices = verticesUnity;
    //     newSubMesh.triangles = triangles;
    //     newSubMesh.uv = getUVs(verticesRD);
    //     newSubMesh.RecalculateNormals();
    //    submeshes.Add(newSubMesh);
    //     activeTiles--;
    // }
    private Vector3[] VerticesRDtoUnity(Vector3RD[] verticesRD, Vector3 unityOrigin)
    {
        int vertexcount = verticesRD.Length;

        Vector3[] verticesUnity = new Vector3[vertexcount];
        for (int i = 0; i < vertexcount; i++)
        {
            verticesUnity[i] = CoordConvert.RDtoUnity(verticesRD[i]) - unityOrigin;
        }
        return(verticesUnity);
    }
        /// <summary>
        /// Load all the large ground tiles from AssetBundles, spawn it in our world, and start filling it with the trees that match the tile
        /// its RD coordinate rectangle. The tiles are named after the RD coordinates in origin at the bottomleft of the tile.
        /// </summary>
        private IEnumerator TraverseTileFiles()
        {
            var info     = new DirectoryInfo(sourceGroundTilesFolder);
            var fileInfo = info.GetFiles();

            var currentFile = 0;

            while (currentFile < fileInfo.Length)
            {
                FileInfo file = fileInfo[currentFile];
                if (!file.Name.Contains(".manifest") && file.Name.Contains("_"))
                {
                    Debug.Log("Filling tile " + currentFile + "/" + fileInfo.Length);
                    yield return(new WaitForEndOfFrame());

                    string filename = file.Name;
                    filename = filename.Replace("terrain_", "");
                    string[] coordinates = filename.Split('-');

                    Vector3RD tileRDCoordinatesBottomLeft = new Vector3RD(double.Parse(coordinates[0], System.Globalization.CultureInfo.InvariantCulture), double.Parse(coordinates[1], System.Globalization.CultureInfo.InvariantCulture), 0);
                    Vector3RD tileCenter          = new Vector3RD(tileRDCoordinatesBottomLeft.x + 500, tileRDCoordinatesBottomLeft.y + 500, tileRDCoordinatesBottomLeft.z);
                    var       assetBundleTile     = AssetBundle.LoadFromFile(file.FullName);
                    Mesh[]    meshesInAssetbundle = new Mesh[0];
                    try
                    {
                        meshesInAssetbundle = assetBundleTile.LoadAllAssets <Mesh>();
                    }
                    catch (Exception)
                    {
                        Debug.Log("Could not find a mesh in this assetbundle.");
                        assetBundleTile.Unload(true);
                    }

                    GameObject newTile = new GameObject();
                    newTile.isStatic = true;
                    newTile.name     = file.Name;
                    newTile.AddComponent <MeshFilter>().sharedMesh   = meshesInAssetbundle[0];
                    newTile.AddComponent <MeshCollider>().sharedMesh = meshesInAssetbundle[0];

                    newTile.AddComponent <MeshRenderer>().material = previewMaterial;
                    newTile.transform.position = CoordConvert.RDtoUnity(tileCenter);

                    GameObject treeRoot = new GameObject();
                    treeRoot.name = file.Name.Replace("terrain", "trees");
                    treeRoot.transform.position = newTile.transform.position;

                    yield return(new WaitForEndOfFrame());                    //Make sure collider is processed

                    SpawnTreesInTile(treeRoot, tileRDCoordinatesBottomLeft);
                }
                currentFile++;
            }
        }
        private GameObject CreateNewGameObject(AssetBundle assetBundle, TileChange tileChange)
        {
            container = new GameObject();

            container.name               = tileChange.X.ToString() + "-" + tileChange.Y.ToString();
            container.transform.parent   = transform.gameObject.transform;
            container.layer              = container.transform.parent.gameObject.layer;
            container.transform.position = CoordConvert.RDtoUnity(new Vector2(tileChange.X + 500, tileChange.Y + 500));

            container.SetActive(isEnabled);
            //Mesh[] meshesInAssetbundle = new Mesh[0];
            try
            {
                meshesInAssetbundle = assetBundle.LoadAllAssets <Mesh>();
            }
            catch (Exception)
            {
                Destroy(container);
                assetBundle.Unload(true);
                return(null);
            }
            mesh = meshesInAssetbundle[0];

            int count = mesh.vertexCount;

            // creating the UV-s runtime takes a lot of time and causes the garbage-collector to kick in.
            // uv's should be built in in to the meshes in the assetbundles.
            if (addHighlightuvs)
            {
                uvs = new Vector2[count];
                for (int i = 0; i < count; i++)
                {
                    uvs[i] = (defaultUV);
                }
                mesh.uv2 = uvs;
            }

            container.AddComponent <MeshFilter>().sharedMesh = mesh;

            meshRenderer = container.AddComponent <MeshRenderer>();
            meshRenderer.sharedMaterials   = DefaultMaterialList.ToArray();
            meshRenderer.shadowCastingMode = tileShadowCastingMode;

            if (createMeshcollider)
            {
                container.AddComponent <MeshCollider>().sharedMesh = mesh;
            }

            assetBundle.Unload(false);

            return(container);
        }
        void ReadTreesFromCsv()
        {
            var lines = File.ReadAllLines(CsvFile);

            foreach (var line in lines.Skip(1))
            {
                try
                {
                    var columns = line.Split(';');
                    var tree    = new Tree();

                    tree.OBJECTNUMMER = columns[0];
                    tree.Soortnaam_NL = columns[1];
                    tree.Boomhoogte   = columns[2];
                    tree.Plantjaar    = int.Parse(columns[3]);
                    tree.RD           = new Vector3RD(Convert.ToDouble(columns[5]), Convert.ToDouble(columns[6]), 0);

                    //var longlat = ConvertToLatLong(tree.RD.x, tree.RD.y);

                    tree.position = CoordConvert.RDtoUnity(tree.RD);
                    //tree.position = CoordConvert.WGS84toUnity(longlat.longitude, longlat.latitude);


                    tree.averageTreeHeight = EstimateTreeHeight(tree.Boomhoogte);
                    tree.prefab            = FindClosestPrefabTypeByName(tree.Soortnaam_NL);
                    //tree.prefab = TestCube;
                    trees.Add(tree);
                }
                catch
                {
                }
            }

            //398 soorten bomen
            var soorten    = trees.GroupBy(o => o.Soortnaam_NL).ToArray();
            var hoogtrd    = trees.GroupBy(o => o.Boomhoogte).ToArray();
            var oldestTree = trees.Min(o => o.Plantjaar);

            Debug.Log($"Aantal bomen:{trees.Count} soorten:{soorten.Length} Oudste boom:{oldestTree}");

            var minx = trees.Min(o => o.RD.x);
            var miny = trees.Min(o => o.RD.y);
            var maxx = trees.Max(o => o.RD.x);
            var maxy = trees.Max(o => o.RD.y);

            var avgHoogteMin = trees.Min(o => o.averageTreeHeight);
            var avgHoogteMax = trees.Max(o => o.averageTreeHeight);

            Debug.Log($"minx:{minx} maxx:{maxx} miny:{miny} maxy:{maxy}");

            //minx:126805.07 maxx:141827.31 miny:448979.02 maxy:461149.85
        }
Beispiel #9
0
        private List <Vector3> CreateVectorlist(List <Vector3Double> vectors)
        {
            List <Vector3> output = new List <Vector3>();
            Vector3        vect;

            for (int i = 0; i < vectors.Count; i++)
            {
                vect = CoordConvert.RDtoUnity(new Vector3RD(vectors[i].x, vectors[i].y, vectors[i].z)) - offset;
                output.Add(vect);
            }
            output.Reverse();
            return(output);
        }
        private Tile CreateNewTile(TileChange tileChange)
        {
            Tile tile = new Tile();

            tile.LOD        = 0;
            tile.tileKey    = new Vector2Int(tileChange.X, tileChange.Y);
            tile.layer      = transform.gameObject.GetComponent <Layer>();
            tile.gameObject = new GameObject();
            tile.gameObject.transform.parent   = transform.gameObject.transform;
            tile.gameObject.layer              = tile.gameObject.transform.parent.gameObject.layer;
            tile.gameObject.transform.position = CoordConvert.RDtoUnity(new Vector2(tileChange.X, tileChange.Y));

            return(tile);
        }
Beispiel #11
0
        private List <Vector3> GetVerts(CityModel cityModel, Vector3RD origin)
        {
            List <Vector3> verts            = new List <Vector3>();
            Vector3        unityOrigin      = CoordConvert.RDtoUnity(origin);
            Vector3RD      vertexCoordinate = new Vector3RD();

            foreach (Vector3Double vertex in cityModel.vertices)
            {
                vertexCoordinate.x = vertex.x;
                vertexCoordinate.y = vertex.y;
                vertexCoordinate.z = vertex.z;
                verts.Add(CoordConvert.RDtoUnity(vertexCoordinate) - unityOrigin);
            }

            return(verts);
        }
 public void Start()
 {
     //Calculate offset. ( Our viewer expects tiles with the origin in the center )
     tileOffset = new Vector3RD()
     {
         x = Config.activeConfiguration.RelativeCenterRD.x,
         y = Config.activeConfiguration.RelativeCenterRD.y,
         z = 0
     };
     tileOffset.x      -= 500;
     tileOffset.y      -= 500;
     unityTileOffset    = CoordConvert.RDtoUnity(tileOffset);
     trees              = new List <Tree>();
     treeLines          = new List <string>();
     noPrefabFoundNames = new List <string>();
     ParseTreeData();
 }
Beispiel #13
0
    // for debugging, create a mesh from the triangleList
    private void CreateMesh(List <Vector3RD> points)
    {
        List <Vector3> vertices = new List <Vector3>();
        List <int>     indices  = new List <int>();

        for (int i = 0; i < points.Count; i++)
        {
            vertices.Add(CoordConvert.RDtoUnity(points[i]));
            indices.Add(i);
        }
        Mesh mesh = new Mesh();

        mesh.vertices = vertices.ToArray();
        mesh.SetIndices(indices.ToArray(), MeshTopology.Triangles, 0);
        mesh.RecalculateNormals();
        gameObject.GetComponent <MeshFilter>().sharedMesh = mesh;
    }
        public void Start()
        {
            Directory.CreateDirectory("Assets/TreeTileAssets/");

            //Calculate offset. ( Our viewer expects tiles with the origin in the center )
            tileOffset      = Config.activeConfiguration.RelativeCenterRD;       // CoordConvert.referenceRD;
            tileOffset.x   -= 500;
            tileOffset.y   -= 500;
            unityTileOffset = CoordConvert.RDtoUnity(new Vector2((float)tileOffset.x, (float)tileOffset.y));

            trees = new List <Tree>();

            noPrefabFoundNames = new List <string>();

            ReadTreesFromCsv();

            //DrawTrees(bomen.Take(100).ToList());
            //DrawTrees(bomen);

            StartCoroutine(TraverseTileFiles());
        }
        private void GetTileDistancesInView(List <int> tileSizes, Vector4 viewRange, Vector3Int cameraPosition)
        {
            //Godview only frustum check
            if (filterByCameraFrustum && CameraModeChanger.Instance.CameraMode == CameraMode.GodView)
            {
                GeometryUtility.CalculateFrustumPlanes(CameraModeChanger.Instance.ActiveCamera, cameraFrustumPlanes);
            }
            tileDistances.Clear();

            foreach (int tileSize in tileSizes)
            {
                startX = (int)Math.Floor(viewRange.x / tileSize) * tileSize;
                startY = (int)Math.Floor(viewRange.y / tileSize) * tileSize;
                endX   = (int)Math.Ceiling((viewRange.x + viewRange.z) / tileSize) * tileSize;
                endY   = (int)Math.Ceiling((viewRange.y + viewRange.w) / tileSize) * tileSize;
                tileList.Clear();

                for (int x = startX; x <= endX; x += tileSize)
                {
                    for (int y = startY; y <= endY; y += tileSize)
                    {
                        Vector3Int tileID = new Vector3Int(x, y, tileSize);
                        if (filterByCameraFrustum && CameraModeChanger.Instance.CameraMode == CameraMode.GodView)
                        {
                            tileBounds.SetMinMax(CoordConvert.RDtoUnity(new Vector2(x, y)), CoordConvert.RDtoUnity(new Vector2(x + tileSize, y + tileSize)));
                            if (GeometryUtility.TestPlanesAABB(cameraFrustumPlanes, tileBounds))
                            {
                                tileList.Add(new Vector3Int(x, y, (int)GetTileDistanceSquared(tileID, cameraPosition)));
                            }
                        }
                        else
                        {
                            tileList.Add(new Vector3Int(x, y, (int)GetTileDistanceSquared(tileID, cameraPosition)));
                        }
                    }
                }

                tileDistances.Add(tileList);
            }
        }
Beispiel #16
0
    IEnumerator GetAssetFromWebserver(TileChange tileChange, System.Action <TileChange> callback = null)
    {
        var x = tileChange.X;
        var y = tileChange.Y;

        var name = _replaceString.Replace("{x}", x.ToString()).Replace("{y}", y.ToString());

        if (_tiles.ContainsKey(name) == false)
        {
            Uri baseUri = new Uri(Config.activeConfiguration.webserverRootPath);
            var uri     = new Uri(baseUri, name);
            var tilepos = CoordConvert.RDtoUnity(new Vector3(x, y, 0));
            using (UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle(uri.AbsoluteUri))
            {
                yield return(uwr.SendWebRequest());

                if (!uwr.isNetworkError && !uwr.isHttpError)
                {
                    AssetBundle assetBundle = DownloadHandlerAssetBundle.GetContent(uwr);

                    // yield return new WaitUntil(() => pauseLoading == false);

                    var        mesh = assetBundle.LoadAllAssets <Mesh>().First();
                    GameObject gam  = new GameObject();
                    gam.transform.localScale = Vector3.one * _scale;
                    gam.name               = name;
                    gam.transform.parent   = transform;
                    gam.transform.position = tilepos + _offset;
                    gam.AddComponent <MeshFilter>().sharedMesh = mesh;
                    gam.AddComponent <MeshRenderer>().material = _material;

                    callback(tileChange);

                    _tiles.Add(name, gam);
                }
            }
        }
        callback(tileChange);
    }
Beispiel #17
0
        IEnumerator GetTilesYAML(string dirname, Material[] materials, string searchfilter, Transform parent)
        {
            var files = Directory.GetFiles(dirname, searchfilter);

            foreach (var file in files)
            {
                var finfo = new FileInfo(file);

                var rd      = file.GetRDCoordinate();
                var tilepos = CoordConvert.RDtoUnity(rd);

                //var mesh = AssetDatabase.LoadAssetAtPath<Mesh>($"{dirname}/{finfo.Name}");
                var mesh = AssetDatabase.LoadAssetAtPath <Mesh>(file);

                if (mesh == null || mesh.vertices.Length == 0)
                {
                    continue;
                }

                GameObject gam = new GameObject();
                gam.name               = finfo.Name;
                gam.transform.parent   = parent;
                gam.transform.position = tilepos + offset;

                var filter = gam.AddComponent <MeshFilter>();
                filter.sharedMesh = mesh;

                var ren = gam.AddComponent <MeshRenderer>();
                //ren.material = material;
                ren.materials = materials;
                yield return(null);

                Debug.Log($"loaded: {finfo.Name}");
            }
            yield return(null);
        }
Beispiel #18
0
        IEnumerator GetTilesUnityFS(string path, bool addCollider, Transform parent, Material material, Material[] materials)
        {
            var files = Directory.GetFiles(path).Where(o => !o.Contains(".manifest")).ToArray();

            foreach (var file in files)
            {
                var finfo = new FileInfo(file);

                if (!file.Contains('-'))
                {
                    continue;
                }

                yield return(null);

                Debug.Log($"going to process: {finfo.Name}");

                var rd      = file.GetRDCoordinate();
                var tilepos = CoordConvert.RDtoUnity(rd);

                var assetbundle = AssetBundle.LoadFromFile(file);

                var mesh = assetbundle.LoadAllAssets <Mesh>().First();

                if (mesh.vertices.Length == 0)
                {
                    continue;
                }

                var verts = mesh.vertices;

                GameObject gam = new GameObject();
                gam.name               = finfo.Name;
                gam.transform.parent   = parent;
                gam.transform.position = tilepos + offset;
                gam.AddComponent <MeshFilter>().sharedMesh = mesh;

                if (addCollider)
                {
                    gam.AddComponent <MeshCollider>().sharedMesh = mesh;
                }
                gam.AddComponent <MeshRenderer>().material = material;

                if (materials != null)
                {
                    var ren = gam.GetComponent <MeshRenderer>();
                    ren.materials = materials;
                }

                yield return(null);

                var newmesh = Instantiate(mesh);
                newmesh.name = finfo.Name;

                AssetBundle.UnloadAllAssetBundles(true);
                AssetDatabase.CreateAsset(newmesh, Path.Combine(assetCreationRelativePath, finfo.Name));

                Debug.Log($"loaded {finfo.Name}");
            }

            Debug.Log("All tiles processed");
        }
Beispiel #19
0
        static void ImportSingle(double OriginX, double OriginY)
        {
            double originX      = OriginX;
            double originY      = OriginY;
            string basefilepath = "E:/TiledData/Terrain1000x1000/";

            string jsonfilename = originX.ToString() + "-" + originY.ToString() + ".json";

            float  tileSize = 1000;
            string filepath = basefilepath;

            Debug.Log(filepath);

            if (File.Exists(filepath + jsonfilename))
            {
                CityModel cm = new CityModel(filepath, jsonfilename);

                //type voetpad
                Mesh RoadsvoetpadMesh = CreateCityObjectMesh(cm, "Road", originX, originY, tileSize, "bgt_functie", new List <string> {
                    "voetpad", "voetgangersgebied", "ruiterpad", "voetpad op trap"
                }, true);
                Mesh LandUseVoetpadMesh = CreateCityObjectMesh(cm, "LandUse", originX, originY, tileSize, "bgt_fysiekvoorkomen", new List <string> {
                    "open verharding"
                }, true);
                LandUseVoetpadMesh = SimplifyMesh(LandUseVoetpadMesh, 0.05f);
                //combine meshes of type "voetpad"
                CombineInstance[] voetpadcombi = new CombineInstance[2];
                voetpadcombi[0].mesh = RoadsvoetpadMesh;
                voetpadcombi[1].mesh = LandUseVoetpadMesh;
                Mesh voetpadmesh = new Mesh();
                voetpadmesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                voetpadmesh.CombineMeshes(voetpadcombi, true, false);
                //type fietspad
                Mesh fietspadMesh = CreateCityObjectMesh(cm, "Road", originX, originY, tileSize, "bgt_functie", new List <string> {
                    "fietspad"
                }, true);

                //type parkeervak
                Mesh parkeervlakMesh = CreateCityObjectMesh(cm, "Road", originX, originY, tileSize, "bgt_functie", new List <string> {
                    "parkeervlak"
                }, true);
                //type spoorbaan
                Mesh spoorbaanMesh = CreateCityObjectMesh(cm, "Road", originX, originY, tileSize, "bgt_functie", new List <string> {
                    "spoorbaan"
                }, true);
                //type woonerf
                Mesh WoonerfMesh = CreateCityObjectMesh(cm, "Road", originX, originY, tileSize, "bgt_functie", new List <string> {
                    "transitie", "woonerf"
                }, true);

                // type weg
                Mesh roadsMesh = CreateCityObjectMesh(cm, "Road", originX, originY, tileSize, "bgt_functie", new List <string> {
                    "fietspad", "parkeervlak", "ruiterpad", "spoorbaan", "voetgangersgebied", "voetpad", "voetpad op trap", "woonerf"
                }, false);
                Mesh LandUseVerhardMesh = CreateCityObjectMesh(cm, "LandUse", originX, originY, tileSize, "bgt_fysiekvoorkomen", new List <string> {
                    "gesloten verharding"
                }, true);
                LandUseVerhardMesh = SimplifyMesh(LandUseVerhardMesh, 0.05f);
                // combine meshes of type "weg"
                CombineInstance[] wegcombi = new CombineInstance[2];
                wegcombi[0].mesh = roadsMesh;
                wegcombi[1].mesh = LandUseVerhardMesh;
                Mesh wegmesh = new Mesh();
                wegmesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                wegmesh.CombineMeshes(wegcombi, true, false);

                // type groen
                Mesh plantcoverMesh = CreateCityObjectMesh(cm, "PlantCover", originX, originY, tileSize, "bgt_fysiekvoorkomen", new List <string> {
                    "alles"
                }, false);
                Mesh LanduseGroenMesh = CreateCityObjectMesh(cm, "LandUse", originX, originY, tileSize, "bgt_fysiekvoorkomen", new List <string> {
                    "groenvoorziening"
                }, true);
                LanduseGroenMesh = SimplifyMesh(LanduseGroenMesh, 0.05f);
                //combine meshes of type "groen"
                CombineInstance[] groencombi = new CombineInstance[2];
                groencombi[0].mesh = plantcoverMesh;
                groencombi[1].mesh = LanduseGroenMesh;
                Mesh groenMesh = new Mesh();
                groenMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                groenMesh.CombineMeshes(groencombi, true, false);

                //type erf
                Mesh erfMesh = CreateCityObjectMesh(cm, "LandUse", originX, originY, tileSize, "bgt_fysiekvoorkomen", new List <string> {
                    "erf"
                }, true);
                erfMesh = SimplifyMesh(erfMesh, 0.05f);

                //type onverhard
                Mesh LandUseMesh = CreateCityObjectMesh(cm, "LandUse", originX, originY, tileSize, "bgt_fysiekvoorkomen", new List <string> {
                    "erf", "groenvoorziening", "gesloten verharding", "open verharding"
                }, false);
                LandUseMesh = SimplifyMesh(LandUseMesh, 0.05f);

                Mesh genericCityObjectMesh = CreateCityObjectMesh(cm, "GenericCityObject", originX, originY, tileSize, "bgt_type", null, true);
                Mesh waterBodyMesh         = CreateCityObjectMesh(cm, "WaterBody", originX, originY, tileSize, "bgt_type", null, true);
                Mesh bridgeMesh            = CreateCityObjectMesh(cm, "Bridge", originX, originY, tileSize, "bgt_type", null, true);



                //create LOD1 Mesh
                CombineInstance[] combi = new CombineInstance[12];
                combi[0].mesh  = voetpadmesh;     //
                combi[1].mesh  = fietspadMesh;    //
                combi[2].mesh  = parkeervlakMesh; //
                combi[3].mesh  = wegmesh;         //
                combi[4].mesh  = groenMesh;       //
                combi[5].mesh  = erfMesh;         //
                combi[6].mesh  = LandUseMesh;     //
                combi[7].mesh  = spoorbaanMesh;   //
                combi[8].mesh  = WoonerfMesh;     //
                combi[9].mesh  = genericCityObjectMesh;
                combi[10].mesh = bridgeMesh;
                combi[11].mesh = waterBodyMesh;
                ;

                Mesh lod1Mesh = new Mesh();
                lod1Mesh.CombineMeshes(combi, false, false);
                lod1Mesh.uv2 = RDuv2(lod1Mesh.vertices, CoordConvert.RDtoUnity(new Vector3RD(originX, originY, 0)), tileSize);
                Physics.BakeMesh(lod1Mesh.GetInstanceID(), false);
                AssetDatabase.CreateAsset(lod1Mesh, "Assets/terrainMeshes/LOD0/terrain_" + originX + "-" + originY + "-lod1.mesh");
                //for debug

                //GetComponent<MeshFilter>().sharedMesh = lod1Mesh;



                //create LOD0MEsh
                combi         = new CombineInstance[5];
                combi[0].mesh = voetpadmesh;
                combi[1].mesh = fietspadMesh;
                combi[2].mesh = parkeervlakMesh;
                combi[3].mesh = wegmesh;
                combi[4].mesh = spoorbaanMesh;


                Mesh Roads = new Mesh();
                Roads.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                Roads.CombineMeshes(combi, true, false);
                Roads = SimplifyMesh(Roads, 0.05f);

                combi         = new CombineInstance[3];
                combi[0].mesh = erfMesh;
                combi[1].mesh = LandUseMesh;
                combi[2].mesh = WoonerfMesh;

                Mesh landuse = new Mesh();
                landuse.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                landuse.CombineMeshes(combi, true, false);
                landuse = SimplifyMesh(landuse, 0.05f);

                combi = new CombineInstance[12];


                combi[0].mesh  = CreateEmptyMesh();              //
                combi[1].mesh  = CreateEmptyMesh();              //
                combi[2].mesh  = CreateEmptyMesh();              //
                combi[3].mesh  = Roads;                          //
                combi[4].mesh  = SimplifyMesh(groenMesh, 0.05f); //
                combi[5].mesh  = CreateEmptyMesh();              //
                combi[6].mesh  = landuse;                        //
                combi[7].mesh  = CreateEmptyMesh();              //
                combi[8].mesh  = CreateEmptyMesh();              //
                combi[9].mesh  = genericCityObjectMesh;
                combi[10].mesh = bridgeMesh;
                combi[11].mesh = waterBodyMesh;


                Mesh lod0Mesh = new Mesh();
                lod0Mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                lod0Mesh.CombineMeshes(combi, false, false);
                lod0Mesh.uv2 = RDuv2(lod0Mesh.vertices, CoordConvert.RDtoUnity(new Vector3RD(originX, originY, 0)), tileSize);
                Physics.BakeMesh(lod0Mesh.GetInstanceID(), false);
                AssetDatabase.CreateAsset(lod0Mesh, "Assets/terrainMeshes/LOD0/terrain_" + originX + "-" + originY + "-lod0.mesh");
            }
        }
Beispiel #20
0
        public GameObject CreateMeshesByIdentifier(List <Building> buildings, string identifiername, Vector3RD origin)
        {
            offset = CoordConvert.RDtoUnity(new Vector2((float)origin.x, (float)origin.y));
            GameObject    container             = new GameObject();
            ObjectMapping objMap                = container.AddComponent <ObjectMapping>();
            List <string> identifiers           = new List <string>();
            List <List <SurfaceData> > surfdata = new List <List <SurfaceData> >();
            int buildingnumber = 0;

            foreach (Building building in buildings)
            {
                string buildingname = "";
                foreach (Semantics item in building.semantics)
                {
                    if (item.name == "name")
                    {
                        buildingname = item.value;
                    }
                }
                objMap.Objectmap.Add(buildingnumber, buildingname);
                objMap.BagID.Add(buildingname);
                buildingnumber++;
                List <SurfaceData> surfaces = SortSurfacesBySemantics(building, identifiername, buildingnumber);

                foreach (SurfaceData surf in surfaces)
                {
                    bool found = false;
                    for (int i = 0; i < identifiers.Count; i++)
                    {
                        if (identifiers[i] == surf.identifierValue)
                        {
                            found = true;
                            surfdata[i].Add(surf);
                        }
                    }
                    if (found == false)
                    {
                        identifiers.Add(surf.identifierValue);
                        surfdata.Add(new List <SurfaceData>());
                        surfdata[surfdata.Count - 1].Add(surf);
                    }
                }
            }

            int vertexcount = 0;
            int counter     = 0;

            for (int i = 0; i < identifiers.Count; i++)
            {
                List <CombineInstance> cis = new List <CombineInstance>();
                foreach (SurfaceData surf in surfdata[i])
                {
                    if (vertexcount + surf.texturedMesh.mesh.vertexCount > 65535)
                    {
                        AddSubobject(container, cis, identifiers[i], counter);
                        counter    += 1;
                        cis         = new List <CombineInstance>();
                        vertexcount = 0;
                    }
                    CombineInstance ci = new CombineInstance();
                    ci.mesh = surf.texturedMesh.mesh;
                    cis.Add(ci);
                    surf.texturedMesh.mesh = null;

                    vertexcount += ci.mesh.vertexCount;
                }
                surfdata[i] = null;
                AddSubobject(container, cis, identifiers[i], counter);
            }

            return(container);
        }
Beispiel #21
0
        private Mesh CreateCityObjectMesh(CityModel cityModel, string cityObjectType, double originX, double originY, float tileSize, string bgtProperty, List <string> bgtValues, bool include)
        {
            List <Vector3RD> RDTriangles = GetTriangleListRD(cityModel, cityObjectType, bgtProperty, bgtValues, include);

            List <Vector3RD> clippedRDTriangles = new List <Vector3RD>();
            List <Vector3>   vectors            = new List <Vector3>();

            List <Vector3> clipboundary = CreateClippingPolygon(tileSize);

            if (RDTriangles.Count == 0)
            {
                return(CreateEmptyMesh());
            }

            //clip all the triangles
            for (int i = 0; i < RDTriangles.Count; i += 3)
            {
                if (PointISInsideArea(RDTriangles[i], originX, originY, tileSize) && PointISInsideArea(RDTriangles[i + 1], originX, originY, tileSize) && PointISInsideArea(RDTriangles[i + 2], originX, originY, tileSize))
                {
                    clippedRDTriangles.Add(RDTriangles[i + 2]);
                    clippedRDTriangles.Add(RDTriangles[i + 1]);
                    clippedRDTriangles.Add(RDTriangles[i]);
                    continue;
                }


                //offset RDvertices so coordinates can be saved as a float
                // flip y and z-axis so clippingtool works
                //reverse order to make them clockwise so the clipping-algorithm can use them
                vectors.Clear();
                vectors.Add(new Vector3((float)(RDTriangles[i + 2].x - originX), (float)RDTriangles[i + 2].z, (float)(RDTriangles[i + 2].y - originY)));
                vectors.Add(new Vector3((float)(RDTriangles[i + 1].x - originX), (float)RDTriangles[i + 1].z, (float)(RDTriangles[i + 1].y - originY)));
                vectors.Add(new Vector3((float)(RDTriangles[i].x - originX), (float)RDTriangles[i].z, (float)(RDTriangles[i].y - originY)));


                List <Vector3> defshape = Netherlands3D.Utilities.TriangleClipping.SutherlandHodgman.ClipPolygon(vectors, clipboundary);

                if (defshape.Count < 3)
                {
                    continue;
                }

                if (defshape[0].x.ToString() == "NaN")
                {
                    continue;
                }

                Vector3RD vectorRD = new Vector3RD();
                // add first three vectors

                vectorRD.x = defshape[0].x + originX;
                vectorRD.y = defshape[0].z + originY;
                vectorRD.z = defshape[0].y;
                clippedRDTriangles.Add(vectorRD);

                vectorRD.x = defshape[1].x + originX;
                vectorRD.y = defshape[1].z + originY;
                vectorRD.z = defshape[1].y;
                clippedRDTriangles.Add(vectorRD);
                vectorRD.x = defshape[2].x + originX;
                vectorRD.y = defshape[2].z + originY;
                vectorRD.z = defshape[2].y;
                clippedRDTriangles.Add(vectorRD);

                // add extra vectors. vector makes a triangle with the first and the previous vector.
                for (int j = 3; j < defshape.Count; j++)
                {
                    vectorRD.x = defshape[0].x + originX;
                    vectorRD.y = defshape[0].z + originY;
                    vectorRD.z = defshape[0].y;
                    clippedRDTriangles.Add(vectorRD);

                    vectorRD.x = defshape[j - 1].x + originX;
                    vectorRD.y = defshape[j - 1].z + originY;
                    vectorRD.z = defshape[j - 1].y;
                    clippedRDTriangles.Add(vectorRD);

                    vectorRD.x = defshape[j].x + originX;
                    vectorRD.y = defshape[j].z + originY;
                    vectorRD.z = defshape[j].y;
                    clippedRDTriangles.Add(vectorRD);
                }
            }

            //createMesh
            List <Vector3> verts        = new List <Vector3>();
            Vector3RD      tileCenterRD = new Vector3RD();

            tileCenterRD.x = originX + (tileSize / 2);
            tileCenterRD.y = originY + (tileSize / 2);
            tileCenterRD.z = 0;
            Vector3    tileCenterUnity = CoordConvert.RDtoUnity(tileCenterRD);
            List <int> ints            = new List <int>();

            for (int i = 0; i < clippedRDTriangles.Count; i++)
            {
                Vector3 coord = CoordConvert.RDtoUnity(clippedRDTriangles[i]) - tileCenterUnity;
                ints.Add(i);
                verts.Add(coord);
            }
            ints.Reverse(); //reverse the trianglelist to make the triangles counter-clockwise again

            if (ints.Count == 0)
            {
                return(CreateEmptyMesh());
            }
            Mesh mesh = new Mesh();

            mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
            mesh.vertices    = verts.ToArray();
            mesh.triangles   = ints.ToArray();
            mesh             = WeldVertices(mesh);
            mesh.RecalculateNormals();
            mesh.Optimize();
            return(mesh);
        }
Beispiel #22
0
        IEnumerator GetTilesUnityFSAndCorrectHeightSpikes(string path, Transform parent, Material material, Material[] materials)
        {
            Directory.CreateDirectory(assetCreationRelativePath);

            int count = 0;
            var files = Directory.GetFiles(path).Where(o => !o.Contains(".manifest")).ToArray();

            int heightMax       = 15;       //vertices above this value are considered to be spikes, vlaue in meters
            int heightMin       = -15;      //vertices above this value are considered to be spikes, vlaue in meters
            int lookaroundWidth = 1;        //area in meters to look around for other vertices to find common height

            foreach (var file in files)
            {
                var finfo = new FileInfo(file);

                if (File.Exists(Path.Combine(assetCreationRelativePath, finfo.Name)))
                {
                    continue;
                }

                //if (!file.Contains("140000-457000")) continue;

                if (!file.Contains('-'))
                {
                    continue;
                }

                yield return(null);

                Debug.Log($"going to process: {finfo.Name}");

                var rd      = file.GetRDCoordinate();
                var tilepos = CoordConvert.RDtoUnity(rd);

                var assetbundle = AssetBundle.LoadFromFile(file);

                var mesh = assetbundle.LoadAllAssets <Mesh>().First();

                if (mesh.vertices.Length == 0)
                {
                    continue;
                }

                var verts = mesh.vertices;

                var correctverts          = verts.Where(o => o.y <heightMax && o.y> heightMin);
                var correctvertsAvgHeight = correctverts.Average(o => o.y);

                bool hasspike = false;
                for (int i = 0; i < verts.Length; i++)
                {
                    if (verts[i].y > heightMax || verts[i].y < heightMin)
                    {
                        hasspike   = true;
                        verts[i].y = correctvertsAvgHeight;                         //for now just use the average height

                        //experimental code, needs further testing
                        //var x = verts[i].x;
                        //var z = verts[i].z;
                        //var vertsaround = correctverts.Where(o => o.x < x + lookaroundWidth
                        //								&& o.x > x - lookaroundWidth
                        //								&& o.z < z + lookaroundWidth
                        //								&& o.z > z - lookaroundWidth);
                        //if (vertsaround.Any())
                        //{
                        //	var avgh = vertsaround.Max(o => o.y);
                        //	verts[i].y = avgh;
                        //}
                        //else
                        //{
                        //	verts[i].y = correctvertsAvgHeight;
                        //}
                    }
                }

                if (hasspike)
                {
                    mesh.vertices = verts;
                }

                if (!hasspike)
                {
                    yield return(null);

                    Debug.Log($"no spike in: {finfo.Name}");
                    continue;
                }

                GameObject gam = new GameObject();
                gam.name               = finfo.Name;
                gam.transform.parent   = parent;
                gam.transform.position = tilepos + offset;
                gam.AddComponent <MeshFilter>().sharedMesh = mesh;

                gam.AddComponent <MeshRenderer>().material = material;

                if (materials != null)
                {
                    var ren = gam.GetComponent <MeshRenderer>();
                    ren.materials = materials;
                }

                yield return(null);

                var newmesh = Instantiate(mesh);
                newmesh.name = finfo.Name;

                AssetBundle.UnloadAllAssetBundles(true);
                AssetDatabase.CreateAsset(newmesh, Path.Combine(assetCreationRelativePath, finfo.Name + ".mesh"));

                count++;
                Debug.Log($"processed {count}");
                //if (count > 1) break;
            }

            Debug.Log("All tiles processed");
        }
Beispiel #23
0
        /// <summary>
        /// Parse files whose name contains coordinates that overlap the provided tile area
        /// </summary>
        /// <param name="rdCoordinates">Bottom left RD coordinates of the tile</param>
        /// <returns></returns>
        private IEnumerator ParseSpecificFiles(Vector2Int rdCoordinates)
        {
            //Read files list
            var info     = new DirectoryInfo(geoJsonSourceFilesFolder);
            var fileInfo = info.GetFiles();

            //First create gameobjects for all the buildigns we parse
            int parsed = 0;

            for (int i = 0; i < fileInfo.Length; i++)
            {
                var file = fileInfo[i];

                string[] fileNameParts = file.Name.Replace(".json", "").Split('_');

                //Determine parts of the filename
                var id    = fileNameParts[0];
                var count = fileNameParts[1];
                var xmin  = double.Parse(fileNameParts[3]);
                var ymin  = double.Parse(fileNameParts[4]);
                var xmax  = double.Parse(fileNameParts[5]);
                var ymax  = double.Parse(fileNameParts[6]);

                //Skip if these filename bounds are not within our selected rectangle
                if (xmin > rdCoordinates.x + tileSize || xmax < rdCoordinates.x || ymin > rdCoordinates.y + tileSize || ymax < rdCoordinates.y)
                {
                    continue;
                }
                Debug.Log("Parsing " + file.Name);
                if (!Application.isBatchMode)
                {
                    yield return(new WaitForEndOfFrame());
                }

                //Parse the file
                var jsonstring   = File.ReadAllText(file.FullName);
                var cityjsonNode = JSON.Parse(jsonstring);
                if (cityjsonNode["CityObjects"] == null)
                {
                    Debug.Log("FAILURE PARSING: " + file.Name);
                    continue; //Failed to parse the json
                }

                //Get vertices
                allVerts = new List <Vector3>();

                //Optionaly parse transform scale and offset
                var transformScale = (cityjsonNode["transform"] != null && cityjsonNode["transform"]["scale"] != null) ? new Vector3Double(
                    cityjsonNode["transform"]["scale"][0].AsDouble,
                    cityjsonNode["transform"]["scale"][1].AsDouble,
                    cityjsonNode["transform"]["scale"][2].AsDouble
                    ) : new Vector3Double(1, 1, 1);

                var transformOffset = (cityjsonNode["transform"] != null && cityjsonNode["transform"]["translate"] != null) ? new Vector3Double(
                    cityjsonNode["transform"]["translate"][0].AsDouble,
                    cityjsonNode["transform"]["translate"][1].AsDouble,
                    cityjsonNode["transform"]["translate"][2].AsDouble
                    ) : new Vector3Double(0, 0, 0);

                //Now load all the vertices with the scaler and offset applied
                foreach (JSONNode node in cityjsonNode["vertices"])
                {
                    var rd = new Vector3RD(
                        node[0].AsDouble * transformScale.x + transformOffset.x,
                        node[1].AsDouble * transformScale.y + transformOffset.y,
                        node[2].AsDouble * transformScale.z + transformOffset.z
                        );
                    var unityCoordinates = CoordConvert.RDtoUnity(rd);
                    allVerts.Add(unityCoordinates);
                }

                //Now build the meshes and create objects for these buildings
                int buildingCount = 0;
                foreach (JSONNode buildingNode in cityjsonNode["CityObjects"])
                {
                    //A building
                    var name = buildingNode["attributes"]["identificatie"].Value.Replace("NL.IMBAG.Pand.", "");

                    //Check if this name/ID exists in our list of manualy added child objects. If it is there, skip it.
                    if (overrideChildObjects.Where(overrideGameObject => overrideGameObject.name == name).SingleOrDefault())
                    {
                        print("Skipped parsing " + name + " because we have added a custom object for that");
                        continue;
                    }

                    GameObject building = new GameObject();
                    building.transform.SetParent(this.transform, false);
                    building.name = name;

                    //The building verts/triangles
                    var boundaries = buildingNode["geometry"][lodSlot]["boundaries"][0];
                    meshTriangles = new List <int>();
                    List <Vector3> thisMeshVerts = new List <Vector3>();
                    foreach (JSONNode boundary in boundaries)
                    {
                        JSONNode triangle = boundary[0];

                        vertIndex = triangle[2].AsInt;
                        thisMeshVerts.Add(allVerts[vertIndex]);
                        meshTriangles.Add(thisMeshVerts.Count - 1); //TODO. Group same verts

                        vertIndex = triangle[1].AsInt;
                        thisMeshVerts.Add(allVerts[vertIndex]);
                        meshTriangles.Add(thisMeshVerts.Count - 1);

                        vertIndex = triangle[0].AsInt;
                        thisMeshVerts.Add(allVerts[vertIndex]);
                        meshTriangles.Add(thisMeshVerts.Count - 1);
                    }

                    //Construct the mesh
                    Mesh buildingMesh = new Mesh();
                    if (thisMeshVerts.Count > Mathf.Pow(2, 16))
                    {
                        buildingMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                    }

                    buildingMesh.vertices  = thisMeshVerts.ToArray();
                    buildingMesh.triangles = meshTriangles.ToArray();
                    buildingMesh.RecalculateNormals();

                    var meshRenderer = building.AddComponent <MeshRenderer>();
                    meshRenderer.material = DefaultMaterial;
                    meshRenderer.enabled  = renderInViewport;
                    building.AddComponent <MeshFilter>().sharedMesh = buildingMesh;
                    buildingCount++;
                }

                parsed++;
                print("Parsed GeoJSONS to fill tile: " + parsed + ". Buildings in tile: " + buildingCount);
            }
        }
Beispiel #24
0
        /// <summary>
        /// This method creates gameobjects for tiles, and fills them up with parsed buildings from GeoJSON files overlapping this tile.
        /// </summary>
        /// <returns></returns>
        private IEnumerator CreateTilesAndReadInGeoJSON()
        {
            print("Baking objects into tiles");
            var xTiles = Mathf.RoundToInt(((float)boundingBoxTopRight.x - (float)boundingBoxBottomLeft.x) / (float)tileSize);
            var yTiles = Mathf.RoundToInt(((float)boundingBoxTopRight.y - (float)boundingBoxBottomLeft.y) / (float)tileSize);

            var totalTiles  = xTiles * yTiles;
            int currentTile = 0;

            //Show a previewmap
            backDropTexture           = new Texture2D(500, 500, TextureFormat.RGBA32, false);
            drawIntoPixels            = new Texture2D(yTiles, yTiles, TextureFormat.RGBA32, false);
            drawIntoPixels.filterMode = FilterMode.Point;

            gridPixelsRawImage.texture = drawIntoPixels;

            //Download background preview image
            var downloadUrl = previewBackdropImage.Replace("{xmin}", boundingBoxBottomLeft.x.ToString()).Replace("{ymin}", boundingBoxBottomLeft.y.ToString()).Replace("{xmax}", boundingBoxTopRight.x.ToString()).Replace("{ymax}", boundingBoxTopRight.y.ToString()).Replace("{w}", backgroundSize.ToString()).Replace("{h}", backgroundSize.ToString());

            print(downloadUrl);
            UnityWebRequest www = UnityWebRequestTexture.GetTexture(downloadUrl);

            yield return(www.SendWebRequest());

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.Log(www.error);
            }
            else
            {
                backDropTexture = ((DownloadHandlerTexture)www.downloadHandler).texture;
            }
            backgroundRawImage.texture = backDropTexture;

            //Walk the tilegrid
            var tileRD = new Vector2Int(0, 0);

            for (int x = 0; x < xTiles; x++)
            {
                tileRD.x = (int)boundingBoxBottomLeft.x + (x * tileSize);
                for (int y = 0; y < yTiles; y++)
                {
                    currentTile++;

                    tileRD.y = (int)boundingBoxBottomLeft.y + (y * tileSize);

                    string tileName = "buildings_" + tileRD.x + "_" + tileRD.y + "." + lodLevel;

                    //Maybe skip files?
                    string assetFileName = unityMeshAssetFolder + tileName + ".asset";
                    if (skipExistingFiles && File.Exists(Application.dataPath + "/../" + assetFileName))
                    {
                        print("Skipping existing tile: " + Application.dataPath + "/../" + assetFileName);
                        drawIntoPixels.SetPixel(x, y, Color.grey);
                        drawIntoPixels.Apply();
                        if (!Application.isBatchMode)
                        {
                            yield return(new WaitForEndOfFrame());
                        }
                        continue;
                    }

                    //Spawn our tile container
                    GameObject newTileContainer = new GameObject();
                    newTileContainer.transform.position = CoordConvert.RDtoUnity(tileRD + tileOffset);
                    newTileContainer.name = tileName;

                    print("Parsing JSON files for tile " + currentTile + " / " + totalTiles + ": " + newTileContainer.name);
                    if (!Application.isBatchMode)
                    {
                        yield return(new WaitForEndOfFrame());
                    }

                    //Load GEOJsons that overlap this tile
                    yield return(StartCoroutine(ParseSpecificFiles(tileRD)));

                    if (!Application.isBatchMode)
                    {
                        yield return(new WaitForEndOfFrame());
                    }

                    //Now move them into the tile if their centerpoint is within our defined tile region
                    int buildingsAdded = MoveChildrenIntoTile(tileRD, newTileContainer, true);
                    if (buildingsAdded == 0)
                    {
                        drawIntoPixels.SetPixel(x, y, Color.black);
                    }
                    else
                    {
                        drawIntoPixels.SetPixel(x, y, Color.clear);
                    }
                    drawIntoPixels.Apply();

                    if (!Application.isBatchMode)
                    {
                        yield return(new WaitForEndOfFrame());
                    }

                    //Now bake the tile into an asset file
                    if (generateAssetFiles)
                    {
                        CreateBuildingTile(newTileContainer, newTileContainer.transform.position);
                        print("Created tile " + currentTile + "/" + totalTiles + " with " + buildingsAdded + " buildings -> " + newTileContainer.name);
                    }
                    if (!Application.isBatchMode)
                    {
                        yield return(new WaitForEndOfFrame());
                    }
                }
            }
            print("Done!");
            if (optionalObjectToEnableWhenFinished)
            {
                optionalObjectToEnableWhenFinished.SetActive(true);
            }
        }