/// <inheritdoc /> public override List <MeshData> Build(Building building) { var random = new System.Random((int)building.Id); var footprint = building.Footprint; var roofOffset = building.Elevation + building.MinHeight + building.Height; var roofHeight = roofOffset + building.RoofHeight; var offset = new ClipperOffset(); offset.AddPath(footprint.Select(p => new IntPoint(p.X * Scale, p.Y * Scale)).ToList(), JoinType.jtMiter, EndType.etClosedPolygon); var result = new List <List <IntPoint> >(); offset.Execute(ref result, random.NextFloat(1, 3) * -Scale); if (result.Count != 1 || result[0].Count != footprint.Count) { Trace.Warn(LogCategory, Strings.RoofGenFailed, Name, building.Id.ToString()); return(base.Build(building)); } var topVertices = ObjectPool.NewList <Vector2d>(footprint.Count); double scale = Scale; foreach (var intPoint in result[0]) { topVertices.Add(new Vector2d(intPoint.X / scale, intPoint.Y / scale)); } // NOTE need reverse vertices topVertices.Reverse(); var floorCount = building.Levels; var topMesh = CreateMesh(topVertices); var floorMesh = CreateMesh(footprint); var roofVertexCount = topMesh.Triangles.Count * 3 * 2 + footprint.Count * 2 * 12; var floorVertexCount = floorMesh.Triangles.Count * 3 * 2 * floorCount; var vertexCount = roofVertexCount + floorVertexCount; var planeCount = footprint.Count + floorCount + 1; bool limitIsReached = false; if (vertexCount * 2 > Consts.MaxMeshSize) { vertexCount = roofVertexCount; planeCount = building.Footprint.Count + 1; limitIsReached = true; } var meshIndex = new MultiPlaneMeshIndex(planeCount, vertexCount); var meshData = new MeshData(meshIndex, vertexCount); var roofGradient = CustomizationService.GetGradient(building.RoofColor); int index = FindStartIndex(topVertices[0], footprint); for (int i = 0; i < topVertices.Count; i++) { var top = topVertices[i]; var bottom = footprint[(index + i) % footprint.Count]; var nextTop = topVertices[(i + 1) % topVertices.Count]; var nextBottom = footprint[(index + i + 1) % footprint.Count]; var v0 = new Vector3((float)bottom.X, roofOffset, (float)bottom.Y); var v1 = new Vector3((float)nextBottom.X, roofOffset, (float)nextBottom.Y); var v2 = new Vector3((float)nextTop.X, roofHeight, (float)nextTop.Y); var v3 = new Vector3((float)top.X, roofHeight, (float)top.Y); meshIndex.AddPlane(v0, v1, v2, meshData.NextIndex); AddTriangle(meshData, roofGradient, v0, v2, v3); AddTriangle(meshData, roofGradient, v2, v0, v1); } ObjectPool.StoreList(topVertices); // Attach top reusing roof context object var context = new RoofContext() { Mesh = topMesh, MeshData = meshData, MeshIndex = meshIndex, Bottom = roofHeight, FloorCount = 1, FloorHeight = building.Height / floorCount, FloorFrontGradient = CustomizationService.GetGradient(building.FloorFrontColor), FloorBackGradient = CustomizationService.GetGradient(building.FloorBackColor), IsLastRoof = true, RoofFrontGradient = roofGradient, RoofBackGradient = roofGradient }; AttachFloors(context); if (!limitIsReached) { context.Mesh = floorMesh; context.MeshData = meshData; context.Bottom = building.Elevation + building.MinHeight; context.FloorCount = floorCount; context.IsLastRoof = false; AttachFloors(context); return(new List <MeshData>(1) { meshData }); } var meshDataList = BuildFloors(building, building.Levels, false); meshDataList.Add(meshData); return(meshDataList); }
/// <summary> Builds floor. </summary> protected void AttachFloors(RoofContext context) { var triCount = context.Mesh.Triangles.Count; var vertPerFloor = triCount * 3; var halfVertCount = context.MeshData.Vertices.Length / 2; var vertices = context.MeshData.Vertices; var triangles = context.MeshData.Triangles; var colors = context.MeshData.Colors; int lastFloorIndex = context.IsLastRoof ? context.FloorCount - 1 : -1; var startIndex = context.MeshData.NextIndex; int index = 0; foreach (var triangle in context.Mesh.Triangles) { var backSideIndex = index; for (int i = 0; i < 3; i++) { var p = triangle.GetVertex(2 - i); var v = new Vector3((float)p.X, 0, (float)p.Y); float eleNoise = p.Type == VertexType.FreeVertex ? Noise.Perlin3D(v, 0.1f) : 0f; var frontColor = GetColor(context.FloorFrontGradient, v); var backColor = GetColor(context.FloorBackGradient, v); // iterate over floors and set up the corresponding vertex for (int k = 0; k < context.FloorCount; k++) { var floorOffsetIndex = startIndex + vertPerFloor * k; var currentIndex = floorOffsetIndex + index; v = new Vector3(v.x, context.Bottom + context.FloorHeight * k + eleNoise, v.z); if (k == lastFloorIndex) { frontColor = GetColor(context.RoofFrontGradient, v); backColor = GetColor(context.RoofBackGradient, v); } vertices[currentIndex] = v; triangles[currentIndex] = currentIndex; colors[currentIndex] = frontColor; vertices[halfVertCount + currentIndex] = v; triangles[halfVertCount + currentIndex] = halfVertCount + floorOffsetIndex + backSideIndex + 2 - i; colors[halfVertCount + currentIndex] = backColor; } index++; } } // setup mesh index for (int i = 0; i < context.FloorCount; i++) { var triIndex = startIndex + vertPerFloor * i; var v0 = vertices[triIndex]; var v1 = vertices[triIndex + 1]; var v2 = vertices[triIndex + 2]; context.MeshIndex.AddPlane(v0, v1, v2, triIndex); } context.MeshData.NextIndex += vertPerFloor * context.FloorCount * 2; }