using Mapbox.Unity.Map; namespace Mapbox.Unity.MeshGeneration.Modifiers { using System.Collections.Generic; using UnityEngine; using Mapbox.Unity.MeshGeneration.Data; /// /// Line Mesh Modifier creates line polygons from a list of vertices. It offsets the original vertices to both sides using Width parameter and triangulates them manually. /// It also creates tiled UV mapping using the line length. /// MergeStartEnd parameter connects both edges of the line segment and creates a closed loop which is useful for some cases like pavements around a building block. /// [CreateAssetMenu(menuName = "Mapbox/Modifiers/Line Mesh Modifier")] public class LineMeshModifier : MeshModifier { [SerializeField] LineGeometryOptions _options; private float _scaledWidth; public override ModifierType Type { get { return ModifierType.Preprocess; } } public override void SetProperties(ModifierProperties properties) { _options = (LineGeometryOptions)properties; _options.PropertyHasChanged += UpdateModifier; } public override void Run(VectorFeatureUnity feature, MeshData md, float scale) { _scaledWidth = _options.Width * scale; ExtureLine(feature, md); } public override void Run(VectorFeatureUnity feature, MeshData md, UnityTile tile = null) { _scaledWidth = tile != null ? _options.Width * tile.TileScale : _options.Width; ExtureLine(feature, md); } private void ExtureLine(VectorFeatureUnity feature, MeshData md) { if (feature.Points.Count < 1) return; foreach (var roadSegment in feature.Points) { var mdVertexCount = md.Vertices.Count; var roadSegmentCount = roadSegment.Count; for (int i = 1; i < roadSegmentCount * 2; i++) { md.Edges.Add(mdVertexCount + i); md.Edges.Add(mdVertexCount + i - 1); } md.Edges.Add(mdVertexCount); md.Edges.Add(mdVertexCount + (roadSegmentCount * 2) - 1); var newVerticeList = new Vector3[roadSegmentCount * 2]; var newNorms = new Vector3[roadSegmentCount * 2]; var uvList = new Vector2[roadSegmentCount * 2]; var newTangents = new Vector4[roadSegmentCount * 2]; Vector3 norm; var lastUv = 0f; var p1 = Constants.Math.Vector3Zero; var p2 = Constants.Math.Vector3Zero; var p3 = Constants.Math.Vector3Zero; for (int i = 1; i < roadSegmentCount; i++) { p1 = roadSegment[i - 1]; p2 = roadSegment[i]; p3 = p2; if (i + 1 < roadSegmentCount) p3 = roadSegment[i + 1]; if (i == 1) { norm = GetNormal(p1, p1, p2) * _scaledWidth; //road width newVerticeList[0] = (p1 + norm); newVerticeList[roadSegmentCount * 2 - 1] = (p1 - norm); newNorms[0] = Constants.Math.Vector3Up; newNorms[roadSegmentCount * 2 - 1] = Constants.Math.Vector3Up; uvList[0] = new Vector2(0, 0); uvList[roadSegmentCount * 2 - 1] = new Vector2(1, 0); newTangents[0] = new Vector4(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z, 1).normalized; newTangents[roadSegmentCount * 2 - 1] = newTangents[0]; } var dist = Vector3.Distance(p1, p2); lastUv += dist; norm = GetNormal(p1, p2, p3) * _scaledWidth; newVerticeList[i] = (p2 + norm); newVerticeList[2 * roadSegmentCount - 1 - i] = (p2 - norm); newNorms[i] = Constants.Math.Vector3Up; newNorms[2 * roadSegmentCount - 1 - i] = Constants.Math.Vector3Up; uvList[i] = new Vector2(0, lastUv); uvList[2 * roadSegmentCount - 1 - i] = new Vector2(1, lastUv); newTangents[i] = new Vector4(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z, 1).normalized; newTangents[2 * roadSegmentCount - 1 - i] = newTangents[i]; } md.Vertices.AddRange(newVerticeList); md.Normals.AddRange(newNorms); md.UV[0].AddRange(uvList); md.Tangents.AddRange(newTangents); var lineTri = new List(); var n = roadSegmentCount; for (int i = 0; i < n - 1; i++) { lineTri.Add(mdVertexCount + i); lineTri.Add(mdVertexCount + i + 1); lineTri.Add(mdVertexCount + 2 * n - 1 - i); lineTri.Add(mdVertexCount + i + 1); lineTri.Add(mdVertexCount + 2 * n - i - 2); lineTri.Add(mdVertexCount + 2 * n - i - 1); } if (md.Triangles.Count < 1) md.Triangles.Add(new List()); md.Triangles[0].AddRange(lineTri); } } private Vector3 GetNormal(Vector3 p1, Vector3 newPos, Vector3 p2) { if (newPos == p1 || newPos == p2) { var n = (p2 - p1).normalized; return new Vector3(-n.z, 0, n.x); } var b = (p2 - newPos).normalized + newPos; var a = (p1 - newPos).normalized + newPos; var t = (b - a).normalized; if (t == Mapbox.Unity.Constants.Math.Vector3Zero) { var n = (p2 - p1).normalized; return new Vector3(-n.z, 0, n.x); } return new Vector3(-t.z, 0, t.x); } } }