【Unity】パーリンノイズとは?滑らかで自然なノイズを生成する擬似乱数

パーリンノイズとは? Unity

こんにちは、ともくんのゲーム作り部屋にようこそ!

このページでは、

「パーリンノイズってなに?」

「パーリンノイズはどうやって使えば良いの?」

というお悩みの方に向けた内容となっています。

Unityでは、パーリンノイズ(PerlinNoise)という滑らかな擬似乱数を生成することができるメソッドを使うことができます。

このパーリンノイズは、様々な分野で使われますが、ゲームでは、リアルな地形の作成に使われたり、アニメーションなどの動きに自然なゆらぎを与えたりすることができます。

例えば、ゲームを開始するたびにコースや地形を自動で変化させたいなどの際に、パーリンノイズが非常に便利に活用できます。

そこでこのページでは、Unityで使えるパーリンノイズについて、どういうものなのか、また基本的な使い方や実装例をまとめていきます。

この記事を書いた人

ゲーム作りを学び始めた一児のパパです。
このブログは、子供から「ゲームを作ってみたい!」と言われ、非プログラマーでゲーム作りをしたことない僕が、ゲーム作りの本を読んで独学でゲーム開発を学んでいるブログです。
同じように初めてゲーム作りをしている方と一緒に学んでいけるようなブログに出来たらいいなと思っています。
また、「このコードはおかしい」とか「もっと良い書き方があるよ!」などあれば、どんどん指摘して頂けると助かります。

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

まずは、パーリンノイズがどういうものなのか紹介していきます。

滑らかで自然なノイズを生成する擬似乱数

パーリンノイズとは、滑らかで自然なノイズを生成するための擬似乱数のことで、ケン・パーリンという人が開発したアルゴリズムです。

このパーリンノイズの大きな特徴として、上記でも書いた「滑らかな」擬似乱数を生成できるという部分にあります。

一般的に、Unityなどで擬似乱数を使う場合、Randomクラスの関数を使うことが多いですが、以下のように値がランダムに取得されるため、それぞれの値同士の変化量は大きくなります。

一方で、パーリンノイズを使う場合は、値同士の変化量を小さくすることができ、以下のように数値の変動が滑らかな擬似乱数を生成することができます。

このようにパーリンノイズは、少しずつ変化する乱数を取得することができるという特徴があります。

リアルな地形や自然な動きを作れる

パーリンノイズが滑らかな擬似乱数であるという特徴から、ゲーム内で滑らかでリアルな地形を自動で作成したり、アニメーションの動きをより自然にするといったことができます。

例えば、以下のように四角いオブジェクトを並べておき、それぞれのオブジェクトの高さをスクリプトから変更できるようにしておきます。

この際に、パーリンノイズで取得した値を使ってオブジェクトの高さを指定してあげると、以下のように少しずつ変化した滑らかな繋がった地形を作り出すことができます。

ちなみに、この時Randomクラスの関数を使ってオブジェクトの高さを指定すると、以下のようにそれぞれの高さがランダムとなるので、ボコボコで地形のようには生成されません。

また、地形以外にもアニメーションの動きなどに対して、パーリンノイズで少しだけ変化を加えてあげることで、一定した不自然な動きを解消させることができるようになります。

特定の入力値で決まった値を取得してくる

パーリンノイズのもう一つの特徴として、毎回ランダムな値を取得してくるのではなく、特定の入力値に対して決まった値を取得してくるという特徴があります。

これはパーリンノイズのアルゴリズムの仕組み部分で、Unityでは2Dパーリンノイズとして2次元の平面座標を使って値を取得していくことになります。

この平面座標上に、それぞれの値が徐々に変化するようなパターンが準備されていて、X座標Y座標を指定してあげることで、その座標に位置する値を取得することができます。

つまり、指定する座標が同じであれば、毎回取得してくる値も同じということになります。

そして、この指定する座標を徐々にずらしていくことで、少しずつ変動した値を取得することができ、その値を使って地形やオブジェクトの動きに変化を加えることができます。

パーリンノイズ(PerlinNoise)の基本的な使い方

ここからは、Unityでパーリンノイズを使う方法を紹介していきます。

Mathf.PerlinNoiseの引数で2次元座標を指定する

Unityでパーリンノイズを使う場合は、以下のように記述して使うことで、0~1までのfloat型のノイズ値を取得することができます。

Mathf.PerlinNoise(x, y);

x:平面上のX座標の値(float型)
y:平面上のX座標の値(float型)

