From 696343f2589cd5ea7af96a1b118547cfb08a45cc Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Wed, 4 Sep 2019 18:20:49 +0200 Subject: [PATCH] Add more detailed edges --- Assets/Map/LocationSite.cs | 2 + Assets/Scripts/MapRenderer.cs | 83 ++++++++++++++++++++++--- Assets/Triangulator.cs | 112 ++++++++++++++++++++++++++++++++++ Assets/Triangulator.cs.meta | 3 + 4 files changed, 192 insertions(+), 8 deletions(-) create mode 100644 Assets/Triangulator.cs create mode 100644 Assets/Triangulator.cs.meta diff --git a/Assets/Map/LocationSite.cs b/Assets/Map/LocationSite.cs index d48c181..0e08387 100644 --- a/Assets/Map/LocationSite.cs +++ b/Assets/Map/LocationSite.cs @@ -19,6 +19,8 @@ namespace Assets.Map public LocationType Type; + public List DetailedEdge = new List(); + public void AddSite(LocationSite site) { site.Location = this; diff --git a/Assets/Scripts/MapRenderer.cs b/Assets/Scripts/MapRenderer.cs index fedb6fe..e70c4c4 100644 --- a/Assets/Scripts/MapRenderer.cs +++ b/Assets/Scripts/MapRenderer.cs @@ -4,6 +4,7 @@ using System.Linq; using Assets.Common; using Assets.Map; using UnityEngine; +using Random = UnityEngine.Random; namespace Assets { @@ -13,13 +14,15 @@ namespace Assets public class MapRenderer : MonoBehaviour { public float UVScale = 1.0f; - + private List _vertices; private List _uv; private List _normals; private List _colors; private List _triangles; + private List> _edges; + public void Generate() { var graph = GetComponent(); @@ -37,7 +40,8 @@ namespace Assets foreach (var location in graph.LocationGenerator.Result.Vertices.Skip(1)) { - GenerateLocationMesh(location, points); + GenerateLocationEdges(location, points); + GenerateLocationMeshAlt(location, points); GenerateLocationWall(location, points); } @@ -49,6 +53,53 @@ namespace Assets mesh.colors = _colors.ToArray(); GetComponent().sharedMesh = mesh; + + } + + private void GenerateLocationEdges(Location location, List points) + { + foreach (var (a, b) in location.BoundaryEdges.Select(x => (points[x.Item1], points[x.Item2]))) + location.DetailedEdge.AddRange(this.SplitEdge(a, b, 3)); + } + + private IEnumerable SplitEdge(Point a, Point b, int count) + { +// var direction = ; + var magnitude = Point.Dist(a, b); + var d = new Point(-(b.y - a.y) / magnitude, (b.x - a.x) / magnitude); + + magnitude *= Random.value * 0.4 - 0.2; + + Point c = new Point((a.x + b.x) / 2.0 + d.x * magnitude, (a.y + b.y) / 2.0 + d.y * magnitude); + + if (count > 0) + { + foreach (var p in SplitEdge(a, c, count - 1)) + yield return p; + + yield return c; + + foreach (var p in SplitEdge(c, b, count - 1)) + yield return p; + } + else + { + yield return c; + } + } + + private void GenerateLocationMeshAlt(Location location, IList points) + { + var start = _vertices.Count; + var count = location.DetailedEdge.Count; + + _vertices.AddRange(location.DetailedEdge.Select(p => new Vector3((float)p.x, location.Type.height, (float)p.y))); + _normals.AddRange(Enumerable.Repeat(Vector3.up, count)); + _colors.AddRange(Enumerable.Repeat(Color.blue, count)); + _uv.AddRange(location.DetailedEdge.Select(p => new Vector2((float)p.x, (float)p.y) / UVScale)); + + var triangulator = new Triangulator(location.DetailedEdge.Select(v => new Vector2((float)v.x, (float)v.y)).ToArray()); + _triangles.AddRange(triangulator.Triangulate().Select(x => x + start)); } private void GenerateLocationMesh(Location location, IList points) @@ -71,11 +122,10 @@ namespace Assets } int end = _vertices.Count; + + var triangulator = new Triangulator(_vertices.Skip(start).Take(end - start).Select(v => new Vector2(v.x, v.z)).ToArray()); + _triangles.AddRange(triangulator.Triangulate().Select(x => x + start)); - for (int i = start + 1; i < end - 1; i++) - { - _triangles.AddRange(new []{ start, i, i+1 }); - } } } @@ -88,8 +138,8 @@ namespace Assets { var length = 0.0; - var collection = location.BoundaryPoints.Append(location.BoundaryPoints.First()); - var edges = collection.Zip(collection.Skip(1), (a, b) => (a, b)).Zip(collection.Skip(2), (tuple, c) => (points[tuple.a], points[tuple.b], points[c])); + var collection = location.DetailedEdge.Append(location.DetailedEdge.First()); + var edges = collection.Zip(collection.Skip(1), (a, b) => (a, b)).Zip(collection.Skip(2), (tuple, c) => (tuple.a, tuple.b, c)); foreach (var (p, c, n) in edges) { @@ -126,5 +176,22 @@ namespace Assets length += dist; } } + + private void OnDrawGizmos() + { + var graph = GetComponent(); + + foreach (var location in graph.LocationGenerator.Result.Vertices.Skip(1)) + { + var boundary = location.DetailedEdge; + foreach (var (a, b) in boundary.Zip(boundary.Skip(1).Append(boundary.First()), (a, b) => (a, b))) + { + var va = new Vector3((float) a.x, location.Type.height, (float) a.y); + var vb = new Vector3((float) b.x, location.Type.height, (float) b.y); + + Gizmos.DrawLine(va, vb); + } + } + } } } \ No newline at end of file diff --git a/Assets/Triangulator.cs b/Assets/Triangulator.cs new file mode 100644 index 0000000..4973ae3 --- /dev/null +++ b/Assets/Triangulator.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Assets +{ + public class Triangulator + { + private List m_points = new List(); + + public Triangulator (Vector2[] points) { + m_points = new List(points); + } + + public int[] Triangulate() { + List indices = new List(); + + int n = m_points.Count; + if (n < 3) + return indices.ToArray(); + + int[] V = new int[n]; + if (Area() > 0) { + for (int v = 0; v < n; v++) + V[v] = v; + } + else { + for (int v = 0; v < n; v++) + V[v] = (n - 1) - v; + } + + int nv = n; + int count = 2 * nv; + for (int v = nv - 1; nv > 2; ) { + if ((count--) <= 0) + return indices.ToArray(); + + int u = v; + if (nv <= u) + u = 0; + v = u + 1; + if (nv <= v) + v = 0; + int w = v + 1; + if (nv <= w) + w = 0; + + if (Snip(u, v, w, nv, V)) { + int a, b, c, s, t; + a = V[u]; + b = V[v]; + c = V[w]; + indices.Add(a); + indices.Add(b); + indices.Add(c); + for (s = v, t = v + 1; t < nv; s++, t++) + V[s] = V[t]; + nv--; + count = 2 * nv; + } + } + + indices.Reverse(); + return indices.ToArray(); + } + + private float Area () { + int n = m_points.Count; + float A = 0.0f; + for (int p = n - 1, q = 0; q < n; p = q++) { + Vector2 pval = m_points[p]; + Vector2 qval = m_points[q]; + A += pval.x * qval.y - qval.x * pval.y; + } + return (A * 0.5f); + } + + private bool Snip (int u, int v, int w, int n, int[] V) { + int p; + Vector2 A = m_points[V[u]]; + Vector2 B = m_points[V[v]]; + Vector2 C = m_points[V[w]]; + if (Mathf.Epsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x)))) + return false; + for (p = 0; p < n; p++) { + if ((p == u) || (p == v) || (p == w)) + continue; + Vector2 P = m_points[V[p]]; + if (InsideTriangle(A, B, C, P)) + return false; + } + return true; + } + + private bool InsideTriangle (Vector2 A, Vector2 B, Vector2 C, Vector2 P) { + float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; + float cCROSSap, bCROSScp, aCROSSbp; + + ax = C.x - B.x; ay = C.y - B.y; + bx = A.x - C.x; by = A.y - C.y; + cx = B.x - A.x; cy = B.y - A.y; + apx = P.x - A.x; apy = P.y - A.y; + bpx = P.x - B.x; bpy = P.y - B.y; + cpx = P.x - C.x; cpy = P.y - C.y; + + aCROSSbp = ax * bpy - ay * bpx; + cCROSSap = cx * apy - cy * apx; + bCROSScp = bx * cpy - by * cpx; + + return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); + } + } +} diff --git a/Assets/Triangulator.cs.meta b/Assets/Triangulator.cs.meta new file mode 100644 index 0000000..d9500c9 --- /dev/null +++ b/Assets/Triangulator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0cc918130bd1443ea69b7b49290749d2 +timeCreated: 1567611131 \ No newline at end of file