Perlin噪音的输出范围 [英] Output range of Perlin noise

查看:171
本文介绍了Perlin噪音的输出范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在调查一些相干噪声的实现(我知道有库,但这主要是为了我自己的启发和好奇心)以及如何使用它,并且我有一个问题与原始Perlin噪音的事情。

I'm investigating a few of the various implementations for coherent noise (I know there are libraries, but this is mostly for my own edification and curiosity) and how you can use it, and there's one problem I have with the original Perlin noise thing.

根据这个经常链接的数学常见问题解答,输出范围介于 -1 和<$ c $之间c> 1 ,但我不明白该值是如何在该范围内。

According to this frequently linked Math FAQ, the output range will be between -1 and 1, but I don't understand how the value gets to be in that range.

据我了解,算法基本上是这样的:每个网格点都有一个相关的随机梯度向量,长度 1 。然后,对于每个点,对于所有四个周围网格点,您计算随机梯度的点积和从该网格点开始的矢量。然后使用花式缓动曲线和线性插值将其降低到一个值。

As I understand it, the algorithm is basically this: each grid point has an associated random gradient vector of length 1. Then, for each point, for all four surrounding grid points, you calculate the dot product of the random gradient and the vector going from that grid-point. Then you use a fancy ease curve and linear interpolation to get that down to one value.

但是,这是我的问题:这些点积有时会超出 [ - 1,1] ,并且由于你最终在点积之间进行线性插值,这并不意味着最终值有时会超出 [ - 1,1] <的范围/ code>?

But, here's my problem: these dot-products are, occasionally, going to be outside the range [-1, 1], and since you do the linear interpolation ultimately between the dot products, doesn't that mean that the final value will, on occasion, be outside the range of [-1, 1]?

例如,假设其中一个随机向量是(sqrt(2)/ 2,sqrt( 2)/ 2)(长度为1)和(0.8,0.8)(单位为平方),你得到大致 1.131 的结果。如果在线性插值中使用该值,则生成的值完全有可能大于 1 。事实上,通过我的直接实施,这种情况经常发生。

Say, for instance, that one of the random vectors is (sqrt(2)/2, sqrt(2)/2) (which has a length of 1) and (0.8, 0.8) (which is in the unit square), you get a result of roughly 1.131. If that value is used in the linear interpolation, it's entirely possible that the value generated will be greater than 1. And, indeed, with my straight-forward implementation, that happens quite frequently.

我在这里遗漏了什么吗?

Am I missing something here?

作为参考,这是我的Java代码。 Vec 是一个简单的类来进行简单的2d向量运算, fade()是缓动曲线, lerp()是线性插值, gradient(x,y)为您提供该网格点的渐变为 VEC gridSize 变量为您提供网格的大小(以像素为单位):

For reference, here's my code in Java. Vec is a simple class to do simple 2d vector arithmetic, fade() is the ease curve, lerp() is linear interpolation, and gradient(x, y) gives you the gradient for that grid-point as a Vec. The gridSize variable gives you the size of the grid in pixels (it has type double):

public double getPoint(int x, int y) {
    Vec p = new Vec(x / gridSize, y / gridSize);
    Vec d = new Vec(Math.floor(p.x), Math.floor(p.y));


    int x0 = (int)d.x,
        y0 = (int)d.x;


    double d00 = gradient(x0    , y0    ).dot(p.sub(x0    , y0    )),
           d01 = gradient(x0    , y0 + 1).dot(p.sub(x0    , y0 + 1)),
           d10 = gradient(x0 + 1, y0    ).dot(p.sub(x0 + 1, y0    )),
           d11 = gradient(x0 + 1, y0 + 1).dot(p.sub(x0 + 1, y0 + 1));

    double fadeX = fade(p.x - d.x),
           fadeY = fade(p.y - d.y);

    double i1 = lerp(fadeX, d00, d10),
           i2 = lerp(fadeX, d01, d11);

    return lerp(fadeY, i1, i2);
}

编辑:这是生成随机渐变的代码:

here's the code for generating the random gradients:

double theta = gen.nextDouble() * 2 * Math.PI; 
gradients[i] = new Vec(Math.cos(theta), Math.sin(theta));

其中 gen java.util.Random中

推荐答案

你有 y0 =(int)dx; ,但是你意味着 dy 。这肯定会影响您的输出范围,这也是您看到这些大部分超出范围的原因。