引数のxyで指定した座標に対応したノイズ値を取得することができ、このxとyを少しずつ変動させることで、徐々に変化したノイズ値を取得することになります。

例えば、X座標の値を0.1ずつずらしてノイズ値を取得してみます。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        for(int i = 0; i < 5; i++)
        {
            float num = Mathf.PerlinNoise(0.1f * i, 0);
            Debug.Log(num);
        }
    }
}

上記の9行目でPerlinNoiseメソッドを使って、ループ処理が起きるたびに引数のX座標の値が0.1ずつ上がるように記述しています。

すると、以下のように少しずつノイズ値が変化して取得できているのが分かります。

この取得できるノイズ値は、0~1までの間の値となるため、この値に対して倍率などを掛け合わせて調整してあげることで、実際に地形などを作っていくことになります。

毎回変わる2Dコースを作成する

実際にパーリンノイズを使って、ゲームを開始するたびに毎回変わるような簡単な2Dコースを作成してみます。

まず、以下のようにスタート地点となる3×1の横長のオブジェクト(黒色)と、コースの基準となる1×1の正方形のオブジェクト(黄色)を作成しておきます。

ゲーム開始後に、正方形のオブジェクトの数を増やしてコースを伸ばしていきたいので、正方形のオブジェクトはPrefab化して、一旦シーン内から削除しています。

次に、空オブジェクトを配置しておき、以下のスクリプトをアタッチしておきます。

using UnityEngine;

public class Test2 : MonoBehaviour
{
    public GameObject box;  // コースのベースとなるPrefab
    public GameObject start;    // スタート地点のオブジェクト
    public int length = 30; // 新しく作成したい数

    void Start()
    {
        int number = Random.Range(0, 20);   // コースを決める数
        int loopCount = number + length;    // ループ回数

        for (int i = number; i < loopCount; i++)
        {
            GameObject clone = Instantiate(box);    // Prefabを新しく作成する処理
            float noise = Mathf.PerlinNoise(0.06f * i, 0.06f * i) * 2 - 1;  // ノイズ値を取得
            clone.transform.position = new Vector2(i - number - 13, Mathf.Round(noise * 7));    // 作成したオブジェクトの座標の移動処理
            if (i == number)
            {
                start.transform.position = new Vector2(start.transform.position.x, clone.transform.position.y); // スタート地点のオブジェクトを移動
            }
        }
    }
}

11行目で、Random.Rangeメソッドを使って、0から9までのランダムな値を変数numberで取得していて、この数値によってコースが変動するようにしています。

つまり、ここでは10通りのコースが自動で作られるようにしていて、この数を増やすことでよりコースのパターンを増やすということができます。

for文の中の16行目で、Instantiateメソッドを使ってPrefab化した正方形のオブジェクトを生成するループ処理を行っています。

そして、17行目でPerlinNoiseメソッドを使って、ノイズ値を取得しています。

このPerlinNoiseの引数に、ループ変数のi0.06を掛けた値を指定することで、ループする度に毎回少し異なる値が指定されるようにしています。

また、PerlinNoiseの値を2倍にして1を引いてあげることで、ノイズ値を-1から1の間の値に変換しています。

あとは、18行目で生成されたオブジェクトの座標を指定する際に、Y座標に先ほどのノイズ値を5倍にしてMathf.Roundで偶数丸めの処理を行って整数で指定しています。

今回は、ベースとなるオブジェクト同士の高さの間が1以下の中途半端な位置に配置されないように、Mathf.Roundを使っています。

あと、21行目でスタート地点となるオブジェクトの位置を、最初にInstantiateで作成されたオブジェクトと同じ高さになるように指定しています。

これで何度かゲームを実行してみると、

実行するたびに生成されるコースが少し変わっていて、コースもしっかりと繋がっているのが分かります。

ここでは、ゲーム実行時点でコースを作成していますが、プレイヤーが進むに連れて自動で生成されるなどのような仕組みも同様に作れそうです。

まとめ

このページでは、Unityで使えるパーリンノイズについて、どんな仕組みなのか、使い方までをまとめていきましたが、いかがでしたでしょうか?

パーリンノイズとは、数値の変動を滑らかにさせた擬似乱数を生成してくれる関数のことです。

パーリンノイズを使うことで、ゲーム内の地形を作成する際に滑らかでより自然な地形にしたり、アニメーションに自然なゆらぎを加えたりすることができます。

仕組みが少し複雑なので理解しにくいですが、パーリンノイズを使うことでより滑らかで自然な流れを作ることができるようになります。

最後までお読みいただきまして、ありがとうございました!

コメント