/// <inheritdoc /> public override IGameObject BuildWay(Tile tile, Rule rule, Way way) { if (way.Points.Count < 2) { Trace.Warn("model.barrier", Strings.InvalidPolyline); return(null); } if (tile.Registry.Contains(way.Id)) { return(null); } tile.Registry.RegisterGlobal(way.Id); var gameObjectWrapper = GameObjectFactory.CreateNew(GetName(way)); var maxWidth = 4f; var points = ObjectPool.NewList <Vector2d>(way.Points.Count); PointUtils.SetPolygonPoints(tile.RelativeNullPoint, way.Points, points); var vertexCount = GetVertexCount(points, maxWidth); var meshIndex = new MultiPlaneMeshIndex(points.Count - 1, vertexCount); var meshData = new MeshData(meshIndex, vertexCount) { MaterialKey = rule.GetMaterialKey(), GameObject = gameObjectWrapper, }; meshData.Index = meshIndex; var context = new SegmentBuilderContext() { MeshData = meshData, Gradient = CustomizationService.GetGradient(rule.GetFillColor()), ColorNoiseFreq = rule.GetColorNoiseFreq(), Height = rule.GetHeight(), MaxWidth = maxWidth, }; var index = 0; for (int i = 0; i < points.Count - 1; i++) { var p1 = points[i]; var p2 = points[i + 1]; var start = new Vector3((float)p1.X, ElevationProvider.GetElevation(p1), (float)p1.Y); var end = new Vector3((float)p2.X, ElevationProvider.GetElevation(p2), (float)p2.Y); meshIndex.AddPlane(new Vector3((float)p1.X, 0, (float)p1.Y), start, end, meshData.NextIndex); BuildBarrierSegment(context, start, end, ref index); } ObjectPool.StoreList(points); BuildObject(tile.GameObject, meshData, rule, way); return(gameObjectWrapper); }
private int GetVertexCount(List <Vector2d> points, float maxWidth) { int count = 0; for (int i = 0; i < points.Count - 1; i++) { var p1 = points[i]; var p2 = points[i + 1]; var start = new Vector3((float)p1.X, ElevationProvider.GetElevation(p1), (float)p1.Y); var end = new Vector3((float)p2.X, ElevationProvider.GetElevation(p2), (float)p2.Y); var distance = Vector3.Distance(start, end); count += (int)Math.Ceiling(distance / maxWidth) * 12; } return(count); }
/// <summary> Process unity specific data. </summary> private void BuildObject(Tile tile, IGameObject gameObjectWrapper, Rule rule, Rectangle2d rect, Vector2d point, float minHeight) { var gameObject = gameObjectWrapper.AddComponent(GameObject.CreatePrimitive(PrimitiveType.Cube)); var transform = gameObject.transform; var elevation = ElevationProvider.GetElevation(point); transform.position = new Vector3((float)point.X, elevation + minHeight, (float)point.Y); // TODO define size transform.localScale = new Vector3(2, 2, 2); var p0 = new Vector2((float)rect.Left, (float)rect.Bottom); var p1 = new Vector2((float)rect.Right, (float)rect.Bottom); var p2 = new Vector2((float)rect.Left, (float)rect.Top); var p3 = new Vector2((float)rect.Right, (float)rect.Top); var mesh = gameObject.GetComponent <MeshFilter>().mesh; // Imagine looking at the front of the cube, the first 4 vertices are arranged like so // 2 --- 3 // | | // | | // 0 --- 1 // then the UV's are mapped as follows // 2 3 0 1 Front // 6 7 10 11 Back // 19 17 16 18 Left // 23 21 20 22 Right // 4 5 8 9 Top // 15 13 12 14 Bottom mesh.uv = new[] { p0, p1, p2, p3, p2, p3, p2, p3, p0, p1, p0, p1, p0, p3, p1, p2, p0, p3, p1, p2, p0, p3, p1, p2 }; gameObject.GetComponent <MeshRenderer>().sharedMaterial = rule.GetMaterial(CustomizationService); gameObjectWrapper.Parent = tile.GameObject; }
/// <inheritdoc /> public override IGameObject BuildArea(Tile tile, Rule rule, Area area) { base.BuildArea(tile, rule, area); if (tile.Registry.Contains(area.Id)) { return(null); } double radius; Vector2d center; CircleUtils.GetCircle(tile.RelativeNullPoint, area.Points, out radius, out center); var elevation = ElevationProvider.GetElevation(center); var height = rule.GetHeight(); var minHeight = rule.GetMinHeight(); var actualHeight = (height - minHeight); var color = rule.GetFillColor(); var gradient = CustomizationService.GetGradient(color); tile.Registry.RegisterGlobal(area.Id); var cylinderGen = new CylinderGenerator() .SetCenter(new Vector3((float)center.X, elevation + minHeight, (float)center.Y)) .SetHeight(actualHeight) .SetMaxSegmentHeight(5f) .SetRadialSegments(7) .SetRadius((float)radius) .SetGradient(gradient); var meshData = new MeshData(MeshDestroyIndex.Default, cylinderGen.CalculateVertexCount()) { GameObject = GameObjectFactory.CreateNew(GetName(area)), MaterialKey = rule.GetMaterialKey() }; cylinderGen.Build(meshData); BuildObject(tile.GameObject, meshData, rule, area); return(meshData.GameObject); }
/// <inheritdoc /> public override IGameObject BuildArea(Tile tile, Rule rule, Area area) { base.BuildArea(tile, rule, area); if (tile.Registry.Contains(area.Id)) { return(null); } tile.Registry.RegisterGlobal(area.Id); double radius; Vector2d center; CircleUtils.GetCircle(tile.RelativeNullPoint, area.Points, out radius, out center); var elevation = ElevationProvider.GetElevation(center); var minHeight = rule.GetMinHeight(); var color = rule.GetFillColor(); var gradient = CustomizationService.GetGradient(color); int recursionLevel = rule.EvaluateDefault("recursion_level", 2); var center3d = new Vector3((float)center.X, elevation + minHeight, (float)center.Y); var sphereGen = new IcoSphereGenerator() .SetCenter(center3d) .SetRadius((float)radius) .SetRecursionLevel(recursionLevel) .SetGradient(gradient); var meshData = new MeshData(new SphereMeshIndex((float)radius, center3d), sphereGen.CalculateVertexCount()); meshData.GameObject = GameObjectFactory.CreateNew(GetName(area)); meshData.MaterialKey = rule.GetMaterialKey(); sphereGen.Build(meshData); BuildObject(tile.GameObject, meshData, rule, area); return(meshData.GameObject); }
private IGameObject BuildBuilding(Tile tile, Rule rule, Model model, List <GeoCoordinate> footPrint) { if (tile.Registry.Contains(model.Id)) { return(null); } var points = ObjectPool.NewList <Vector2d>(); PointUtils.GetClockwisePolygonPoints(tile.RelativeNullPoint, footPrint, points); var minHeight = BuildingRuleExtensions.GetMinHeight(rule); // TODO invent better algorithm var elevation = ElevationProvider.GetElevation(points[0]); var gameObject = BuildGameObject(tile, rule, model, points, elevation, minHeight); ObjectPool.StoreList(points); return(gameObject); }
private void CreateForest(IGameObject parent, Rule rule, Mesh mesh) { var trunkGradientKey = rule.Evaluate <string>("trunk-color"); var foliageGradientKey = rule.Evaluate <string>("foliage-color"); int treeFreq = (int)(1 / rule.EvaluateDefault <float>("tree-freq", 0.1f)); // TODO reuse tree builder? // TODO behaviour should be set somehow var node = new Node(); foreach (var triangle in mesh.Triangles) { // TODO reuse mesh and/or generator? if (triangle.Id % treeFreq != 0) { continue; } var v0 = triangle.GetVertex(0); var v1 = triangle.GetVertex(1); var v2 = triangle.GetVertex(2); var center = new Vector2d((v0.X + v1.X + v2.X) / 3, (v0.Y + v1.Y + v2.Y) / 3); var elevation = ElevationProvider.GetElevation(center); var treeGen = new TreeGenerator() .SetTrunkGradient(CustomizationService.GetGradient(trunkGradientKey)) .SetFoliageGradient(CustomizationService.GetGradient(foliageGradientKey)) .SetPosition(new Vector3((float)center.X, elevation, (float)center.Y)); var meshData = new MeshData(MeshDestroyIndex.Default, treeGen.CalculateVertexCount()); meshData.GameObject = GameObjectFactory.CreateNew("tree"); meshData.MaterialKey = rule.GetMaterialKey(); treeGen.Build(meshData); BuildObject(parent, meshData, rule, node); } }
/// <inheritdoc /> public override IGameObject BuildNode(Tile tile, Rule rule, Node node) { var mapPoint = GeoProjection.ToMapCoordinate(tile.RelativeNullPoint, node.Point); var elevation = ElevationProvider.GetElevation(mapPoint); var trunkGradientKey = rule.Evaluate <string>("trunk-color"); var foliageGradientKey = rule.Evaluate <string>("foliage-color"); var treeGen = new TreeGenerator() .SetTrunkGradient(CustomizationService.GetGradient(trunkGradientKey)) .SetFoliageGradient(CustomizationService.GetGradient(foliageGradientKey)) .SetPosition(new Vector3((float)mapPoint.X, elevation, (float)mapPoint.Y)); var meshData = new MeshData(MeshDestroyIndex.Default, treeGen.CalculateVertexCount()); meshData.GameObject = GameObjectFactory.CreateNew("tree " + node.Id); meshData.MaterialKey = rule.GetMaterialKey(); treeGen.Build(meshData); BuildObject(tile.GameObject, meshData, rule, node); return(meshData.GameObject); }
private void BuildBarrierSegment(SegmentBuilderContext context, Vector3 start, Vector3 end, ref int startIndex) { var distance = Vector3.Distance(start, end); var direction = (end - start).normalized; var stepCount = (int)Math.Ceiling(distance / context.MaxWidth); var width = distance / stepCount; var startEle = ElevationProvider.GetElevation(start.x, start.z); // read context properties var gradient = context.Gradient; var colorNoiseFreq = context.ColorNoiseFreq; var vertCount = context.MeshData.Vertices.Length / 2; var vertices = context.MeshData.Vertices; var triangles = context.MeshData.Triangles; var colors = context.MeshData.Colors; for (int z = 0; z < stepCount; z++) { // get next points end = start + direction * width; var middle = start + direction * (0.5f * width); float endEle = ElevationProvider.GetElevation(end.x, end.z); var p0 = new Vector3(start.x, startEle, start.z); var p1 = new Vector3(end.x, endEle, end.z); var p2 = new Vector3(end.x, endEle + context.Height, end.z); var p3 = new Vector3(start.x, startEle + context.Height, start.z); var pc = new Vector3(middle.x, startEle + context.Height / 2, middle.z); var count = startIndex; #region Vertices vertices[count] = p3; vertices[count + vertCount] = p3; vertices[++count] = p0; vertices[count + vertCount] = p0; vertices[++count] = pc; vertices[count + vertCount] = pc; vertices[++count] = p0; vertices[count + vertCount] = p0; vertices[++count] = p1; vertices[count + vertCount] = p1; vertices[++count] = pc; vertices[count + vertCount] = pc; vertices[++count] = p1; vertices[count + vertCount] = p1; vertices[++count] = p2; vertices[count + vertCount] = p2; vertices[++count] = pc; vertices[count + vertCount] = pc; vertices[++count] = p2; vertices[count + vertCount] = p2; vertices[++count] = p3; vertices[count + vertCount] = p3; vertices[++count] = pc; vertices[count + vertCount] = pc; #endregion #region Triangles // triangles for outer part for (int i = startIndex; i < startIndex + 12; i++) { triangles[i] = i; } var lastIndex = startIndex + vertCount + 12; for (int i = startIndex + vertCount; i < lastIndex; i++) { var rest = i % 3; triangles[i] = rest == 0 ? i : (rest == 1 ? i + 1 : i - 1); } #endregion #region Colors count = startIndex; var color = GetColor(gradient, colorNoiseFreq, p3); colors[count] = color; colors[count + vertCount] = color; colors[++count] = color; colors[count + vertCount] = color; colors[++count] = color; colors[count + vertCount] = color; color = GetColor(gradient, colorNoiseFreq, p0); colors[++count] = color; colors[count + vertCount] = color; colors[++count] = color; colors[count + vertCount] = color; colors[++count] = color; colors[count + vertCount] = color; color = GetColor(gradient, colorNoiseFreq, p1); colors[++count] = color; colors[count + vertCount] = color; colors[++count] = color; colors[count + vertCount] = color; colors[++count] = color; colors[count + vertCount] = color; color = GetColor(gradient, colorNoiseFreq, p2); colors[++count] = color; colors[count + vertCount] = color; colors[++count] = color; colors[count + vertCount] = color; colors[++count] = color; colors[count + vertCount] = color; #endregion // reuse last start = end; startEle = endEle; startIndex += 12; } }