private MultiPlaneMeshIndex GetMeshIndex(out Vector3[] vertices)
        {
            var plane = new List <Vector3>()
            {
                new Vector3(0, 0, 0),
                new Vector3(10, 0, 0),
                new Vector3(10, 0, 10),
                new Vector3(0, 0, 10)
            };
            var center = new Vector3(5, 5, 5);

            vertices = new Vector3[plane.Count * 2 * 3];
            var halfVertCount = vertices.Length / 2;
            var meshIndex     = new MultiPlaneMeshIndex(plane.Count, halfVertCount);

            for (int i = 0; i < plane.Count; i++)
            {
                var start = plane[i];
                var end   = plane[i == plane.Count - 1 ? 0 : i + 1];
                meshIndex.AddPlane(start, end, center, i * 3);
                vertices[i * 3]     = start;
                vertices[i * 3 + 1] = end;
                vertices[i * 3 + 2] = center;

                vertices[halfVertCount + i * 3]     = start;
                vertices[halfVertCount + i * 3 + 1] = end;
                vertices[halfVertCount + i * 3 + 2] = center;
            }
            return(meshIndex);
        }
Esempio n. 2
0
        private void HandleSimpleCase(MeshData meshData, MultiPlaneMeshIndex meshIndex, GradientWrapper gradient,
                                      Skeleton skeleton, EdgeResult edge, float roofOffset, float roofHeight)
        {
            var polygon   = edge.Polygon;
            var distances = skeleton.Distances;

            for (int i = 0; i <= polygon.Count - 2; i += 2)
            {
                var p0 = polygon[i];
                var p1 = polygon[i + 1];
                var p2 = polygon[i + 2 == polygon.Count ? 0 : i + 2];

                var v0 = new Vector3((float)p0.X, distances[p0] > 0 ? roofHeight + roofOffset : roofOffset,
                                     (float)p0.Y);
                var v1 = new Vector3((float)p1.X, distances[p1] > 0 ? roofHeight + roofOffset : roofOffset,
                                     (float)p1.Y);
                var v2 = new Vector3((float)p2.X, distances[p2] > 0 ? roofHeight + roofOffset : roofOffset,
                                     (float)p2.Y);

                if (i == 0)
                {
                    meshIndex.AddPlane(v0, v1, v2, meshData.NextIndex);
                }
                AddTriangle(meshData, gradient, v0, v1, v2);
            }
        }
Esempio n. 3
0
        private MeshData BuildMeshData(WallBuilder emptyWallBuilder, List <Vector2d> footprint,
                                       int vertCount, float elevation, int startIndex, int endIndex)
        {
            var meshIndex = new MultiPlaneMeshIndex(footprint.Count, vertCount);
            var meshData  = new MeshData(meshIndex, vertCount);

            emptyWallBuilder.SetMeshData(meshData);

            for (int i = startIndex; i < endIndex; i++)
            {
                var nextIndex = i == (footprint.Count - 1) ? 0 : i + 1;
                var start     = footprint[i];
                var end       = footprint[nextIndex];

                var startVector      = new Vector3((float)start.X, elevation, (float)start.Y);
                var endVector        = new Vector3((float)end.X, elevation, (float)end.Y);
                var somePointOnPlane = new Vector3((float)end.X, elevation + 10, (float)end.Y);

                meshIndex.AddPlane(startVector, endVector, somePointOnPlane, meshData.NextIndex);
                emptyWallBuilder
                .SetStartIndex(meshData.NextIndex)
                .Build(startVector, endVector);
            }

            return(meshData);
        }
        /// <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);
        }