You have y0 = (int)d.x;, but you mean d.y. This will most certainly affect your output range, and is the reason you are seeing such largely out-of-range values.

也就是说,Perlin噪声的输出范围实际上 [ - 1,1] 。虽然我自己也不太确定数学(我必须变老),但这个相当冗长的讨论认为实际范围是 [ - sqrt(n)/ 2,sqrt(n)/ 2] ,其中 n 是维度(在您的情况下为2)。因此,2D Perlin噪声函数的输出范围应为 [ - 0.707,0.707] 。这在某种程度上与 d 和插值参数都是 p 的函数有关。如果您仔细阅读该讨论,您可能会找到您正在寻找的确切解释(特别是发布#7

That said, the output range of Perlin noise is not actually [-1, 1]. While I'm not quite sure of the math myself (I must be getting old), this rather lengthy discussion works out that the actual range is [-sqrt(n)/2, sqrt(n)/2], where n is the dimensionality (2 in your case). So the output range of your 2D Perlin noise function should be [-0.707, 0.707]. This is somehow related to the fact that both d and the interpolation parameters are a function of p. If you read through that discussion, you may find the precise explanation you are looking for (particularly, post #7).

我正在使用以下程序测试您的实现(我一起入侵了从你的例子中,原谅奇怪的使用 gridCells gridSize ):

I am testing your implementation using the following program (which I hacked together from your example, so pardon the weird use of gridCells and gridSize):

import java.util.Random;


public class Perlin {

    static final int gridSize = 200;
    static final int gridCells = 20;
    static final Vec[][] gradients = new Vec[gridCells + 1][gridCells + 1];

    static void initializeGradient () {
        Random rand = new Random();
        for (int r = 0; r < gridCells + 1; ++ r) {
            for (int c = 0; c < gridCells + 1; ++ c) {
                double theta = rand.nextFloat() * Math.PI;
                gradients[c][r] = new Vec(Math.cos(theta), Math.sin(theta));                
            }
        }
    }

    static class Vec {
        double x;
        double y;
        Vec (double x, double y) { this.x = x; this.y = y; }
        double dot (Vec v) { return x * v.x + y * v.y; }
        Vec sub (double x, double y) { return new Vec(this.x - x, this.y - y); }
    }

    static double fade (double v) {
        // easing doesn't matter for range sample test.
        // v = 3 * v * v - 2 * v * v * v;
        return v;
    }

    static double lerp (double p, double a, double b) {
        return (b - a) * p + a;
    }

    static Vec gradient (int c, int r) {
        return gradients[c][r];
    }

    // your function, with y0 fixed. note my gridSize is not a double like yours.     
    public static double getPoint(int x, int y) {

        Vec p = new Vec(x / (double)gridSize, y / (double)gridSize);
        Vec d = new Vec(Math.floor(p.x), Math.floor(p.y));

        int x0 = (int)d.x,
            y0 = (int)d.y;

        double d00 = gradient(x0    , y0    ).dot(p.sub(x0    , y0    )),
               d01 = gradient(x0    , y0 + 1).dot(p.sub(x0    , y0 + 1)),
               d10 = gradient(x0 + 1, y0    ).dot(p.sub(x0 + 1, y0    )),
               d11 = gradient(x0 + 1, y0 + 1).dot(p.sub(x0 + 1, y0 + 1));

        double fadeX = fade(p.x - d.x),
               fadeY = fade(p.y - d.y);

        double i1 = lerp(fadeX, d00, d10),
               i2 = lerp(fadeX, d01, d11);

        return lerp(fadeY, i1, i2);

    }

    public static void main (String[] args) {

        // loop forever, regenerating gradients and resampling for range. 
        while (true) {

            initializeGradient();

            double minz = 0, maxz = 0;

            for (int x = 0; x < gridSize * gridCells; ++ x) {
                for (int y = 0; y < gridSize * gridCells; ++ y) {
                    double z = getPoint(x, y);
                    if (z < minz)
                        minz = z;
                    else if (z > maxz)
                        maxz = z;
                }
            }

            System.out.println(minz + " " + maxz);

        }

    }

}

我看到理论范围内的值 [ - 0.707,0.707] ,尽管我通常看到-0.6到0.6之间的值;这可能只是价值分配和低采样率的结果。

I am seeing values within the theoretical range of [-0.707, 0.707], although I am generally seeing values between -0.6 and 0.6; which could just be a consequence of the value distribution and a low sampling rate.

这篇关于Perlin噪音的输出范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