diff --git a/Editor/Builders.meta b/Editor/Builders.meta new file mode 100644 index 0000000..2b9112e --- /dev/null +++ b/Editor/Builders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 64cd68c66a7d979428c21c49ff57a8b1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Components/BlockFromFeature.cs b/Editor/Builders/BlockFromPolygonBuilder.cs similarity index 55% rename from Runtime/Components/BlockFromFeature.cs rename to Editor/Builders/BlockFromPolygonBuilder.cs index b32fb7e..00b80e1 100644 --- a/Runtime/Components/BlockFromFeature.cs +++ b/Editor/Builders/BlockFromPolygonBuilder.cs @@ -4,26 +4,12 @@ using UnityEngine.ProBuilder; using UnityEngine.ProBuilder.MeshOperations; -namespace GeoJsonCityBuilder +namespace GeoJsonCityBuilder.Editor { - // Require removed, because it caused a Unity build-error - // with HDRP (build apparently tries to remove all - // components without checking component-dependencies) - // [RequireComponent(typeof(ProBuilderMesh))] - [RequireComponent(typeof(MeshCollider))] - public class BlockFromFeature : MonoBehaviour - { - public IList floor; - - public Material topMaterial; - public Material bottomMaterial; - public Material sideMaterial; - public float height = 10f; - - public bool pointedRoof = false; - public float pointedRoofHeight = 3f; - public bool raiseFrontAndBackFacadeTop = false; - public float leanForward = 0f; + public class BlockFromPolygonBuilder { + public BlockFromPolygon BlockInfo { get; private set; } + public GameObject GameObject {get; private set; } + Face topFace; Face frontFace; Face backFace; @@ -34,69 +20,72 @@ public class BlockFromFeature : MonoBehaviour Edge frontFaceTopEdge = new Edge(); Edge backFaceTopEdge = new Edge(); - bool fourSides = false; - - public AutoUnwrapSettings sideUvUnwrapSettings = new AutoUnwrapSettings(); + public BlockFromPolygonBuilder (BlockFromPolygon blockInfo) + { + this.BlockInfo = blockInfo; + this.GameObject = blockInfo.gameObject; + } - public ProBuilderMesh pb; + private ProBuilderMesh pb; + bool fourSides = false; public void Draw() { - var mesh = gameObject.GetComponent(); + var mesh = this.GameObject.GetComponent(); if (mesh == null) { - mesh = gameObject.AddComponent(); + mesh = this.GameObject.AddComponent(); } - var first = floor.First(); - var last = floor.Last(); + var first = this.BlockInfo.floorPolygon.First(); + var last = this.BlockInfo.floorPolygon.Last(); if (first.x == last.x && first.y == last.y && first.z == last.z) { - floor.Remove(floor.Last()); + this.BlockInfo.floorPolygon.Remove(this.BlockInfo.floorPolygon.Last()); } - mesh.CreateShapeFromPolygon(floor, height, false); + mesh.CreateShapeFromPolygon(this.BlockInfo.floorPolygon, this.BlockInfo.height, false); - pb = gameObject.GetComponent(); - if (pb.faceCount > 2) + this.pb = GameObject.GetComponent(); + if (this.pb.faceCount > 2) { - pb.SetMaterial(pb.faces, sideMaterial); - pb.SetMaterial(new List() { pb.faces[0] }, topMaterial); - pb.SetMaterial(new List() { pb.faces[1] }, bottomMaterial); + this.pb.SetMaterial(this.pb.faces, this.BlockInfo.sideMaterial); + this.pb.SetMaterial(new List() { this.pb.faces[0] }, this.BlockInfo.topMaterial); + this.pb.SetMaterial(new List() { this.pb.faces[1] }, this.BlockInfo.bottomMaterial); } var i = 0; - foreach (var face in pb.faces) + foreach (var face in this.pb.faces) { // Skip the bottom and ceiling face: if (i>1) { - face.uv = this.sideUvUnwrapSettings; + face.uv = this.BlockInfo.sideUvUnwrapSettings; } i++; } - pb.ToMesh(); - pb.Refresh(); + this.pb.ToMesh(); + this.pb.Refresh(); - FindSpecialSides(); + this.FindSpecialSides(); - LeanForward(); + this.LeanForward(); - if (pointedRoof) + if (this.BlockInfo.pointedRoof) { - AddPointedRoof(); + this.AddPointedRoof(); } } public void FindSpecialSides() { - if (pb.faces.Count < 5) + if (this.pb.faces.Count < 5) { return; } - this.topFace = pb.faces[0]; - var topWingedEdges = WingedEdge.GetWingedEdges(pb, new Face[] {this.topFace}, false); + this.topFace = this.pb.faces[0]; + var topWingedEdges = WingedEdge.GetWingedEdges(this.pb, new Face[] {this.topFace}, false); // For now, this only works on blocks with a building with 4 sides. if (this.topFace.edges.Count != 4) @@ -110,7 +99,7 @@ public void FindSpecialSides() // find shortest side: foreach (var wingedEdge in topWingedEdges) { - var vertices = pb.GetVertices(new List() {wingedEdge.edge.local.a, wingedEdge.edge.local.b}); + var vertices = this.pb.GetVertices(new List() {wingedEdge.edge.local.a, wingedEdge.edge.local.b}); var edgeLength = Vector3.Distance(vertices[0].position, vertices[1].position); if (shortestDistance == 0 || edgeLength < shortestDistance) { shortestDistance = edgeLength; @@ -133,13 +122,13 @@ public void FindSpecialSides() } } - var wingedEdges = WingedEdge.GetWingedEdges(pb, pb.faces, false); + var wingedEdges = WingedEdge.GetWingedEdges(this.pb, this.pb.faces, false); foreach (var wingedEdge in wingedEdges) { - if (wingedEdge.edge.common == topFaceShortestEdgeCommon && wingedEdge.face != topFace) { + if (wingedEdge.edge.common == this.topFaceShortestEdgeCommon && wingedEdge.face != this.topFace) { this.frontFace = wingedEdge.face; this.frontFaceTopEdge = wingedEdge.edge.local; } - if (wingedEdge.edge.common == topFaceOppositeEdgeCommon && wingedEdge.face != topFace) { + if (wingedEdge.edge.common == this.topFaceOppositeEdgeCommon && wingedEdge.face != this.topFace) { this.backFace = wingedEdge.face; this.backFaceTopEdge = wingedEdge.edge.local; } @@ -148,29 +137,29 @@ public void FindSpecialSides() public void AddPointedRoof() { - if (!fourSides) + if (!this.fourSides) { return; } try { // Optionally, pull up back and front facades: - if (this.raiseFrontAndBackFacadeTop) { - VertexEditing.SplitVertices(pb, this.frontFaceTopEdge); - VertexEditing.SplitVertices(pb, this.backFaceTopEdge); - pb.TranslateVertices(new Edge[] {this.frontFaceTopEdge, this.backFaceTopEdge}, new Vector3(0f, pointedRoofHeight, 0f)); + if (this.BlockInfo.raiseFrontAndBackFacadeTop) { + VertexEditing.SplitVertices(this.pb, this.frontFaceTopEdge); + VertexEditing.SplitVertices(this.pb, this.backFaceTopEdge); + pb.TranslateVertices(new Edge[] {this.frontFaceTopEdge, this.backFaceTopEdge}, new Vector3(0f, this.BlockInfo.pointedRoofHeight, 0f)); } // Draw new top-ridge as edge connecting center shortest side and its opposite side - var connectResult = pb.Connect(new Edge[] {this.topFaceShortestEdge, this.topFaceOppositeEdge}); + var connectResult = this.pb.Connect(new Edge[] {this.topFaceShortestEdge, this.topFaceOppositeEdge}); var newEdge = connectResult.item2[0]; // Pull this new edge up: - var extrudedEdges = pb.Extrude(new Edge[] {newEdge}, 0f, false, true); - pb.TranslateVertices(connectResult.item2, new Vector3(0f, pointedRoofHeight, 0f)); + var extrudedEdges = this.pb.Extrude(new Edge[] {newEdge}, 0f, false, true); + this.pb.TranslateVertices(connectResult.item2, new Vector3(0f, this.BlockInfo.pointedRoofHeight, 0f)); - pb.ToMesh(); - pb.Refresh(); + this.pb.ToMesh(); + this.pb.Refresh(); } catch (System.Exception) { @@ -179,21 +168,21 @@ public void AddPointedRoof() { public void LeanForward() { - if (!fourSides | leanForward == 0) + if (!this.fourSides | this.BlockInfo.leanForward == 0) { return; } - LeanForwardFromTopEdge(this.topFaceShortestEdgeCommon); - LeanForwardFromTopEdge(this.topFaceOppositeEdgeCommon); + this.LeanForwardFromTopEdge(this.topFaceShortestEdgeCommon); + this.LeanForwardFromTopEdge(this.topFaceOppositeEdgeCommon); } public void LeanForwardFromTopEdge(Edge edge) { - var edgePoints = pb.GetVertices(new List() {edge.a, edge.b}); + var edgePoints = this.pb.GetVertices(new List() {edge.a, edge.b}); var vector = edgePoints[1].position - edgePoints[0].position; var dist = vector.magnitude; - var transform = new Vector3(vector.z * leanForward / vector.magnitude, 0, vector.x * leanForward / vector.magnitude); + var transform = new Vector3(vector.z * this.BlockInfo.leanForward / vector.magnitude, 0, vector.x * this.BlockInfo.leanForward / vector.magnitude); pb.TranslateVertices(new List(){this.topFaceShortestEdge}, transform); pb.ToMesh(); @@ -204,7 +193,7 @@ private Face findWallBelow(Edge edge) { // find the wall-face below, to get its normal (because we want to stretch in that direction); var i = 0; - foreach (var face in pb.faces) { + foreach (var face in this.pb.faces) { // first we get the bottom and ceiling, we want to skip those if (i > 1) { diff --git a/Editor/Editors/PrefabOnGridEditor.cs.meta b/Editor/Builders/BlockFromPolygonBuilder.cs.meta similarity index 83% rename from Editor/Editors/PrefabOnGridEditor.cs.meta rename to Editor/Builders/BlockFromPolygonBuilder.cs.meta index fa0656e..ee5f6d7 100644 --- a/Editor/Editors/PrefabOnGridEditor.cs.meta +++ b/Editor/Builders/BlockFromPolygonBuilder.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: dcefbb0f190a9d24cb6419d79f70b81c +guid: 8be066ff3d8570241a3bd23b60b2898f MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Builders/BlocksFromGeoJsonBuilder.cs b/Editor/Builders/BlocksFromGeoJsonBuilder.cs new file mode 100644 index 0000000..ce4c09d --- /dev/null +++ b/Editor/Builders/BlocksFromGeoJsonBuilder.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; + +using System.Linq; +using GeoJsonCityBuilder.Data.GeoJSON; +using UnityEngine; +using UnityEngine.ProBuilder; + +namespace GeoJsonCityBuilder.Editor +{ + public class BlocksFromGeoJsonBuilder { + + Coordinate m_origin; + List m_features; + + public BlocksFromGeoJson Component { get; private set; } + + public BlocksFromGeoJsonBuilder(BlocksFromGeoJson blocksFromGeoJsonComponent) + { + this.Component = blocksFromGeoJsonComponent; + this.m_origin = Component.GetComponent().Origin; + } + + + private void DeserializeGeoJson() + { + var geoJSON = new GeoJSONObject(this.Component.geoJsonFile.text); + var filteredFeatures = + from feature in geoJSON.FeatureCollection.Features + select feature; + + if (this.Component.featureTypeFilter != null && this.Component.featureTypeFilter != "") { + filteredFeatures = + from feature in filteredFeatures + where feature.Properties.Type == this.Component.featureTypeFilter + select feature; + } + this.m_features = filteredFeatures.ToList(); + } + + void DeserializeGeoJsonIfNecessary() + { + if (this.m_features == null) + { + DeserializeGeoJson(); + } + } + + public void RemoveAllChildren() + { + if (Application.IsPlaying(this.Component.gameObject)) + { + foreach (Transform child in this.Component.transform) + { + GameObject.Destroy(child.gameObject); + } + } + else + { + while (this.Component.transform.childCount > 0) + { + GameObject.DestroyImmediate(this.Component.transform.GetChild(0).gameObject); + } + } + } + + public void Rebuild() + { + this.RemoveAllChildren(); + this.DeserializeGeoJson(); + + int i = 0; + + foreach (var feature in this.m_features) + { + var geometry = feature.Geometry as PolygonGeometry; + + var block = new GameObject(this.Component.featureTypeFilter + i++.ToString()); + block.transform.parent = this.Component.transform; + block.transform.position = this.Component.transform.position; + + var controller = block.AddComponent(); + controller.height = feature.Properties.Height == null || feature.Properties.Height == 0 ? Random.Range(this.Component.heightMin, this.Component.heightMax) : feature.Properties.Height.Value; + + controller.sideMaterial = this.Component.sideMaterials[Random.Range(0, this.Component.sideMaterials.Count)]; + controller.topMaterial = this.Component.topMaterial; + controller.bottomMaterial = this.Component.bottomMaterial; + controller.sideUvUnwrapSettings = this.Component.sideUvUnwrapSettings; + controller.pointedRoof = this.Component.pointedRoofTops; + controller.raiseFrontAndBackFacadeTop = this.Component.raiseFacades; + + controller.floorPolygon = new List(from coor in geometry.Coordinates[0] select new Vector3(coor.ToLocalGrid(m_origin).x, 0, coor.ToLocalGrid(m_origin).y)); + + var blockBuilder = new BlockFromPolygonBuilder(controller); + blockBuilder.Draw(); + } + } + } +} \ No newline at end of file diff --git a/Editor/Editors/BlockFromFeatureEditor.cs.meta b/Editor/Builders/BlocksFromGeoJsonBuilder.cs.meta similarity index 83% rename from Editor/Editors/BlockFromFeatureEditor.cs.meta rename to Editor/Builders/BlocksFromGeoJsonBuilder.cs.meta index b6aee38..aba5cdb 100644 --- a/Editor/Editors/BlockFromFeatureEditor.cs.meta +++ b/Editor/Builders/BlocksFromGeoJsonBuilder.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c82b56247e988b749bc9004eddeac3d0 +guid: 516b8864e44994b42920848c95006cc2 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Builders/PrefabsFromGeoJsonBuilder.cs b/Editor/Builders/PrefabsFromGeoJsonBuilder.cs new file mode 100644 index 0000000..f1af678 --- /dev/null +++ b/Editor/Builders/PrefabsFromGeoJsonBuilder.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; + +using System.Linq; +using GeoJsonCityBuilder.Data.GeoJSON; +using UnityEditor; +using UnityEngine; +using UnityEngine.ProBuilder; +using UnityEngine.ProBuilder.MeshOperations; + +namespace GeoJsonCityBuilder.Editor +{ + public class PrefabsFromGeoJsonBuilder { + public PrefabsFromGeoJson Component + { + get; + private set; + } + + Coordinate m_origin; + List m_geometries; + + public PrefabsFromGeoJsonBuilder(PrefabsFromGeoJson component) + { + this.Component = component; + this.m_origin = component.GetComponent().Origin; + + } + + private void DeserializeGeoJson() + { + var geoJSON = new GeoJSONObject(this.Component.geoJsonFile.text); + var filteredGeometries = + from feature in geoJSON.FeatureCollection.Features + where this.Component.featureTypeFilter == "" || feature.Properties.Type == this.Component.featureTypeFilter + select feature.Geometry as PointGeometry; + this.m_geometries = filteredGeometries.ToList(); + } + + public void RemoveAllChildren() + { + if (Application.IsPlaying(this.Component.gameObject)) + { + foreach (Transform child in this.Component.transform) + { + GameObject.Destroy(child.gameObject); + } + } + else + { + while (this.Component.transform.childCount > 0) + { + GameObject.DestroyImmediate(this.Component.transform.GetChild(0).gameObject); + } + } + } + + public void Rebuild() + { + this.RemoveAllChildren(); + this.DeserializeGeoJson(); + + foreach (var geometry in this.m_geometries) + { + var go = Object.Instantiate(this.Component.prefab, this.Component.transform); + + var positionComponent = go.AddComponent(); + positionComponent.Origin = geometry.Coordinate; + + positionComponent.Recalculate(); + + go.transform.Rotate(0f, Random.Range(0f, 360f), 0, Space.Self); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Components/BlockFromFeature.cs.meta b/Editor/Builders/PrefabsFromGeoJsonBuilder.cs.meta similarity index 83% rename from Runtime/Components/BlockFromFeature.cs.meta rename to Editor/Builders/PrefabsFromGeoJsonBuilder.cs.meta index 413a86f..7191180 100644 --- a/Runtime/Components/BlockFromFeature.cs.meta +++ b/Editor/Builders/PrefabsFromGeoJsonBuilder.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 075290b1cf9d618409b2b837129f125f +guid: eec4f8115b828e84d8a494e167c5d10f MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Editors/BlockFromFeatureEditor.cs b/Editor/Editors/BlockFromPolygonEditor.cs similarity index 86% rename from Editor/Editors/BlockFromFeatureEditor.cs rename to Editor/Editors/BlockFromPolygonEditor.cs index 44a15a9..a421494 100644 --- a/Editor/Editors/BlockFromFeatureEditor.cs +++ b/Editor/Editors/BlockFromPolygonEditor.cs @@ -6,9 +6,9 @@ namespace GeoJsonCityBuilder.Editor { - [CustomEditor(typeof(BlockFromFeature))] + [CustomEditor(typeof(BlockFromPolygon))] [CanEditMultipleObjects] - public class BlockFromFeatureEditor : UnityEditor.Editor + public class BlockFromPolygonEditor : UnityEditor.Editor { SerializedProperty topMaterial; SerializedProperty bottomMaterial; @@ -36,9 +36,10 @@ void OnEnable() public override void OnInspectorGUI() { - var controller = this.serializedObject.targetObject as BlockFromFeature; + var controller = this.serializedObject.targetObject as BlockFromPolygon; serializedObject.Update(); + EditorGUILayout.PropertyField(height); EditorGUILayout.Separator(); EditorGUILayout.PropertyField(topMaterial); @@ -49,14 +50,16 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(pointedRoofHeight); EditorGUILayout.PropertyField(raiseFrontAndBackFacadeTop); EditorGUILayout.PropertyField(leanForward); - if (controller.floor != null) { + + if (controller.floorPolygon != null) { EditorGUILayout.BeginFoldoutHeaderGroup(false, "Polygon"); - foreach(var coordinate in (this.serializedObject.targetObject as BlockFromFeature).floor) + foreach(var coordinate in (this.serializedObject.targetObject as BlockFromPolygon).floorPolygon) { EditorGUILayout.LabelField(coordinate.ToString()); } EditorGUILayout.EndFoldoutHeaderGroup(); } + // EditorGUILayout.PropertyField(floor); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Set Test Floor")) @@ -65,16 +68,17 @@ public override void OnInspectorGUI() } if (GUILayout.Button("Draw")) { - controller.Draw(); + var builder = new BlockFromPolygonBuilder(controller); + builder.Draw(); } EditorGUILayout.EndHorizontal(); serializedObject.ApplyModifiedProperties(); } private void CreateTestFloor() { - var controller = this.target as BlockFromFeature; + var controller = this.target as BlockFromPolygon; - controller.floor = new List() { + controller.floorPolygon = new List() { new Vector3( 5f, 0f, 10f), new Vector3(-5f, 0f, 10f), new Vector3(-5f, 0f,-10f), diff --git a/Editor/Editors/GeoJsonCityBuilderEditor.cs.meta b/Editor/Editors/BlockFromPolygonEditor.cs.meta similarity index 83% rename from Editor/Editors/GeoJsonCityBuilderEditor.cs.meta rename to Editor/Editors/BlockFromPolygonEditor.cs.meta index 7e0be53..e1d0b76 100644 --- a/Editor/Editors/GeoJsonCityBuilderEditor.cs.meta +++ b/Editor/Editors/BlockFromPolygonEditor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 6cdf41c34809d7241a385e1ce061427f +guid: e35a02d850d41a14b9c06052b9f32cc6 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Editors/BlocksFromGeoJsonEditor.cs b/Editor/Editors/BlocksFromGeoJsonEditor.cs index ad118fe..ebcd32a 100644 --- a/Editor/Editors/BlocksFromGeoJsonEditor.cs +++ b/Editor/Editors/BlocksFromGeoJsonEditor.cs @@ -22,6 +22,8 @@ public class BlocksFromGeoJsonEditor : UnityEditor.Editor SerializedProperty pointedRoofTops; SerializedProperty raiseFacades; + BlocksFromGeoJsonBuilder builder; + void OnEnable() { geoJsonFile = serializedObject.FindProperty("geoJsonFile"); @@ -34,6 +36,8 @@ void OnEnable() bottomMaterial = serializedObject.FindProperty("bottomMaterial"); pointedRoofTops = serializedObject.FindProperty("pointedRoofTops"); raiseFacades = serializedObject.FindProperty("raiseFacades"); + + builder = new BlocksFromGeoJsonBuilder(this.serializedObject.targetObject as BlocksFromGeoJson); } public override void OnInspectorGUI() @@ -53,15 +57,11 @@ public override void OnInspectorGUI() EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Clear")) { - var controller = this.serializedObject.targetObject as BlocksFromGeoJson; - - controller.RemoveAllChildren(); + this.builder.RemoveAllChildren(); } if (GUILayout.Button("Generate")) { - var controller = this.serializedObject.targetObject as BlocksFromGeoJson; - - controller.Rebuild(); + this.builder.Rebuild(); } EditorGUILayout.EndHorizontal(); serializedObject.ApplyModifiedProperties(); diff --git a/Editor/Editors/GeoJsonCityBuilderEditor.cs b/Editor/Editors/GeoJsonCityBuilderEditor.cs deleted file mode 100644 index b9c9193..0000000 --- a/Editor/Editors/GeoJsonCityBuilderEditor.cs +++ /dev/null @@ -1,54 +0,0 @@ -//C# Example (LookAtPointEditor.cs) -using UnityEngine; -using UnityEditor; -using GeoJsonCityBuilder; - - -namespace GeoJsonCityBuilder.Editor -{ - - [CustomEditor(typeof(GeoJsonCityBuilder))] - [CanEditMultipleObjects] - public class GeoJsonCityBuilderEditor : UnityEditor.Editor - { - SerializedProperty geoJsonFile; - SerializedProperty wallMaterial; - SerializedProperty waterMaterial; - SerializedProperty streetMaterial; - SerializedProperty treePrefab; - - void OnEnable() - { - geoJsonFile = serializedObject.FindProperty("geoJsonFile"); - wallMaterial = serializedObject.FindProperty("wallMaterial"); - waterMaterial = serializedObject.FindProperty("waterMaterial"); - streetMaterial = serializedObject.FindProperty("streetMaterial"); - treePrefab = serializedObject.FindProperty("treePrefab"); - } - - public override void OnInspectorGUI() - { - serializedObject.Update(); - EditorGUILayout.PropertyField(geoJsonFile); - EditorGUILayout.PropertyField(wallMaterial); - EditorGUILayout.PropertyField(streetMaterial); - EditorGUILayout.PropertyField(waterMaterial); - EditorGUILayout.PropertyField(treePrefab); - EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button("Clear")) - { - var controller = this.serializedObject.targetObject as GeoJsonCityBuilder; - - controller.RemoveAllChildren(); - } - if (GUILayout.Button("Generate")) - { - var controller = this.serializedObject.targetObject as GeoJsonCityBuilder; - - controller.Rebuild(); - } - EditorGUILayout.EndHorizontal(); - serializedObject.ApplyModifiedProperties(); - } - } -} \ No newline at end of file diff --git a/Editor/Editors/PrefabOnGridEditor.cs b/Editor/Editors/PrefabOnGridEditor.cs deleted file mode 100644 index bbbf8fc..0000000 --- a/Editor/Editors/PrefabOnGridEditor.cs +++ /dev/null @@ -1,57 +0,0 @@ -//C# Example (LookAtPointEditor.cs) -using UnityEngine; -using UnityEditor; - - -namespace GeoJsonCityBuilder.Editor -{ - - [CustomEditor(typeof(PrefabOnGrid))] - [CanEditMultipleObjects] - public class PrefabOnGridEditor : UnityEditor.Editor - { - SerializedProperty maxRowHeight; - SerializedProperty maxColumnWidth; - SerializedProperty prefab; - SerializedProperty rotation; - SerializedProperty zPosition; - SerializedProperty width; - SerializedProperty height; - - void OnEnable() - { - maxRowHeight = serializedObject.FindProperty("maxRowHeight"); - maxColumnWidth = serializedObject.FindProperty("maxColumnWidth"); - prefab = serializedObject.FindProperty("prefab"); - rotation = serializedObject.FindProperty("rotation"); - zPosition = serializedObject.FindProperty("zPosition"); - width = serializedObject.FindProperty("width"); - height = serializedObject.FindProperty("height"); - } - - public override void OnInspectorGUI() - { - serializedObject.Update(); - EditorGUILayout.PropertyField(maxRowHeight); - EditorGUILayout.PropertyField(maxColumnWidth); - EditorGUILayout.PropertyField(prefab); - EditorGUILayout.PropertyField(rotation); - EditorGUILayout.PropertyField(zPosition); - EditorGUILayout.PropertyField(width); - EditorGUILayout.PropertyField(height); - EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button("Recalculate")) - { - var controller = this.serializedObject.targetObject as PrefabOnGrid; - controller.RecalculateGrid(); - } - if (GUILayout.Button("Draw")) - { - var controller = this.serializedObject.targetObject as PrefabOnGrid; - controller.DrawGrid(); - } - EditorGUILayout.EndHorizontal(); - serializedObject.ApplyModifiedProperties(); - } - } -} \ No newline at end of file diff --git a/Editor/Editors/PrefabsFromGeoJsonEditor.cs b/Editor/Editors/PrefabsFromGeoJsonEditor.cs index d34b333..fc7eab7 100644 --- a/Editor/Editors/PrefabsFromGeoJsonEditor.cs +++ b/Editor/Editors/PrefabsFromGeoJsonEditor.cs @@ -13,11 +13,15 @@ public class PrefabsFromGeoJsonEditor : UnityEditor.Editor SerializedProperty featureTypeFilter; SerializedProperty prefab; + PrefabsFromGeoJsonBuilder builder; + void OnEnable() { geoJsonFile = serializedObject.FindProperty("geoJsonFile"); featureTypeFilter = serializedObject.FindProperty("featureTypeFilter"); prefab = serializedObject.FindProperty("prefab"); + + builder = new PrefabsFromGeoJsonBuilder(this.serializedObject.targetObject as PrefabsFromGeoJson); } public override void OnInspectorGUI() @@ -29,15 +33,11 @@ public override void OnInspectorGUI() EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Clear")) { - var controller = this.serializedObject.targetObject as PrefabsFromGeoJson; - - controller.RemoveAllChildren(); + builder.RemoveAllChildren(); } if (GUILayout.Button("Generate")) { - var controller = this.serializedObject.targetObject as PrefabsFromGeoJson; - - controller.Rebuild(); + builder.Rebuild(); } EditorGUILayout.EndHorizontal(); serializedObject.ApplyModifiedProperties(); diff --git a/Runtime/Components/BlockFromPolygon.cs b/Runtime/Components/BlockFromPolygon.cs new file mode 100644 index 0000000..83e10b0 --- /dev/null +++ b/Runtime/Components/BlockFromPolygon.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.ProBuilder; +using UnityEngine.ProBuilder.MeshOperations; + +namespace GeoJsonCityBuilder +{ + // Require removed, because it caused a Unity build-error + // with HDRP (build apparently tries to remove all + // components without checking component-dependencies) + // [RequireComponent(typeof(ProBuilderMesh))] + [RequireComponent(typeof(MeshCollider))] + public class BlockFromPolygon : MonoBehaviour + { + public List floorPolygon = new List(); + + public Material topMaterial; + public Material bottomMaterial; + public Material sideMaterial; + public float height = 10f; + + public bool pointedRoof = false; + public float pointedRoofHeight = 3f; + public bool raiseFrontAndBackFacadeTop = false; + public float leanForward = 0f; + + public AutoUnwrapSettings sideUvUnwrapSettings = new AutoUnwrapSettings(); + } +} \ No newline at end of file diff --git a/Runtime/Components/BlockFromPolygon.cs.meta b/Runtime/Components/BlockFromPolygon.cs.meta new file mode 100644 index 0000000..b4a4d86 --- /dev/null +++ b/Runtime/Components/BlockFromPolygon.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e16c7b1cbd9e7a44ab7725f25789806 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Components/BlocksFromGeoJson.cs b/Runtime/Components/BlocksFromGeoJson.cs index 428834f..0ad631b 100644 --- a/Runtime/Components/BlocksFromGeoJson.cs +++ b/Runtime/Components/BlocksFromGeoJson.cs @@ -22,85 +22,5 @@ public class BlocksFromGeoJson : MonoBehaviour public AutoUnwrapSettings sideUvUnwrapSettings = new AutoUnwrapSettings(); public bool pointedRoofTops = false; public bool raiseFacades = false; - - Coordinate m_origin; - List m_features; - // Start is called before the first frame update - void Start() - { - m_origin = GetComponent().Origin; - } - private void DeserializeGeoJson() - { - var geoJSON = new GeoJSONObject(geoJsonFile.text); - var filteredFeatures = - from feature in geoJSON.FeatureCollection.Features - select feature; - - if (featureTypeFilter != null && featureTypeFilter != "") { - filteredFeatures = - from feature in filteredFeatures - where feature.Properties.Type == featureTypeFilter - select feature; - } - m_features = filteredFeatures.ToList(); - } - - void DeserializeGeoJsonIfNecessary() - { - if (m_features == null) - { - DeserializeGeoJson(); - } - } - - public void RemoveAllChildren() - { - if (Application.IsPlaying(gameObject)) - { - foreach (Transform child in transform) - { - GameObject.Destroy(child.gameObject); - } - } - else - { - while (transform.childCount > 0) - { - GameObject.DestroyImmediate(transform.GetChild(0).gameObject); - } - } - } - - public void Rebuild() - { - RemoveAllChildren(); - DeserializeGeoJson(); - - int i = 0; - - foreach (var feature in m_features) - { - var geometry = feature.Geometry as PolygonGeometry; - - var block = new GameObject(featureTypeFilter + i++.ToString()); - block.transform.parent = transform; - block.transform.position = transform.position; - - var controller = block.AddComponent(); - controller.height = feature.Properties.Height == null || feature.Properties.Height == 0 ? Random.Range(heightMin, heightMax) : feature.Properties.Height.Value; - - controller.sideMaterial = this.sideMaterials[Random.Range(0, this.sideMaterials.Count)]; - controller.topMaterial = topMaterial; - controller.bottomMaterial = bottomMaterial; - controller.sideUvUnwrapSettings = sideUvUnwrapSettings; - controller.pointedRoof = pointedRoofTops; - controller.raiseFrontAndBackFacadeTop = raiseFacades; - - controller.floor = new List(from coor in geometry.Coordinates[0] select new Vector3(coor.ToLocalGrid(m_origin).x, 0, coor.ToLocalGrid(m_origin).y)); - - controller.Draw(); - } - } } } \ No newline at end of file diff --git a/Runtime/Components/BuildingController.cs b/Runtime/Components/BuildingController.cs deleted file mode 100644 index a5f7748..0000000 --- a/Runtime/Components/BuildingController.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.ProBuilder; -using UnityEngine.ProBuilder.MeshOperations; - -namespace GeoJsonCityBuilder -{ - public class BuildingController : MonoBehaviour - { - public IList floor; - - public Material wallMaterial; - public float height = 10f; - - public void DrawBuilding() - { - var mesh = gameObject.AddComponent(); - if (gameObject.GetComponent() == null) - { - gameObject.AddComponent(); - } - - var first = floor.First(); - var last = floor.Last(); - if (first.x == last.x && first.y == last.y && first.z == last.z) - { - floor.Remove(floor.Last()); - } - - mesh.CreateShapeFromPolygon(floor, height, false); - gameObject.GetComponent().material = this.wallMaterial; - - } - } -} \ No newline at end of file diff --git a/Runtime/Components/BuildingController.cs.meta b/Runtime/Components/BuildingController.cs.meta deleted file mode 100644 index 8f09536..0000000 --- a/Runtime/Components/BuildingController.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b7a35e68d3fba094c86a704149bc3b4c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Components/GeoJsonCityBuilder.cs b/Runtime/Components/GeoJsonCityBuilder.cs deleted file mode 100644 index 479ea1d..0000000 --- a/Runtime/Components/GeoJsonCityBuilder.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System.Collections.Generic; - -using System.Linq; -using GeoJsonCityBuilder.Data.GeoJSON; -using UnityEditor; -using UnityEngine; -using UnityEngine.ProBuilder; -using UnityEngine.ProBuilder.MeshOperations; - -namespace GeoJsonCityBuilder -{ - - [ExecuteAlways] - [RequireComponent(typeof(PositionOnWorldCoordinates))] - public class GeoJsonCityBuilder : MonoBehaviour - { - public TextAsset geoJsonFile; - public Material wallMaterial; - public Material waterMaterial; - public Material streetMaterial; - public GameObject treePrefab; - - private Coordinate origin; - - private FeatureCollection dataFromJson; - - // Start is called before the first frame update - void Start() - { - origin = GetComponent().Origin; - } - void DeserializeGeoJson() - { - var geoJSON = new GeoJSONObject(geoJsonFile.text); - dataFromJson = geoJSON.FeatureCollection; - } - - public void RemoveAllChildren() - { - if (Application.IsPlaying(gameObject)) - { - foreach (Transform child in transform) - { - GameObject.Destroy(child.gameObject); - } - } - else - { - while (transform.childCount > 0) - { - GameObject.DestroyImmediate(transform.GetChild(0).gameObject); - } - } - } - - public void Rebuild() - { - RemoveAllChildren(); - DeserializeGeoJson(); - CreateTerrain(dataFromJson.Features, 2000f); - - int i = 0; - - foreach (var feature in dataFromJson.Features) - { - if (feature.Properties.Type == "Building") - { - var polygon = feature.Geometry as PolygonGeometry; - var building = new GameObject("Building " + i++.ToString()); - - building.transform.parent = transform; - - var controller = building.AddComponent(); - controller.height = controller.height + Random.Range(-2f, 2f); - controller.wallMaterial = wallMaterial; - controller.floor = new List(from coor in polygon.Coordinates[0] select new Vector3(coor.ToLocalGrid(origin).x, 0, coor.ToLocalGrid(origin).y)); - - controller.DrawBuilding(); - } - - if (feature.Properties.Type == "Tree") - { - var tree = Instantiate(treePrefab, transform); - - var point = feature.Geometry as PointGeometry; - - var positionComponent = tree.AddComponent(); - positionComponent.Origin = point.Coordinate; - - positionComponent.Recalculate(); - } - } - - } - - private void DrawCanals(IEnumerable features) - { - var canalPolygons = from feature in features where feature.Properties.Type == "Canal" select feature.Geometry as PolygonGeometry; - foreach (var polygon in canalPolygons) - { - var points = from coor in polygon.Coordinates[0] select new Vector3(coor.ToLocalGrid(origin).x, 0.5f, coor.ToLocalGrid(origin).y); - // canalController.DrawCanal(points.ToArray(), 2f); - } - } - - private void CreateTerrain(List features, float sizeBorderToCenter) - { - var canalPolygons = (from feature in features where feature.Properties.Type == "Canal" select feature.Geometry as PolygonGeometry).ToList(); - - Poly2Mesh.Polygon poly = new Poly2Mesh.Polygon(); - poly.outside = new List() { - new Vector3(sizeBorderToCenter * -1, 0, sizeBorderToCenter), - new Vector3(sizeBorderToCenter, 0, sizeBorderToCenter), - new Vector3(sizeBorderToCenter, 0, sizeBorderToCenter * -1), - new Vector3(sizeBorderToCenter * -1, 0, sizeBorderToCenter * -1), - }; - foreach (var polygon in canalPolygons) - { - var points = from coor in polygon.Coordinates[0] select new Vector3(coor.ToLocalGrid(origin).x, 0f, coor.ToLocalGrid(origin).y); - - poly.holes.Add(new List(points)); - } - - // Set up game object with mesh; - GameObject terrainObject = Poly2Mesh.CreateGameObject(poly); - terrainObject.name = "Street"; - terrainObject.transform.parent = transform; - - // Probuilderize: - var importer = new MeshImporter(terrainObject); - importer.Import(); - - // Add collider: - var collider = terrainObject.AddComponent(); - - // Set material and use auto UV using world space (to prevent stretching): - - var terrainMesh = terrainObject.GetComponent(); - foreach(var face in terrainMesh.faces) - { - face.manualUV = false; - } - terrainObject.GetComponent().material = this.streetMaterial; - - terrainMesh.ToMesh(); - terrainMesh.Refresh(); - - - // Now add the canal containers: - foreach (var polygon in canalPolygons) - { - var canalObject = new GameObject("Canal"); - canalObject.transform.parent = transform; - var canalMesh = canalObject.AddComponent(); - canalObject.AddComponent(); - - var points = (from coor in polygon.Coordinates[0] select new Vector3(coor.ToLocalGrid(origin).x, 0f, coor.ToLocalGrid(origin).y)).ToList(); - - var first = points.First(); - var last = points.Last(); - if (first.x == last.x && first.y == last.y && first.z == last.z) - { - points.Remove(points.Last()); - } - - const float canalDepth = 2f; - - canalMesh.CreateShapeFromPolygon(points, -1 * canalDepth, false); - - // Find the top face: - Face ceiling = null; - foreach(var face in canalMesh.faces) - { - ceiling = face; - foreach(var vertex in canalMesh.GetVertices(face.distinctIndexes)) - { - if (vertex.position.y < 0) - { - ceiling = null; - break; - } - } - if (ceiling != null) - { - break; - } - } - - - // Delete the top face: - canalMesh.DeleteFace(ceiling); - - - - // Find the bottom face: - Face bottom = null; - foreach(var face in canalMesh.faces) - { - bottom = face; - foreach(var vertex in canalMesh.GetVertices(face.distinctIndexes)) - { - if (vertex.position.y == 0) - { - bottom = null; - break; - } - } - if (bottom != null) - { - break; - } - } - - foreach(var face in canalMesh.faces) - { - face.Reverse(); - } - - canalMesh.ToMesh(); - - canalMesh.SetMaterial(canalMesh.faces, this.wallMaterial); - canalMesh.SetMaterial(new List() { bottom }, this.waterMaterial); - //canalMesh.GetComponent().material = this.wallMaterial; - - - canalMesh.Refresh(); - - } - - - } - } -} \ No newline at end of file diff --git a/Runtime/Components/GeoJsonCityBuilder.cs.meta b/Runtime/Components/GeoJsonCityBuilder.cs.meta deleted file mode 100644 index 0311b6f..0000000 --- a/Runtime/Components/GeoJsonCityBuilder.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9bc2d096ae0d94240a6803cf8ee83d9f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Components/PrefabOnGrid.cs b/Runtime/Components/PrefabOnGrid.cs deleted file mode 100644 index 9189b72..0000000 --- a/Runtime/Components/PrefabOnGrid.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.ProBuilder; - -public class PrefabOnGrid : MonoBehaviour -{ - public float maxRowHeight; - public float maxColumnWidth; - // public Face face; - public GameObject prefab; - - public float rotation; - public float zPosition; - - public float width; - public float height; - - float[] rows; - float[] columns; - - float m_rowHeight; - float m_columnWidth; - - public void RecalculateGrid() { - var width = this.width; - var height = this.height; - - var columnCount = (int)System.Math.Floor(width / maxColumnWidth); - var rowCount = (int)System.Math.Floor(height / maxRowHeight); - - m_columnWidth = width / columnCount; - m_rowHeight = height / rowCount; - - columns = new float[columnCount]; - rows = new float[rowCount]; - - for (int i = 0; i < columnCount; i++) - { - columns[i] = (i * m_columnWidth) + (m_columnWidth / 2); - } - - for (int i = 0; i < rowCount; i++) - { - rows[i] = (i * m_rowHeight) + (m_rowHeight / 2); - } - } - - public void DrawGrid() - { - foreach (var column in columns) - { - foreach (var row in rows) - { - var go = Instantiate(prefab, transform); - go.transform.localPosition = new Vector3(column, row, zPosition); - go.transform.localScale = new Vector3(m_columnWidth, m_columnWidth, 1); - } - } - } - - float GetWidth() - { - return 0f; - } - - float GetHeight() - { - return 0f; - } -} diff --git a/Runtime/Components/PrefabOnGrid.cs.meta b/Runtime/Components/PrefabOnGrid.cs.meta deleted file mode 100644 index 89e781d..0000000 --- a/Runtime/Components/PrefabOnGrid.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e166499f35375a0449f701eccd51b25e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Components/PrefabsFromGeoJson.cs b/Runtime/Components/PrefabsFromGeoJson.cs index 98d2529..215b867 100644 --- a/Runtime/Components/PrefabsFromGeoJson.cs +++ b/Runtime/Components/PrefabsFromGeoJson.cs @@ -18,61 +18,5 @@ public class PrefabsFromGeoJson : MonoBehaviour public string featureTypeFilter; public GameObject prefab; - - Coordinate m_origin; - List m_geometries; - - // Start is called before the first frame update - void Start() - { - m_origin = GetComponent().Origin; - } - - private void DeserializeGeoJson() - { - var geoJSON = new GeoJSONObject(geoJsonFile.text); - var filteredGeometries = - from feature in geoJSON.FeatureCollection.Features - where featureTypeFilter == "" || feature.Properties.Type == featureTypeFilter - select feature.Geometry as PointGeometry; - m_geometries = filteredGeometries.ToList(); - } - - public void RemoveAllChildren() - { - if (Application.IsPlaying(gameObject)) - { - foreach (Transform child in transform) - { - GameObject.Destroy(child.gameObject); - } - } - else - { - while (transform.childCount > 0) - { - GameObject.DestroyImmediate(transform.GetChild(0).gameObject); - } - } - } - - public void Rebuild() - { - RemoveAllChildren(); - DeserializeGeoJson(); - - foreach (var geometry in m_geometries) - { - var go = Instantiate(prefab, transform); - - - var positionComponent = go.AddComponent(); - positionComponent.Origin = geometry.Coordinate; - - positionComponent.Recalculate(); - - go.transform.Rotate(0f, Random.Range(0f, 360f), 0, Space.Self); - } - } } } \ No newline at end of file