Esempio n. 5
0
        /// <summary> Builds flat floors. </summary>
        protected List <MeshData> BuildFloors(Building building, int floorCount,
                                              bool lastFloorIsRoof, int extraMeshCount = 0)
        {
            var mesh = CreateMesh(building.Footprint);

            var floorHeight  = building.Height / building.Levels;
            var bottomOffset = building.Elevation + building.MinHeight;

            var vertexPerFloor = mesh.Triangles.Count * 3 * 2;
            int vertexCount    = vertexPerFloor * floorCount;

            int meshCount          = 1;
            int floorsPerIteration = floorCount;
            var twoSizedMeshCount  = vertexCount * 2;

            if (twoSizedMeshCount > Consts.MaxMeshSize)
            {
                Trace.Warn(LogCategory, Strings.MeshHasMaxVertexLimit, building.Id.ToString(),
                           twoSizedMeshCount.ToString());
                meshCount          = (int)Math.Ceiling((double)twoSizedMeshCount / Consts.MaxMeshSize);
                floorsPerIteration = floorCount / meshCount;
            }

            var meshDataList = new List <MeshData>(meshCount + extraMeshCount);

            for (int i = 0; i < meshCount; i++)
            {
                var stepFloorCount = (i != meshCount - 1 || meshCount == 1)
                    ? floorsPerIteration
                    : floorsPerIteration + floorCount % meshCount;

                var stepVertexCount  = vertexPerFloor * stepFloorCount;
                var stepBottomOffset = bottomOffset + i * (floorsPerIteration * floorHeight);

                var meshIndex = new MultiPlaneMeshIndex(stepFloorCount, stepVertexCount);
                var meshData  = new MeshData(meshIndex, stepVertexCount);

                AttachFloors(new RoofContext()
                {
                    Mesh      = mesh,
                    MeshData  = meshData,
                    MeshIndex = meshIndex,

                    Bottom             = stepBottomOffset,
                    FloorCount         = stepFloorCount,
                    FloorHeight        = floorHeight,
                    FloorFrontGradient = CustomizationService.GetGradient(building.FloorFrontColor),
                    FloorBackGradient  = CustomizationService.GetGradient(building.FloorBackColor),

                    IsLastRoof        = i == meshCount - 1 && lastFloorIsRoof,
                    RoofFrontGradient = CustomizationService.GetGradient(building.RoofColor),
                    RoofBackGradient  = CustomizationService.GetGradient(building.RoofColor),
                });

                meshDataList.Add(meshData);
            }

            return(meshDataList);
        }
