コード例 #1
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);
        }
コード例 #2
0
        /// <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;
        }