/// <summary>
        /// Generates a value-coherent-noise value from the coordinates of a
        /// three-dimensional input value.
        /// </summary>
        /// <param name="x">The x coordinate of the input value.</param>
        /// <param name="y">The y coordinate of the input value.</param>
        /// <param name="z">The z coordinate of the input value.</param>
        /// <param name="seed">The random number seed.</param>
        /// <param name="noiseQuality">The quality of the coherent-noise.</param>
        /// <returns>The generated value-coherent-noise value.</returns>
        /// <remarks>
        /// The return value ranges from -1.0 to +1.0.
        ///
        /// For an explanation of the difference between gradient noise and
        /// value noise, see the comments for the <see cref="GradientNoise3D"/> function.
        /// </remarks>
        public static double ValueCoherentNoise3D(double x, double y, double z, int seed = 0, NoiseQuality noiseQuality = NoiseQuality.Standard)
        {
            // Create a unit-length cube aligned along an integer boundary.  This cube
            // surrounds the input point.
            var x0 = x > 0.0 ? (int)x : (int)x - 1;
            var x1 = x0 + 1;
            var y0 = y > 0.0 ? (int)y : (int)y - 1;
            var y1 = y0 + 1;
            var z0 = z > 0.0 ? (int)z : (int)z - 1;
            var z1 = z0 + 1;

            // Map the difference between the coordinates of the input value and the
            // coordinates of the cube's outer-lower-left vertex onto an S-curve.
            double xs = 0, ys = 0, zs = 0;

            switch (noiseQuality)
            {
            case NoiseQuality.Fast:
                xs = x - x0;
                ys = y - y0;
                zs = z - z0;
                break;

            case NoiseQuality.Standard:
                xs = NoiseMath.SCurve3(x - x0);
                ys = NoiseMath.SCurve3(y - y0);
                zs = NoiseMath.SCurve3(z - z0);
                break;

            case NoiseQuality.Best:
                xs = NoiseMath.SCurve5(x - x0);
                ys = NoiseMath.SCurve5(y - y0);
                zs = NoiseMath.SCurve5(z - z0);
                break;
            }

            // Now calculate the noise values at each vertex of the cube.  To generate
            // the coherent-noise value at the input point, interpolate these eight
            // noise values using the S-curve value as the interpolant (trilinear
            // interpolation.)
            double n0, n1, ix0, ix1, iy0, iy1;

            n0  = ValueNoise3D(x0, y0, z0, seed);
            n1  = ValueNoise3D(x1, y0, z0, seed);
            ix0 = NoiseMath.Linear(n0, n1, xs);
            n0  = ValueNoise3D(x0, y1, z0, seed);
            n1  = ValueNoise3D(x1, y1, z0, seed);
            ix1 = NoiseMath.Linear(n0, n1, xs);
            iy0 = NoiseMath.Linear(ix0, ix1, ys);
            n0  = ValueNoise3D(x0, y0, z1, seed);
            n1  = ValueNoise3D(x1, y0, z1, seed);
            ix0 = NoiseMath.Linear(n0, n1, xs);
            n0  = ValueNoise3D(x0, y1, z1, seed);
            n1  = ValueNoise3D(x1, y1, z1, seed);
            ix1 = NoiseMath.Linear(n0, n1, xs);
            iy1 = NoiseMath.Linear(ix0, ix1, ys);

            return(NoiseMath.Linear(iy0, iy1, zs));
        }