Esempio n. 6
0
        private void HandleComplexCase(MeshData meshData, MultiPlaneMeshIndex meshIndex, GradientWrapper gradient,
                                       Skeleton skeleton, EdgeResult edge, float roofOffset, float roofHeight)
        {
            var polygon   = edge.Polygon;
            var distances = skeleton.Distances;

            using (var trianglePolygon = new Polygon(polygon.Count, ObjectPool))
            {
                trianglePolygon.AddContour(polygon.Select(p => new Point(p.X, p.Y)).ToList());
                var  mesh         = trianglePolygon.Triangulate();
                bool planeIsAdded = false;
                foreach (var triangle in mesh.Triangles)
                {
                    var p0 = new Vector2d(triangle.vertices[0].X, triangle.vertices[0].Y);
                    var p1 = new Vector2d(triangle.vertices[1].X, triangle.vertices[1].Y);
                    var p2 = new Vector2d(triangle.vertices[2].X, triangle.vertices[2].Y);

                    double y;
                    if (distances.TryGetValue(p0, out y) && y > 0)
                    {
                        y = roofHeight + roofOffset;
                    }
                    else
                    {
                        y = roofOffset;
                    }
                    var v0 = new Vector3((float)p0.X, (float)y, (float)p0.Y);

                    if (distances.TryGetValue(p1, out y) && y > 0)
                    {
                        y = roofHeight + roofOffset;
                    }
                    else
                    {
                        y = roofOffset;
                    }
                    var v1 = new Vector3((float)p1.X, (float)y, (float)p1.Y);

                    if (distances.TryGetValue(p2, out y) && y > 0)
                    {
                        y = roofHeight + roofOffset;
                    }
                    else
                    {
                        y = roofOffset;
                    }
                    var v2 = new Vector3((float)p2.X, (float)y, (float)p2.Y);

                    if (!planeIsAdded)
                    {
                        meshIndex.AddPlane(v0, v1, v2, meshData.NextIndex);
                        planeIsAdded = true;
                    }
                    AddTriangle(meshData, gradient, v0, v1, v2);
                }
            }
        }
        public override List <MeshData> Build(Building building)
        {
            var roofOffset = building.Elevation + building.MinHeight + building.Height;
            var roofHeight = roofOffset + building.RoofHeight;

            // 1. detect the longest segment
            float    length;
            Vector2d longestStart;
            Vector2d longestEnd;

            GetLongestSegment(building.Footprint, out length, out longestStart, out longestEnd);

            // 2. get direction vector
            var ridgeDirection = (new Vector3((float)longestEnd.X, roofOffset, (float)longestEnd.Y) -
                                  new Vector3((float)longestStart.X, roofOffset, (float)longestStart.Y)).normalized;

            // 3. get centroid
            var centroidPoint  = PolygonUtils.GetCentroid(building.Footprint);
            var centroidVector = new Vector3((float)centroidPoint.X, roofHeight, (float)centroidPoint.Y);

            // 4. get something like center line
            Vector3 p1 = centroidVector + length * length * ridgeDirection;
            Vector3 p2 = centroidVector - length * length * ridgeDirection;

            // 5. detect segments which have intesection with center line
            Vector2d first, second;
            int      firstIndex, secondIndex;

            DetectIntersectSegments(building.Footprint, new Vector2d(p1.x, p1.z), new Vector2d(p2.x, p2.z),
                                    out first, out firstIndex, out second, out secondIndex);
            if (firstIndex == -1 || secondIndex == -1)
            {
                Trace.Warn(LogCategory, Strings.RoofGenFailed, Name, building.Id.ToString());
                return(base.Build(building));
            }

            // prepare mesh and its index
            var mesh             = CreateMesh(building.Footprint);
            var floorCount       = building.Levels;
            var floorVertexCount = mesh.Triangles.Count * 3 * 2 * floorCount;
            var roofVertexCount  = (building.Footprint.Count - 1) * 2 * 12;

            var vertexCount = roofVertexCount + floorVertexCount;
            var planeCount  = building.Footprint.Count + floorCount;

            bool limitIsReached = false;

            if (vertexCount * 2 > Consts.MaxMeshSize)
            {
                vertexCount    = roofVertexCount;
                planeCount     = building.Footprint.Count;
                limitIsReached = true;
            }

            var meshIndex = new MultiPlaneMeshIndex(planeCount, vertexCount);
            var meshData  = new MeshData(meshIndex, vertexCount);

            // 6. process all segments and create vertices
            FillMeshData(meshData, CustomizationService.GetGradient(building.RoofColor), roofOffset,
                         roofHeight, building.Footprint, first, firstIndex, second, secondIndex);

            if (!limitIsReached)
            {
                AttachFloors(new RoofContext()
                {
                    Mesh      = mesh,
                    MeshData  = meshData,
                    MeshIndex = meshIndex,

                    Bottom             = building.Elevation + building.MinHeight,
                    FloorCount         = floorCount,
                    FloorHeight        = building.Height / floorCount,
                    FloorFrontGradient = CustomizationService.GetGradient(building.FloorFrontColor),
                    FloorBackGradient  = CustomizationService.GetGradient(building.FloorBackColor),

                    IsLastRoof = false
                });

                return(new List <MeshData>(1)
                {
                    meshData
                });
            }

            var meshDataList = BuildFloors(building, building.Levels, false);

            meshDataList.Add(meshData);
            return(meshDataList);
        }
