简体   繁体   English

如何为“ perlin”噪声发生器添加比例因子?

[英]How can I add scaling factors to my “perlin” noise generator?

I have a Perlin noise generator which I am attempting to use to create scrolling terrain. 我有一个Perlin噪声发生器,正在尝试使用它来创建滚动地形。

I've got a center terrain, eight terrains of the same side surrounding it (these are working fine) and a second ring of terrains which are three times larger. 我有一个中心地形,围绕它的同一侧有八个地形(它们工作正常),第二个地形环是它的三倍。 For these, I need my noise generator to output noise that is three times "denser", such that I could place a larger terrain over a smaller terrain and, except for the three times larger tiles (and map size), they'd match. 对于这些,我需要我的噪声发生器来输出三倍于“密集器”的噪声,这样我就可以在较小的地形上放置较大的地形,并且除了三倍大的图块(和地图尺寸)外,它们都可以匹配。

I don't want to just generate a larger map; 我不想只是生成一张更大的地图; that would quickly get prohibitive. 很快就会变得令人望而却步。

I do not know what to do; 我不知道该怎么办; the obvious solutions all failed, one way or another. 显而易见的解决方案都以一种或另一种方式失败了。

    /// <summary>
    /// Generates a new perlin map.
    /// </summary>
    /// <param name="xStart">The left coordinate (using 0, 0 as top-left and +, + as down and to the right).</param>
    /// <param name="yStart">The top coordinate (using 0, 0 as top-left and +, + as down and to the right).</param>
    /// <param name="width">The width of the map.</param>
    /// <param name="length">The length of the map.</param>
    /// <param name="persistance">If set, values lower than 1 make the map less noisey; values greater than 1 make the map more noisy.</param>
    /// <param name="fromShift">Low values here provide for a broader "base".</param>
    /// <param name="toShift">High values here provide for more speckled "highlights".</param>
    /// <param name="interpolate">If set to false, the algorithm will not smooth values.</param>
    public double[,] Generate(
        int xStart, int yStart,
        int width, int length,
        double? persistance,
        uint fromShift, uint toShift,
        bool interpolate = true,
    )
    {
        _noiseMap = new double[width, length];
        _workingMap = new double[width + 6, length + 6];
        _smoothedNoise = new double[width + 6, length + 6];
        int ifromShift = -(int)(toShift),
            itoShift = -(int)(fromShift);
        int idiv = 1 + (itoShift - ifromShift);
        double ddiv = 0;
        double amplitude = 0.0;
        if (persistance.HasValue)
            for (int i = ifromShift; i <= itoShift; ++i)
                ddiv += Math.Pow(persistance.Value, i);

        for (int i = ifromShift; i <= itoShift; ++i)
        {
            _frequency = Math.Pow(2, i);
            if (persistance.HasValue) amplitude = Math.Pow(persistance.Value, i);
            int useWidth = (int)(width * _frequency) + 1,
                useLength = (int)(length * _frequency) + 1;
            int useXStart = (int)(xStart * _frequency),
                useYStart = (int)(yStart * _frequency);
            double frequencyXStart = xStart * _frequency - useXStart,
                frequencyYStart = yStart * _frequency - useYStart;

            for (int y = 0; y < useLength + 5; ++y)
                for (int x = 0; x < useWidth + 5; ++x)
                {
                    int genX = ((int)(useXStart) + (int)((x) + 0.5));
                    int genY = ((int)(useYStart) + (int)((y) + 0.5));
                    _workingMap[x, y] = GenerateNoise(genX, genY);
                }

            if (interpolate)
            {
                for (int y = 1; y < length + 4; ++y)
                    for (int x = 1; x < width + 4; ++x)
                    {
                        _smoothedNoise[x, y] = SmoothedNoise(x, y);
                    }

                if (persistance.HasValue)
                    for (int y = 0; y < length; ++y)
                        for (int x = 0; x < width; ++x)
                        {
                            _noiseMap[x, y] += InterpolatedNoise((x * _frequency) + 2 + frequencyXStart, (y * _frequency) + 2 + frequencyYStart) * amplitude;
                            // _noiseMap[x, y] += _workingMap[x, y] * amplitude;
                        }
                else
                    for (int y = 0; y < length; ++y)
                        for (int x = 0; x < width; ++x)
                        {
                            _noiseMap[x, y] += InterpolatedNoise((x * _frequency) + 2 + frequencyXStart, (y * _frequency) + 2 + frequencyYStart) / idiv;
                            // _noiseMap[x, y] += _workingMap[x, y] / idiv;
                        }
            }
            else
                if (persistance.HasValue)
                    for (int y = 0; y < length; ++y)
                        for (int x = 0; x < width; ++x)
                        {
                            _noiseMap[x, y] +=
                                _workingMap[(int)((x * _frequency) + 2 + frequencyXStart), (int)((y * _frequency) + 2 + frequencyYStart)] * amplitude;
                        }
                else
                    for (int y = 0; y < length; ++y)
                        for (int x = 0; x < width; ++x)
                        {
                            _noiseMap[x, y] +=
                                _workingMap[(int)((x * _frequency) + 2 + frequencyXStart), (int)((y * _frequency) + 2 + frequencyYStart)] / idiv;
                        }
        }

        if (persistance.HasValue)
            for (int y = 0; y < length; ++y)
                for (int x = 0; x < width; ++x)
                {
                    _noiseMap[x, y] = _noiseMap[x, y] / ddiv;
                }

        return _noiseMap;
    }

Thanks. 谢谢。

Perlin noise is alot more dense than your samples can be, so the shape of one algorythm is dense for all grids. Perlin噪声比您的样本要密集得多,因此一个算法的形状对于所有网格都是密集的。 if you want extra detail, you have to add an octave or a second pass of noise, in which case the grids wouldnt overlay properly. 如果需要更多细节,则必须添加八度或第二遍噪声,在这种情况下,网格将无法正确覆盖。 so it's a question of choosing a shape and sampling it with different grid densities. 因此,选择一个形状并以不同的网格密度对其进行采样是一个问题。

Just to be clear (to check my understanding of your problem). 只是要清楚(检查我对您的问题的理解)。

You generate a map A with side of size X. This map is surrounded by nine more maps B1...B9, each with side of size X. Now you want maps C1...C2, which will surround maps B1...B9 from the outside. 您生成的地图A的边尺寸为X。此地图被另外九个地图B1 ... B9包围,每个地图的边尺寸为X。现在,您想要的地图C1 ... C2将围绕地图B1...。从外面B9。 Each of these maps will have a side of size 3X, but with only X^2 data points (each data point will be of size 3x3). 这些地图中的每个地图的边长均为3X,但只有X ^ 2个数据点(每个数据点的大小为3x3)。

Right? 对?

Have you tried just interpolating the data with nearest neighbor algorithm? 您是否尝试过使用最近邻居算法对数据进行插值? When any code asks for a data from coordinate X, just round the coordinate to a multiple of three and use it. 当任何代码要求从坐标X获得数据时,只需将坐标四舍五入为3的倍数并使用它即可。 I think this should work. 我认为这应该有效。

Another option would be to use the midpoint displacement algorithm , except you would split the tile into three parts instead of just two in each recursive step. 另一种选择是使用中点位移算法 ,除了您将图块分成三个部分,而不是在每个递归步骤中将其分成两个部分。 This would allow you to stop one round early, which would present you with the result you are looking for: A height map with data points generated only on intersection points of 3x3 grid. 这样一来,您可以提前停一轮,从而向您展示所需的结果:高度图,仅在3x3网格的交点上生成数据点。 Without ever having to touch the remaining points. 无需触摸其余点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM