Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
ElmarJ committed Jul 23, 2020
2 parents 371d24a + b15fa60 commit b84ba5f
Show file tree
Hide file tree
Showing 23 changed files with 304 additions and 710 deletions.
8 changes: 8 additions & 0 deletions Editor/Builders.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -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<Vector3> 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;
Expand All @@ -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<ProBuilderMesh>();
var mesh = this.GameObject.GetComponent<ProBuilderMesh>();
if (mesh == null) {
mesh = gameObject.AddComponent<ProBuilderMesh>();
mesh = this.GameObject.AddComponent<ProBuilderMesh>();
}

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<ProBuilderMesh>();
if (pb.faceCount > 2)
this.pb = GameObject.GetComponent<ProBuilderMesh>();
if (this.pb.faceCount > 2)
{
pb.SetMaterial(pb.faces, sideMaterial);
pb.SetMaterial(new List<Face>() { pb.faces[0] }, topMaterial);
pb.SetMaterial(new List<Face>() { pb.faces[1] }, bottomMaterial);
this.pb.SetMaterial(this.pb.faces, this.BlockInfo.sideMaterial);
this.pb.SetMaterial(new List<Face>() { this.pb.faces[0] }, this.BlockInfo.topMaterial);
this.pb.SetMaterial(new List<Face>() { 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)
Expand All @@ -110,7 +99,7 @@ public void FindSpecialSides()
// find shortest side:
foreach (var wingedEdge in topWingedEdges)
{
var vertices = pb.GetVertices(new List<int>() {wingedEdge.edge.local.a, wingedEdge.edge.local.b});
var vertices = this.pb.GetVertices(new List<int>() {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;
Expand All @@ -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;
}
Expand All @@ -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) {

Expand All @@ -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<int>() {edge.a, edge.b});
var edgePoints = this.pb.GetVertices(new List<int>() {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<Edge>(){this.topFaceShortestEdge}, transform);
pb.ToMesh();
Expand All @@ -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)
{
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 98 additions & 0 deletions Editor/Builders/BlocksFromGeoJsonBuilder.cs
Original file line number Diff line number Diff line change
@@ -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<Feature> m_features;

public BlocksFromGeoJson Component { get; private set; }

public BlocksFromGeoJsonBuilder(BlocksFromGeoJson blocksFromGeoJsonComponent)
{
this.Component = blocksFromGeoJsonComponent;
this.m_origin = Component.GetComponent<PositionOnWorldCoordinates>().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<BlockFromPolygon>();
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<Vector3>(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();
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit b84ba5f

Please sign in to comment.