Beispiel #2
0
        /// <summary>
        /// Create a new NoiseCube from the given source NoiseCube using trilinear filtering.
        ///
        /// When the sample is outside the source BorderValue is used by default. If <see cref="clamp"/>/>
        /// is set clamping is used instead.
        /// </summary>
        /// <param name="src">The source NoiseCube</param>
        /// <param name="width">Width of the new NoiseCube</param>
        /// <param name="height">Height of the new NoiseCube</param>
        /// <param name="depth">Depth of the new NoiseCube</param>
        /// <param name="clamp">Use clamping when the sample is outside the source NoiseCube</param>
        /// <returns>The new NoiseCube</returns>
        public static NoiseCube TrilinearFilter(NoiseCube src, int width, int height, int depth, bool clamp = false)
        {
            var dest = new NoiseCube(width, height, depth);

            float xratio = (float)src.Width / dest.Width;
            float yratio = (float)src.Height / dest.Height;
            float zratio = (float)src.Depth / dest.Depth;

            Parallel.For(0, dest.Depth, z =>
            {
                for (int y = 0; y < dest.Height; ++y)
                {
                    for (int x = 0; x < dest.Width; ++x)
                    {
                        float u = (x + 0.5f) * xratio - 0.5f;
                        float v = (y + 0.5f) * yratio - 0.5f;
                        float w = (z + 0.5f) * zratio - 0.5f;

                        int x0 = NoiseMath.FastFloor(u);
                        int y0 = NoiseMath.FastFloor(v);
                        int z0 = NoiseMath.FastFloor(w);
                        int x1 = x0 + 1;
                        int y1 = y0 + 1;
                        int z1 = z0 + 1;

                        float xf = u - x0;
                        float yf = v - y0;
                        float zf = w - z0;

                        if (clamp)
                        {
                            x0 = NoiseMath.Clamp(x0, 0, src.Width - 1);
                            x1 = NoiseMath.Clamp(x1, 0, src.Width - 1);
                            y0 = NoiseMath.Clamp(y0, 0, src.Height - 1);
                            y1 = NoiseMath.Clamp(y1, 0, src.Height - 1);
                            z0 = NoiseMath.Clamp(z0, 0, src.Depth - 1);
                            z1 = NoiseMath.Clamp(z1, 0, src.Depth - 1);
                        }

                        float c000 = src.GetValue(x0, y0, z0);
                        float c001 = src.GetValue(x0, y0, z1);
                        float c010 = src.GetValue(x0, y1, z0);
                        float c011 = src.GetValue(x0, y1, z1);
                        float c100 = src.GetValue(x1, y0, z0);
                        float c101 = src.GetValue(x1, y0, z1);
                        float c110 = src.GetValue(x1, y1, z0);
                        float c111 = src.GetValue(x1, y1, z1);

                        float val = NoiseMath.Trilinear(xf, yf, zf,
                                                        c000, c001, c010, c011, c100, c101, c110, c111);

                        dest.SetValue(x, y, z, val);
                    }
                }
            });

            return(dest);
        }
Beispiel #3
0
        /// <summary>
        /// Create a new NoiseMap from the given source NoiseMap using bilinear filtering.
        ///
        /// When the sample is outside the source BorderValue is used by default. If <see cref="clamp"/>/>
        /// is set clamping is used instead.
        /// </summary>
        /// <param name="src">The source NoiseMap</param>
        /// <param name="width">Width of the new NoiseMap</param>
        /// <param name="height">Height of the new NoiseMap</param>
        /// <param name="clamp">Use clamping when the sample is outside the source NoiseMap</param>
        /// <returns>The new NoiseMap</returns>
        public static NoiseMap BilinearFilter(NoiseMap src, int width, int height, bool clamp = false)
        {
            var dest = new NoiseMap(width, height);

            var xratio = (float)src.Width / dest.Width;
            var yratio = (float)src.Height / dest.Height;

            Parallel.For(0, dest.Height, y =>
            {
                for (var x = 0; x < dest.Width; ++x)
                {
                    var u = (x + 0.5f) * xratio - 0.5f;
                    var v = (y + 0.5f) * yratio - 0.5f;

                    var x0 = NoiseMath.FastFloor(u);
                    var y0 = NoiseMath.FastFloor(v);
                    var x1 = x0 + 1;
                    var y1 = y0 + 1;

                    var xf = u - x0;
                    var yf = v - y0;

                    if (clamp)
                    {
                        x0 = NoiseMath.Clamp(x0, 0, src.Width - 1);
                        x1 = NoiseMath.Clamp(x1, 0, src.Width - 1);
                        y0 = NoiseMath.Clamp(y0, 0, src.Height - 1);
                        y1 = NoiseMath.Clamp(y1, 0, src.Height - 1);
                    }

                    var c00 = src.GetValue(x0, y0);
                    var c01 = src.GetValue(x0, y1);
                    var c10 = src.GetValue(x1, y0);
                    var c11 = src.GetValue(x1, y1);

                    var val = NoiseMath.Bilinear(xf, yf, c00, c01, c10, c11);

                    dest.SetValue(x, y, val);
                }
            });

            return(dest);
        }