(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

パーリンノイズ(PerlinNoise)とは【Unity】【パーリンノイズ】


このエントリーをはてなブックマークに追加

この記事でのバージョン
Unity 2018.2.17f1


はじめに

今回はパーリンノイズ(PerlinNoise)というアルゴリズムが

どういったものなのか、何に使えるのか、Unityではどう使うのか

ということをまとめてみました!


f:id:kan_kikuchi:20181223165211g:plain


ちなみに本ブログでもパーリンノイズに関する記事を何度か書いていますが、



その度に「パーリンノイズとは」を書くのが面倒、というのが本記事の1番の目的だったりします。


パーリンノイズ(PerlinNoise)とは

Unityのリファレンスを見てみると、パーリンノイズは以下のように説明されています。

Perlin noise is a pseudo-random pattern of float values generated across a 2D plane (although the technique does generalise to three or more dimensions, this is not implemented in Unity). The noise does not contain a completely random value at each point but rather consists of "waves" whose values gradually increase and decrease across the pattern. The noise can be used as the basis for texture effects but also for animation, generating terrain heightmaps and many other things.

Google翻訳

Perlinノイズは、2D平面全体で生成される浮動小数点値の擬似ランダムパターンです(3つ以上の次元に一般化されますが、Unityでは実装されていません)。 ノイズは、各点で完全にランダムな値を含むのではなく、その値がパターン全体にわたって徐々に増加および減少する「波」からなる。 ノイズは、テクスチャエフェクトの基礎として使用されるだけでなく、アニメーション、地形の高さマップなど多くのものの生成にも使用できます。

f:id:kan_kikuchi:20181201162348p:plain


つまり、単純にランダムな値を返すものではなく、

入力値(xとy)の変化に合わせて徐々に変化するような乱数という事です。

端的に言えば、変化がなだらなかな乱数と言った感じでしょうか。


これが何に使えるかと言えば、ランダムだけど値の変化が急激だと困るものです。


例えばマイクラみたいなマップを自動生成する時や

(ランダムに生成したいが、高さが急激に変化すると登り降りが出来なくなってしまうため)


f:id:kan_kikuchi:20160316135312p:plain


関節やスカートなどゆらぎ(回転)を追加して

「基本的には同じだけど、ちょっと違うし、ランダムなアニメ」を作る時などです。

(ランダムに動いてほしいが、急激に回転してしまうと不自然になるため)


f:id:kan_kikuchi:20181201193621g:plain


Unityでパーリンノイズを使う

Unityでパーリンノイズを使いたい場合は、

Mathfという数学系の処理を行うクラスのPerlinNoiseを使うと簡単に実装できます。



実際に使う場合は以下のような感じでxとyを指定します。

取得出来る値は0 ~ 1で、xとyの値が同じなら常に同じ値を返します。

//xとyはfloat
float noise = Mathf.PerlinNoise(x, y);


前述の通り、変化がなだらかな乱数なので、

xとyの値が近いと出力される値(上記の例だとnoise)も近くなります。


それを視覚的に表したのが以下の画像です。

各画素値の座標xとyを元にパーリンノイズで値を取得し、

0に近いほど黒に近く、1に近いほど白に近い色を付けてあります。

全体的にはランダムな変化ですが、値の変化がなだらかなので、

色が急激に変化しておらず境界が曖昧になり、ボヤケて見えると思います。


f:id:kan_kikuchi:20181223164053j:plain


ちなみに、ただの乱数を使った場合は以下のような感じになります。

float color = Random.Range(0, 1f);

f:id:kan_kikuchi:20181223164225j:plain


また、入力が同じなら出力も同じ事を利用して、

初期値(上記の例だと_initialSmaple)を変化させると全体をスライドさせるような事も可能です。


f:id:kan_kikuchi:20181223165211g:plain


ちなみにUnityではパーリンノイズの周期が256で実装されているので、

xやyの差が256だと全く同じ結果になる点には注意が必要かもしれません。


f:id:kan_kikuchi:20181223165047j:plain


さらに、xとyの値が近いと出力される値が近い事を利用して、

xとyに任意の倍率(上記の例だと_noizeScale)を乗算する事で、変化の激しさを調整する事も可能です。


f:id:kan_kikuchi:20181223165734g:plain


なお、時間と共に変化させたいという場合はTime.timeを使うと簡単に実装出来ます。

float xSample = Time.time + _initialSmaple.x + x / (float)_texture.width  * _noizeScale;
float ySample = Time.time + _initialSmaple.y + y / (float)_texture.height * _noizeScale;
private void Update() {
  CalcNoise();
}

f:id:kan_kikuchi:20181223170341g:plain


ここまでの例ではMathf.PerlinNoiseに入力するxとyの両方の値を変化させていましたが、

入力値が1つで良い場合は片方を固定し、もう片方を変化させるという使い方も出来ます。

また、こうする事で固定した方を乱数のシードのように扱えるため、

再現を行うことや、逆に違う変化にする事も容易になります。


例えばyは0で変化させず、xをTime.timeで変化させていくと、

以下のように画像の下辺を沿って変化していく感じになります。


f:id:kan_kikuchi:20181223194018j:plain


実際に回転や移動に使ってみると以下のような感じ。

//パーリンノイズで移動
private void Update () {
  Vector3 position = transform.position;

  //Mathf.PerlinNoiseは0 ~ 1の値を返すので-0.5して-0.5 ~ 0.5の値に補正、移動距離を大きくするため10を乗算
  position.x = (Mathf.PerlinNoise(Time.time, 0) - 0.5f) * 10;

  transform.position = position;
}
//パーリンノイズで回転
private void Update () {
  Vector3 rotation = transform.rotation.eulerAngles;

  //0 ~ 360の間で回転するように
  rotation.z = Mathf.PerlinNoise(Time.time, 0) * 360f;

  transform.rotation = Quaternion.Euler(rotation);
}

f:id:kan_kikuchi:20181223171738g:plain


ランダムっぽい動きをしていますが、変化がなだらかなので

「前フレームから○○だけ動かす」とやっていないにもかかわらず、

綺麗に連続して動いているのが分かると思います。