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))); } }
//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 }
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); }
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(); }
// 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); } }
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); }
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); }
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"); }
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"); } }
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); }
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); }
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"); }
/// <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); } }
/// <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); } }