示例#1
0
文件: HeightMap.cs 项目: cg123/xenko
        /// <summary>
        /// Creates an height map using the Fault Formation algorithm.
        /// Produces smooth terrain by adding a random line to a blank height field, and add random height to one of the two sides.
        /// </summary>
        /// <param name="size">Size of square HeightData to be created</param>
        /// <param name="numberIteration">The number of iteration of the algorithm. More iteration yields more spaces</param>
        /// <param name="minHeight">Min value of height produced from the algorithm</param>
        /// <param name="maxHeight">Max value of height produced from the algorithm</param>
        /// <param name="scaleHeight"></param>
        /// <param name="filter"></param>
        /// <returns>HeightData created with Fault Formation algorithm that has "size" of size</returns>
        public static HeightMap GenerateFaultFormation(int size, int numberIteration, float minHeight, float maxHeight, float scaleHeight, float filter)
        {
            var heightMap = new HeightMap(size, scaleHeight);

            var random = new Random();

            for (var i = 0; i < numberIteration; ++i)
            {
                // Calculate height for this iteration
                var height = maxHeight - (maxHeight - minHeight) * i / numberIteration;
                var currentPassHeight = height * ((float)random.NextDouble() - 0.1f);

                // Find the line mark a half space for this iteration
                var point1 = new Point(random.Next(size), random.Next(size));
                var point2 = new Point(random.Next(size), random.Next(size));

                var halfSpaceLineVector = new Vector2(point2.X - point1.X, point2.Y - point1.Y);

                for (var iX = 0; iX < size; ++iX)
                {
                    for (var iZ = 0; iZ < size; ++iZ)
                    {
                        var currentPointLine = new Vector2(iX - point1.X, iZ - point1.Y);

                        float sign;
                        Vector2.Dot(ref halfSpaceLineVector, ref currentPointLine, out sign);

                        if (sign > 0) heightMap[iX, iZ] += currentPassHeight;
                    }
                }

                heightMap.FilterHeightField(filter);
            }

            heightMap.NormalizeHeightMap();
            heightMap.CalculateMedian();

            return heightMap;
        }
        private static void NormalizeHeightMap(HeightMap heightMap)
        {
            var maxHeight = float.MinValue;
            var minHeight = float.MaxValue;

            for (var i = 0; i < heightMap.DataSize; ++i)
            {
                if (maxHeight < heightMap[i]) maxHeight = heightMap[i];
                if (minHeight > heightMap[i]) minHeight = heightMap[i];
            }

            maxHeight -= minHeight;

            for (var i = 0; i < heightMap.DataSize; ++i)
                heightMap[i] = (heightMap[i] - minHeight) / maxHeight;
        }
        private static void FilterHeightField(HeightMap data, float filter)
        {
            var size = data.Size;
            // Erode left to right
            for (var i = 0; i < size; i++)
                FilterHeightBand(data, size * i, 1, size, filter);

            //erode right to left
            for (var i = 0; i < size; i++)
                FilterHeightBand(data, size * i + size - 1, -1, size, filter);

            //erode top to bottom
            for (var i = 0; i < data.Size; i++)
                FilterHeightBand(data, i, size, size, filter);

            //erode from bottom to top
            for (var i = 0; i < data.Size; i++)
                FilterHeightBand(data, size * (size - 1) + i, -size, size, filter);
        }
        /// <summary>
        /// Filters HeightData using band-based filter. by "Jason Shankel"
        /// It simulates terrain erosion.
        /// Throws an ArgumentOutOfRangeException if heightData is empty. 
        /// </summary>
        /// <param name="heightData">In: Already created HeightData, Out: Smoothed HeightData</param>
        /// <param name="startIndex"></param>
        /// <param name="stride"></param>
        /// <param name="count"></param>
        /// <param name="filter"></param>
        public static void FilterHeightBand(HeightMap heightData, int startIndex, int stride, int count, float filter)
        {
            var v = heightData[startIndex];
            var j = stride;

            //go through the height band and apply the erosion filter
            for (var i = 0; i < count - 1; ++i)
            {
                heightData[startIndex + j] = filter * v + (1 - filter) * heightData[startIndex + j];

                v = heightData[startIndex + j];
                j += stride;
            }
        }
