Noise

canvasに対応していません。

■ノイズの種類
OFF  ホワイトノイズ  ブロックノイズ(fBm)  バリューノイズ(fBm)  パーリンノイズ(fBm)  セルノイズ  セルノイズ反転 

■fBm反復回数


■アニメーション

説明

ノイズテクスチャをオフスクリーンで生成して、レイマーチングの距離関数にマッピングさせてみました。
ここで紹介しているのはベーシックなノイズ生成手法のみですが、更に調べていくと頭のおかしい手法がまだまだたくさんあって面白い、というか発狂しそうです。

ホワイトノイズ

全ての点においてランダムな値を返します。
float random(vec2 v) { /* 0.0..1.0の乱数を返す */ return fract(sin(dot(v, vec2(12.9898, 78.233))) * 43758.5453); } float animation(float f) { /* 0.0..1.0をsin波の周期で繰り返す */ return sin(f * 6.283 + u_anim * 2.0) * 0.5 + 0.5; } float noise_(vec2 uv) { float o = animation(random(uv)); return o; }


ブロックノイズ

一定間隔に区切られた矩形の範囲毎に同じランダム値を返します。
float noise_(vec2 uv) { vec2 i_uv = floor(uv * 8.0); float o = animation(random(i_uv)); return o; }


バリューノイズ

ブロックノイズの4点間を補間して滑らかにしたもの。
float interpolation(float f) { /* 0.0..1.0の補間式、5次のものがアーティファクト少なくていいらしい */ /*return f * f * (3.0 - 2.0 * f);*/ return f * f * f * (f * (6.0 * f - 15.0) + 10.0); } float noise_(vec2 uv) { vec2 i_uv = floor(uv * 8.0); vec2 f_uv = fract(uv * 8.0); float f1 = animation(random(i_uv + vec2(0.0, 0.0))); float f2 = animation(random(i_uv + vec2(1.0, 0.0))); float f3 = animation(random(i_uv + vec2(0.0, 1.0))); float f4 = animation(random(i_uv + vec2(1.0, 1.0))); float o = mix( mix(f1, f2, interpolation(f_uv.x)), mix(f3, f4, interpolation(f_uv.x)), interpolation(f_uv.y)); return o; }


パーリンノイズ

クラシックなパーリンノイズの実装です。
バリューノイズでは4点の単一値を補間しましたが、パーリンノイズでは4点に勾配ベクトルを設定し、計算する点へのベクトルとの内積をとることで影響値を算出します。
バリューノイズに比べ、ブロック状のアーティファクトが目立たずより自然な見た目になります。
vec2 random2(vec2 v) { return vec2(random(v), random(v + vec2(0.5, 0.5))); } vec2 animation2(vec2 v) { return vec2(animation(v.x), animation(v.y)); } float noise_(vec2 uv) { vec2 i_uv = floor(uv * 8.0); vec2 f_uv = fract(uv * 8.0); vec2 v1 = animation2(random2(i_uv + vec2(0.0, 0.0))) * 2.0 - 1.0; vec2 v2 = animation2(random2(i_uv + vec2(1.0, 0.0))) * 2.0 - 1.0; vec2 v3 = animation2(random2(i_uv + vec2(0.0, 1.0))) * 2.0 - 1.0; vec2 v4 = animation2(random2(i_uv + vec2(1.0, 1.0))) * 2.0 - 1.0; float o = mix( mix(dot(v1, f_uv - vec2(0.0, 0.0)), dot(v2, f_uv - vec2(1.0, 0.0)), interpolation(f_uv.x)), mix(dot(v3, f_uv - vec2(0.0, 1.0)), dot(v4, f_uv - vec2(1.0, 1.0)), interpolation(f_uv.x)), interpolation(f_uv.y)) * 0.5 + 0.5; return o; }
ここでは実装していませんが、他にも改良版の手法が考案されています。
改良版パーリンノイズ …… 完全にランダムな勾配ベクトルではなく、前もって用意しておいた複数個の勾配ベクトルをハッシュにより参照させることで計算コストを抑える。
シンプレックスノイズ …… その次元での最小プリミティブ(2次元ノイズの場合、三角形)で補間を行う。次元数に対してオーダーが小さい。コードが難解で読めない。

セルノイズ

Cellular noiseとかWorley noiseとかVoronoi noiseとか言われるものと同じです(厳密には違うのかもしれない)
ランダムに配置した複数の点と計算する点の最小距離を求めます。
見た目の割に実装は非常にシンプルです。
float noise_(vec2 uv) { float o = 1.0; for(int i = 0; i < 60; i++) { vec2 v = random2(vec2(float(i), 0.1)); v += (animation2(random2(v)) - 0.5) * 0.1; o = min(length(v - uv), o); } o = min(pow(o * 5.0, 2.0), 1.0); // o = 1.0 - o; // inverse return o; }
タイル分割した範囲にポイントの取りうる座標を限定して、ポイントとの総当たりの計算コストを抑える改良版もあるようです。

fBm

周期と振幅の異なるノイズを段階的に重ね合わすことでいい感じのノイズに。
地形生成や雲の生成なんかに。
float fbm = 0.0; float fbm_max = 0.0; for(int i=0; i>=0; i++) { if(u_fbm_iteration == i) break; float f = pow(0.5, float(i)); fbm += f * noise_(v_uv0 * pow(2.0, float(i))); fbm_max += f; } color.xyz *= fbm / fbm_max;

トップページへ戻る


Follow @yunta_robo