Esempio n. 8
0
        /// <inheritdoc />
        public override List <MeshData> Build(Building building)
        {
            var roofHeight = building.RoofHeight;
            var roofOffset = building.Elevation + building.MinHeight + building.Height;

            var skeleton        = SkeletonBuilder.Build(building.Footprint);
            var roofVertexCount = 0;

            foreach (var edgeResult in skeleton.Edges)
            {
                roofVertexCount += (edgeResult.Polygon.Count - 2) * 12;
            }

            var mesh             = CreateMesh(building.Footprint);
            var floorCount       = building.Levels;
            var floorVertexCount = mesh.Triangles.Count * 3 * 2 * floorCount;

            var vertexCount = roofVertexCount + floorVertexCount;
            var planeCount  = skeleton.Edges.Count + floorCount;

            bool limitIsReached = false;

            if (vertexCount * 2 > Consts.MaxMeshSize)
            {
                vertexCount    = roofVertexCount;
                planeCount     = building.Footprint.Count;
                limitIsReached = true;
            }

            var      meshIndex = new MultiPlaneMeshIndex(planeCount + floorCount, vertexCount);
            MeshData meshData  = new MeshData(meshIndex, vertexCount);

            try
            {
                var roofGradient = CustomizationService.GetGradient(building.RoofColor);
                foreach (var edge in skeleton.Edges)
                {
                    if (edge.Polygon.Count < 5)
                    {
                        HandleSimpleCase(meshData, meshIndex, roofGradient, skeleton, edge, roofOffset, roofHeight);
                    }
                    else
                    {
                        HandleComplexCase(meshData, meshIndex, roofGradient, skeleton, edge, roofOffset, roofHeight);
                    }
                }

                if (!limitIsReached)
                {
                    // attach floors
                    AttachFloors(new RoofContext()
                    {
                        Mesh      = mesh,
                        MeshData  = meshData,
                        MeshIndex = meshIndex,

                        Bottom             = building.Elevation + building.MinHeight,
                        FloorCount         = floorCount,
                        FloorHeight        = building.Height / floorCount,
                        FloorFrontGradient = CustomizationService.GetGradient(building.FloorFrontColor),
                        FloorBackGradient  = CustomizationService.GetGradient(building.FloorBackColor),

                        IsLastRoof = false
                    });
                    return(new List <MeshData>(1)
                    {
                        meshData
                    });
                }
                var meshDataList = BuildFloors(building, building.Levels, false);
                meshDataList.Add(meshData);
                return(meshDataList);
            }
            catch
            {
                // NOTE straight skeleton may fail on some footprints.
                Trace.Warn("building.roof", Strings.RoofGenFailed, Name, building.Id.ToString());
                return(base.Build(building));
            }
        }
Esempio n. 9
0
        /// <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);
        }
Esempio n. 10
0
        /// <inheritdoc />
        public override List <MeshData> Build(Building building)
        {
            var center     = PolygonUtils.GetCentroid(building.Footprint);
            var roofOffset = building.Elevation + building.MinHeight + building.Height;
            var footprint  = building.Footprint;
            var roofHeight = building.RoofHeight;
            var floorCount = building.Levels;

            var length           = footprint.Count;
            var mesh             = CreateMesh(footprint);
            var roofVertexCount  = 12 * length;
            var floorVertexCount = mesh.Triangles.Count * 3 * 2 * floorCount;

            var vertexCount = roofVertexCount + floorVertexCount;
            var planeCount  = building.Footprint.Count + floorCount;

            bool limitIsReached = false;

            if (vertexCount * 2 > Consts.MaxMeshSize)
            {
                vertexCount    = roofVertexCount;
                planeCount     = building.Footprint.Count;
                limitIsReached = true;
            }

            var meshIndex = new MultiPlaneMeshIndex(planeCount, vertexCount);
            var meshData  = new MeshData(meshIndex, vertexCount);

            var roofGradient = CustomizationService.GetGradient(building.RoofColor);

            for (int i = 0; i < length; i++)
            {
                var nextIndex = i == (length - 1) ? 0 : i + 1;

                var v0 = new Vector3((float)footprint[i].X, roofOffset, (float)footprint[i].Y);
                var v1 = new Vector3((float)center.X, roofOffset + roofHeight, (float)center.Y);
                var v2 = new Vector3((float)footprint[nextIndex].X, roofOffset, (float)footprint[nextIndex].Y);

                var v01 = Vector3Utils.GetIntermediatePoint(v0, v1);
                var v12 = Vector3Utils.GetIntermediatePoint(v1, v2);
                var v02 = Vector3Utils.GetIntermediatePoint(v0, v2);

                meshIndex.AddPlane(v0, v1, v2, meshData.NextIndex);

                var color = GetColor(roofGradient, v0);
                meshData.AddTriangle(v0, v01, v02, color, color);

                color = GetColor(roofGradient, v01);
                meshData.AddTriangle(v02, v01, v12, color, color);

                color = GetColor(roofGradient, v02);
                meshData.AddTriangle(v2, v02, v12, color, color);

                color = GetColor(roofGradient, v01);
                meshData.AddTriangle(v01, v1, v12, color, color);
            }

            if (!limitIsReached)
            {
                AttachFloors(new RoofContext()
                {
                    Mesh      = mesh,
                    MeshData  = meshData,
                    MeshIndex = meshIndex,

                    Bottom             = building.Elevation + building.MinHeight,
                    FloorCount         = floorCount,
                    FloorHeight        = building.Height / floorCount,
                    FloorFrontGradient = CustomizationService.GetGradient(building.FloorFrontColor),
                    FloorBackGradient  = CustomizationService.GetGradient(building.FloorBackColor),

                    IsLastRoof = false,
                });

                return(new List <MeshData>(1)
                {
                    meshData
                });
            }

            var meshDataList = BuildFloors(building, building.Levels, false);

            meshDataList.Add(meshData);
            return(meshDataList);
        }