示例#5
0
        /// <summary>
        /// Gets a normal vector for a given x, z coordinate and the corresponding heightmap
        /// </summary>
        /// <param name="heightMap"></param>
        /// <param name="x"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        private static Vector4 GetNormalVector(HeightMap heightMap, int x, int z)
        {
            var currentP = new Vector3(x, heightMap.GetHeight(x, z), z);
            Vector3 p1;
            Vector3 p2;

            if (x == heightMap.Size - 1 && z == heightMap.Size - 1) // Bottom right pixel
            {
                p1 = new Vector3(x, heightMap.GetHeight(x, z - 1), z - 1);
                p2 = new Vector3(x - 1, heightMap.GetHeight(x - 1, z), z);
            }
            else if (x == heightMap.Size - 1) // Right border
            {
                p1 = new Vector3(x - 1, heightMap.GetHeight(x - 1, z), z);
                p2 = new Vector3(x, heightMap.GetHeight(x, z + 1), z + 1);
            }
            else if (z == heightMap.Size - 1) // Bottom border
            {
                p1 = new Vector3(x + 1, heightMap.GetHeight(x + 1, z), z);
                p2 = new Vector3(x, heightMap.GetHeight(x, z - 1), z - 1);
            }
            else // The rest of pixels
            {
                p1 = new Vector3(x, heightMap.GetHeight(x, z + 1), z + 1);
                p2 = new Vector3(x + 1, heightMap.GetHeight(x + 1, z), z);
            }
            return new Vector4(Vector3.Normalize(Vector3.Cross(p1 - currentP, p2 - currentP)), 1);
        }
示例#6
0
        /// <summary>
        /// Initializes Vertex buffer data by a given height map
        /// </summary>
        /// <param name="heightMap"></param>
        /// <param name="vertexBuffer"></param>
        private static unsafe void SetVertexDataFromHeightMap(HeightMap heightMap, IntPtr vertexBuffer)
        {
            var vb = (VertexNormalTexture*)vertexBuffer;

            var halfSize = heightMap.Size * 0.5f;

            for (var iZ = 0; iZ < heightMap.Size; ++iZ)
                for (var iX = 0; iX < heightMap.Size; ++iX)
                {
                    vb[iZ * heightMap.Size + iX] = new VertexNormalTexture
                    {
                        Position = new Vector4(iX - halfSize, heightMap.GetHeight(iX, iZ), -iZ + halfSize, 1),
                        Normal = GetNormalVector(heightMap, iX, iZ),
                        TextureCoordinate = new Vector2((float)iX / heightMap.Size, (float)iZ / heightMap.Size)
                    };
                }
        }
示例#7
0
        /// <summary>
        /// Initializes Vertex and Index buffers with a given height map
        /// </summary>
        /// <param name="heightMap"></param>
        private void InitializeBuffersFromTerrain(HeightMap heightMap)
        {
            var commandList = Game.GraphicsContext.CommandList;

            // Set data in VertexBuffer
            var mappedSubResource = commandList.MapSubresource(terrainVertexBuffer, 0, MapMode.WriteDiscard);
            SetVertexDataFromHeightMap(heightMap, mappedSubResource.DataBox.DataPointer);
            commandList.UnmapSubresource(mappedSubResource);

            // Set data in IndexBuffer
            mappedSubResource = commandList.MapSubresource(terrainIndexBuffer, 0, MapMode.WriteDiscard);
            var elementCount = SetIndexDataForTerrain(heightMap.Size, mappedSubResource.DataBox.DataPointer);
            commandList.UnmapSubresource(mappedSubResource);

            terrainMesh.Draw.DrawCount = elementCount;
        }