private void setupMesh() { // Create Vector2 vertices Vector2[] poly = shape.Select(x => x.vec).ToArray(); // Set up game object with mesh; filter.mesh = Triangulator.CreateMesh(poly, Random.Range(5, 20)); }
private void GenerateFloorPlane(Bounds?tb, GameObject container) { // Now generate a plane and texture it with a map image.. var poly = tb.Value.ToPolygonFromBounds(); // Centre on the origin.. var polyArray = poly.ToList().Select(p => (p.ToVector3xz() - tb.Value.center).ToVector2xz()); var planeMesh = Triangulator.CreateMesh(polyArray.ToArray()); _floorPlaneBounds = planeMesh.bounds; { Vector3[] old = planeMesh.vertices; int[] triangles = planeMesh.triangles; Vector3[] verts = new Vector3[triangles.Length]; for (int i = 0; i < triangles.Length; i++) { verts[i] = old[triangles[i]]; triangles[i] = i; } } Vector3[] vertices = planeMesh.vertices; { Vector2[] uvs = new Vector2[vertices.Length]; for (int i = 0; i < uvs.Length; i++) { uvs[i] = MapCoordToUV(vertices[i].ToVector2xz(), _tileMetadata); } planeMesh.uv = uvs; } for (int i = 0; i < vertices.Length; i++) { vertices[i] = vertices[i] * (float)MESH_SCALAR; } planeMesh.vertices = vertices; planeMesh.RecalculateNormals(); planeMesh.RecalculateBounds(); var planeBounds = planeMesh.bounds; _tilePlane.GetComponent <MeshFilter>().mesh = planeMesh; _tilePlane.transform.parent = container.transform; }
private void ProcessBuildings(IEnumerable <Feature> buildings, Bounds?tb, GameObject container) { //int buildingCount = 0; var geomContainer = new GameObject("Geometry"); geomContainer.transform.parent = container.transform; foreach (var building in buildings) { try { //if (++buildingCount != 1) // continue; if (building.geometry.coordinates == null) { continue; } foreach (var coords in building.geometry.coordinates) { // Create Vector2 vertices List <Vector2> verts = new List <Vector2>(); foreach (var crd in coords) { // remember lat/lon are reversed in geoJSON verts.Add(GM.LatLonToMeters(crd[1], crd[0])); } // Create the Vector3 vertices - // So, x corresponds to latitude // z corresponds to longitude List <Vector3> verts3 = verts.Select(v => v.ToVector3xz()).ToList(); // Calculate axis aligned bounding box for polygon var bound = new Bounds(verts3[0], Vector3.zero); foreach (var vtx in verts3) { bound.Encapsulate(vtx); } // Move the polygon to the origin by subtracting the centre of the bounding box from // each vertex. verts = verts3.Select(vtx => (vtx - bound.center).ToVector2xz()).ToList(); Debug.Log(string.Format("NUM VERTS (before triangulation) = {0}", verts.Count)); // Work out the height of the building either from height or estimate from // number of levels or failing that, just one level.. int numLevels = 1; if (!string.IsNullOrEmpty(building.properties.tags.building_levels)) { numLevels = int.Parse(building.properties.tags.building_levels); } var mesh = Triangulator.CreateMesh(verts.ToArray(), numLevels * BuildingLevelHeight); var g = new GameObject(); g.AddComponent(typeof(MeshFilter)); g.AddComponent(typeof(MeshRenderer)); // If you want to get flat shading then you need a unique vertex for each // face. I haven't processed the data like that so have run this code as a post // process to generate the required vertices // (see http://answers.unity3d.com/questions/798510/flat-shading.html) Vector3[] oldVerts = mesh.vertices; int[] triangles = mesh.triangles; Vector3[] vertices = new Vector3[triangles.Length]; for (int i = 0; i < triangles.Length; i++) { vertices[i] = oldVerts[triangles[i]]; triangles[i] = i; } mesh.vertices = vertices; mesh.triangles = triangles; var dist = (bound.center - tb.Value.center); Vector3[] vertxs = mesh.vertices; Vector2[] uvs = new Vector2[vertxs.Length]; for (int i = 0; i < uvs.Length; i++) { var xz = vertxs[i].ToVector2xz(); xz.x += dist.x; xz.y += dist.z; uvs[i] = MapCoordToUV(xz, _tileMetadata); } for (int i = 0; i < vertices.Length; i++) { vertices[i] = vertices[i] * (float)MESH_SCALAR; } mesh.vertices = vertices; mesh.uv = uvs; mesh.RecalculateBounds(); mesh.RecalculateNormals(); g.GetComponent <MeshFilter>().mesh = mesh; // also, translate the building in y by half of its height.. //dist.y += g.transform.Translate(dist * (float)MESH_SCALAR); if (building.properties.tags != null) { if (!string.IsNullOrEmpty(building.properties.tags.name)) { g.name = building.properties.tags.name; } else if (!string.IsNullOrEmpty(building.properties.tags.addrhousename)) { g.name = building.properties.tags.addrhousename; } else if (!string.IsNullOrEmpty(building.properties.tags.addrstreet)) { g.name = building.properties.tags.addrstreet; } } g.GetComponent <MeshRenderer>().material = _mapMaterial; g.transform.parent = geomContainer.transform; } } catch (Exception) { Debug.Log(string.Format("Building load failed")); } } }
// Use this for initialization void Start() { // MIN 51.579687, -0.341837 // MAX 51.580780, -0.333930 //const float minLat = 51.579687f; //const float maxLat = 51.580780f; //const float minLon = -0.341837f; //const float maxLon = -0.333930f; float maxLat = 51.5140574994f; float maxLon = -0.1145303249f; float minLat = 51.5073134351f; float minLon = -0.1295164166f; float[][][] TileBounds = new float[][][] { new float[][] { new float[] { maxLon, maxLat, 0.0f }, new float[] { minLon, minLat, 0.0f }, } }; // Can get the OSM data using something like the following.. var httpStr = @"http://overpass-api.de/api/interpreter?data=[out:json];(node[""building""](51.579687,-0.341837,51.580780,-0.333930);way[""building""](51.579687,-0.341837,51.580780,-0.333930);relation[""building""](51.579687,-0.341837,51.580780,-0.333930););out body;>;out skel qt;"; //var geoJson = Resources.Load("santander") as TextAsset; var geoJson = Resources.Load("london2") as TextAsset; fsSerializer serializer = new fsSerializer(); serializer.Config.GetJsonNameFromMemberName = GetJsonNameFromMemberName; serializer.AddConverter(new Converter()); fsData data = null; data = fsJsonParser.Parse(geoJson.text); // step 2: deserialize the data GeoJsonRoot deserialized = null; try { serializer.TryDeserialize(data, ref deserialized).AssertSuccessWithoutWarnings(); } catch (Exception ex) { int x = 3; } Debug.Log("Number of features = " + deserialized.features.Count()); var buildings = deserialized.features.Where(f => f.properties != null && f.properties.tags.building != null); // Need to know the centre of the 'tile' so we can create the buildings at // the origin and then translate to the correct positions. // When we are calling an API we will know the lat lon of the requested tile // until then we can use a bounding box around all of the buildings.. //var tb = GetBoundingBoxForBuilding(buildings.First()); //foreach (var building in buildings) //{ // if (building == buildings.First()) // continue; // var bounds = GetBoundingBoxForBuilding(building); // if (bounds == null) // continue; // tb.Value.Encapsulate(bounds.Value); //} // Use the centre of the tile bounding box var tb = GetBoundingBox(TileBounds); int buildingCount = 0; foreach (var building in buildings) { try { if (++buildingCount != 1) { continue; } if (building.geometry.coordinates == null) { continue; } foreach (var coords in building.geometry.coordinates) { // Create Vector2 vertices List <Vector2> verts = new List <Vector2>(); foreach (var crd in coords) { // remember lat/lon are reversed in geoJSON verts.Add(GM.LatLonToMeters(crd[1], crd[0])); } // Create the Vector3 vertices - // So, x corresponds to latitude // z corresponds to longitude List <Vector3> verts3 = verts.Select(v => v.ToVector3xz()).ToList(); // Calculate axis aligned bounding box for polygon var bound = new Bounds(verts3[0], Vector3.zero); foreach (var vtx in verts3) { bound.Encapsulate(vtx); } // Move the polygon to the origin by subtracting the centre of the bounding box from // each vertex. verts = verts3.Select(vtx => (vtx - bound.center).ToVector2xz()).ToList(); Debug.Log(string.Format("NUM VERTS (before triangulation) = {0}", verts.Count)); // Work out the height of the building either from height or estimate from // number of levels or failing that, just one level.. const float oneLevel = 16.0f; int numLevels = 1; if (!string.IsNullOrEmpty(building.properties.tags.building_levels)) { numLevels = int.Parse(building.properties.tags.building_levels); } var mesh = Triangulator.CreateMesh(verts.ToArray(), numLevels * oneLevel); var g = new GameObject(); g.AddComponent(typeof(MeshFilter)); g.AddComponent(typeof(MeshRenderer)); // If you want to get flat shading then you need a unique vertex for each // face. I haven't processed the data like that so have run this code as a post // process to generate the required vertices // (see http://answers.unity3d.com/questions/798510/flat-shading.html) Vector3[] oldVerts = mesh.vertices; int[] triangles = mesh.triangles; Vector3[] vertices = new Vector3[triangles.Length]; for (int i = 0; i < triangles.Length; i++) { vertices[i] = oldVerts[triangles[i]]; triangles[i] = i; } mesh.vertices = vertices; mesh.triangles = triangles; mesh.RecalculateBounds(); mesh.RecalculateNormals(); g.GetComponent <MeshFilter>().mesh = mesh; var dist = bound.center - tb.Value.center; // also, translate the building in y by half of its height.. //dist.y += g.transform.Translate(dist); Material m = new Material(Shader.Find("Standard")); m.color = Color.grey; if (building.properties.tags != null) { if (!string.IsNullOrEmpty(building.properties.tags.name)) { g.name = building.properties.tags.name; } else if (!string.IsNullOrEmpty(building.properties.tags.addrhousename)) { g.name = building.properties.tags.addrhousename; } else if (!string.IsNullOrEmpty(building.properties.tags.addrstreet)) { g.name = building.properties.tags.addrstreet; } } g.GetComponent <MeshRenderer>().material = m; g.transform.parent = gameObject.transform; } } catch (Exception ex) { Debug.Log(string.Format("Building load failed")); } } // Now generate a plane and texture it with a map image.. //var tb = GetBoundingBox(TileBounds); var poly = tb.Value.ToPolygonFromBounds(); // Centre on the origin.. var polyArray = poly.ToList().Select(p => (p.ToVector3xz() - tb.Value.center).ToVector2xz()); var planeMesh = Triangulator.CreateMesh(polyArray.ToArray()); // Set the UVs: //Vector2[] uvs = new Vector2[4]; //uvs[0] = new Vector2(0.0f, 0.0f); //uvs[1] = new Vector2(0.0f, 1.0f); //uvs[2] = new Vector2(1.0f, 1.0f); //uvs[3] = new Vector2(1.0f, 0.0f); { Vector3[] old = planeMesh.vertices; int[] triangles = planeMesh.triangles; Vector3[] vertices = new Vector3[triangles.Length]; for (int i = 0; i < triangles.Length; i++) { vertices[i] = old[triangles[i]]; triangles[i] = i; } } //planeMesh.uv = uvs; planeMesh.RecalculateNormals(); planeMesh.RecalculateBounds(); var gobj = new GameObject(); gobj.name = "Tile Plane"; gobj.AddComponent(typeof(MeshFilter)); gobj.AddComponent(typeof(MeshRenderer)); gobj.GetComponent <MeshFilter>().mesh = planeMesh; Material mt = new Material(Shader.Find("Standard")); mt.color = Color.white; gobj.GetComponent <MeshRenderer>().material = mt; //Texture my_img = (Texture)Resources.Load("harrowtestimg"); //gobj.GetComponent<MeshRenderer>().material.mainTexture = my_img; }