Esempio n. 11
0
        /// <inheritdoc />
        public override List <MeshData> Build(Building building)
        {
            Vector2d center;
            double   radius;

            CircleUtils.GetCircle(building.Footprint, out radius, out center);

            var center3d = new Vector3((float)center.X,
                                       building.Elevation + building.MinHeight + building.Height,
                                       (float)center.Y);

            var sphereGen = new IcoSphereGenerator()
                            .SetCenter(center3d)
                            .SetRadius((float)radius)
                            .SetRecursionLevel(2)
                            .IsSemiphere(true)
                            .SetGradient(CustomizationService.GetGradient(building.RoofColor));

            var mesh = CreateMesh(building.Footprint);

            var        floorCount       = building.Levels;
            var        floorVertexCount = mesh.Triangles.Count * 3 * 2 * floorCount;
            IMeshIndex floorMeshIndex   = new MultiPlaneMeshIndex(building.Levels, floorVertexCount);

            var roofVertexCount = sphereGen.CalculateVertexCount();

            var vertexCount = roofVertexCount + floorVertexCount;

            bool limitIsReached = false;

            if (vertexCount * 2 > Consts.MaxMeshSize)
            {
                vertexCount    = roofVertexCount;
                limitIsReached = true;
                floorMeshIndex = DummyMeshIndex.Default;
            }

            var meshIndex = new CompositeMeshIndex(2)
                            .AddMeshIndex(new SphereMeshIndex((float)radius, center3d))
                            .AddMeshIndex(floorMeshIndex);
            var meshData = new MeshData(meshIndex, vertexCount);

            // attach roof
            sphereGen.Build(meshData);

            if (!limitIsReached)
            {
                // attach floors
                AttachFloors(new RoofContext()
                {
                    Mesh      = mesh,
                    MeshData  = meshData,
                    MeshIndex = (MultiPlaneMeshIndex)floorMeshIndex,

                    Bottom             = building.Elevation + building.MinHeight,
                    FloorCount         = floorCount,
                    FloorHeight        = building.Height / floorCount,
                    FloorFrontGradient = CustomizationService.GetGradient(building.FloorFrontColor),
                    FloorBackGradient  = CustomizationService.GetGradient(building.FloorBackColor),

                    IsLastRoof = false
                });

                return(new List <MeshData>(1)
                {
                    meshData
                });
            }

            var meshDataList = BuildFloors(building, building.Levels, false);

            meshDataList.Add(meshData);
            return(meshDataList);
        }