Perlin Noiseが「ブロック状」に見えるのはなぜですか?


21

自分で Perlin Noiseを実装しようとしました理論だけを使っ(flafla2.github.io/2014/08/09/perlinnoise.htmlに続きます)。残念ながら、「オリジナル」のパーリンノイズの外観を実現できませんでした。

以下のコードがPerlin Noiseのブロックバージョンをレンダリングする理由は何ですか?

アーティファクトなしでPerlin Noiseをレンダリングするために、コードを改善/変更する必要があるものは何ですか?

補間方法またはgradsベクトルに問題がある可能性があります。gradsすべての4つの近くの格子点について-ベクトルドット(格子点ランダムベクトル)の生成物および(サイズのベクター)を含みます。(ランダムおよびサイズのベクトルは、最初のリンクで説明されています。)

GLSLサンドボックス:http : //glslsandbox.com/e#32663.0

ノイズのアーチファクト

float fade(float t) { return t * t * t * (t * (t * 6. - 15.) + 10.); }
vec2 smooth(vec2 x) { return vec2(fade(x.x), fade(x.y)); }

vec2 hash(vec2 co) {
    return fract (vec2(.5654654, -.65465) * dot (vec2(.654, 57.4), co));
}

float perlinNoise(vec2 uv) {
    vec2 PT  = floor(uv);
    vec2 pt  = fract(uv);
    vec2 mmpt= smooth(pt);

    vec4 grads = vec4(
        dot(hash(PT + vec2(.0, 1.)), pt-vec2(.0, 1.)),   dot(hash(PT + vec2(1., 1.)), pt-vec2(1., 1.)),
        dot(hash(PT + vec2(.0, .0)), pt-vec2(.0, .0)),   dot(hash(PT + vec2(1., .0)), pt-vec2(1., 0.))
    );

    return 5.*mix (mix (grads.z, grads.w, mmpt.x), mix (grads.x, grads.y, mmpt.x), mmpt.y);
}

float fbm(vec2 uv) {
    float finalNoise = 0.;
    finalNoise += .50000*perlinNoise(2.*uv);
    finalNoise += .25000*perlinNoise(4.*uv);
    finalNoise += .12500*perlinNoise(8.*uv);
    finalNoise += .06250*perlinNoise(16.*uv);
    finalNoise += .03125*perlinNoise(32.*uv);

    return finalNoise;
}

void main() {
    vec2 position = gl_FragCoord.xy / resolution.y;
    gl_FragColor = vec4( vec3( fbm(3.*position) ), 1.0 );
}

回答:


24

補間はうまく見えます。ここでの主な問題は、使用しているハッシュ関数があまり良くないことです。1オクターブだけを見てhash(PT).x、を出力してハッシュ結果を視覚化すると、次のようになります。

悪いハッシュ関数

これはグリッドスクエアごとに完全にランダムになるはずですが、多くの対角線パターンが含まれていることがわかります(ほぼ市松模様のように見えます)。そのため、非常にランダムなハッシュではなく、これらのパターンが表示されますそれによって生成されるノイズ。

もう1つの問題は、ハッシュが[0、1]の勾配ベクトルのみを返すのに対し、すべての方向の勾配を取得するには[-1、1]にある必要があることです。その部分は再マッピングすることで簡単に修正できます。

これらの問題を修正するために、このハッシュ関数を使用するようにコードを切り替えました(これはMikkel Gjoelから学びました。おそらくWJJ Reyの論文によるものです)。

vec2 hash(vec2 co) {
    float m = dot(co, vec2(12.9898, 78.233));
    return fract(vec2(sin(m),cos(m))* 43758.5453) * 2. - 1.;
}

トリガー機能のため、バージョンよりも少し高価になることに注意してください。ただし、結果のノイズの外観は大幅に改善されます。

より良いハッシュ関数によるfbmノイズ


ありがとう非常にあなたの説明のための多くの。これは多分トピック外ですが、とにかく質問します。ノイズを計算する一部のソースコードでは、人々はベクトルvec3(1、57、113)を使用して、現在の座標のドット積を計算します(ハッシュを取得することも目的だと思います)。なぜこの定数の選択(57は度で約1ラジアン、133 =度で約2 *ラジアン)なのですか?トリガー関数の周期性のためですか?これをグーグルで検索することはできません。
sarasvati

3
@sarasvatiよくわかりませんが、57と113は素数に近いので、57と113が選ばれていると推測されます。(113は素数、57は素数ではありませんが、3 * 19ですので、まだ素数です...もしそれが問題なら。)素数の数を掛けたり改造したりすると、ビットが乱れる傾向があるので、珍しいことではありませんハッシュの成分。
ネイサンリード

1
@cat GLSLプログラムが決定論的であることを考えると、GLSLにはPRNGがあるとは思いません。
user253751

1
このコメントのスレッドでいくつかの潜在的な新たな疑問...があるように見える
センモウヒラムシ

1
私はそれらのアーティファクトを抱えていましたが、このrand()関数はそれを修正しました。問題は、地形を2 km歩いた後、OPのようなアーティファクトが再び現れ始めたことです。ここでハッシュ関数を使用していました:amindforeverprogramming.blogspot.com/2013/07 / ...これにより、アーティファクトがなくなりました(100kmの距離を除き、bcは不正確ですが、それはチャンクに分割して取得する必要がありました)両方の値をハッシュすることで機能します。これにより、perlinノイズがほぼ無期限に実行されます)。したがって、同じ問題を抱えている人を助けるためにここに残しておきます。
ニコラスピピトーン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.