2
3

JavaScriptとp5.jsライブラリを用いて、Perlinノイズに基づく動的な3次元地形アニメーション。

Posted at

スクリーンショット 2024-09-20 044722.png

スクリーンショット 2024-09-20 044748.png

スクリーンショット 2024-09-20 044734.png

概要 Perlinノイズを使った3D地形

本研究では、JavaScriptとp5.jsライブラリを用いて、Perlinノイズに基づく動的な3次元地形アニメーションを生成する手法を提案する。Perlinノイズは、自然界のパターンを模倣した滑らかなノイズ関数であり、ランダム生成においてその連続性と自然な見た目から広く使用されている。本稿では、時間軸を導入した4次元的変化を加え、カラフルかつフルスクリーンで描画される地形アニメーションを実装し、視覚的に豊かな体験を提供する。

  1. はじめに
    コンピュータ生成の地形表現は、ゲーム、映画、シミュレーション、データビジュアライゼーションなど、多くの分野で利用されている。その中でも、ノイズ関数に基づく手法は、複雑で自然な形状を簡便に生成するための強力な技術である。Perlinノイズは、従来のランダムノイズとは異なり、隣接する値同士の滑らかな遷移を特徴とし、地形生成などの応用に適している。本研究では、このPerlinノイズを用いて、リアルタイムに変化するカラフルな地形アニメーションを実現し、ユーザーの画面サイズに適応する動的な可視化を行う。

  2. 手法
    2.1 Perlinノイズの導入
    Perlinノイズは、ケン・パーリンによって開発された連続的な擬似ランダムノイズである。2次元および3次元空間における自然な表現を可能にするため、地形生成やシミュレーションにおいて一般的に使用される。本研究では、p5.jsの組み込み関数であるnoise()を使用して、時間に依存する動的な3次元地形を生成する。

2.2 3次元地形の生成
地形生成は以下のステップで行われる。

ウィンドウサイズに応じたキャンバスを生成する(フルスクリーン対応)。
scale変数によって定義された一定間隔で、地形を2次元グリッド上に描画する。
各グリッド点に対して、Perlinノイズに基づいた高さを計算する。noise(xoff, yoff)によって各グリッドの高さを取得し、その値をmap()関数で-150から150の範囲にスケールする。
3次元グリッド全体に対して、TRIANGLE_STRIPを用いて連続的な頂点を描画し、地形のメッシュを形成する。
2.3 カラフルな視覚効果
本研究の特徴として、地形の高さに基づいたカラフルな視覚効果を実装した。具体的には、地形の各頂点の高さ情報を色の変調に反映し、以下のようにしてカラフルな描画を行う。

各頂点の高さを基に、色を計算し、stroke()およびfill()関数で色を指定する。
fill()関数では透明度も調整し、半透明の色で滑らかな遷移を表現する。
2.4 時間軸の導入による動的変化
時間の経過と共に地形が変化するよう、時間軸を4次元目として追加する。これにより、地形が「呼吸」するように周期的に変化する。具体的には、flyingという時間変数を徐々に減少させることで、地形が滑らかに変化するようにした。flyingはnoise()関数に対するオフセットとして使用され、時間と共にノイズパターンが変化する。

2.5 フルスクリーン描画とレスポンシブデザイン
ユーザーのウィンドウサイズに自動適応するため、windowWidthとwindowHeightを用いてキャンバスサイズを動的に調整している。さらに、ウィンドウのサイズ変更時には、windowResized()関数によってリアルタイムでキャンバスのサイズを再設定し、地形の描画が常にフルスクリーンで表示されるようにした。

  1. 実装結果
    提案した手法を用いて、Perlinノイズに基づくカラフルな地形アニメーションをリアルタイムで生成した。実装されたシステムは、フルスクリーンのウィンドウに合わせて地形を描画し、ユーザーが視覚的に楽しめるアニメーションを提供する。時間と共に地形が変化するため、動きのあるダイナミックなビジュアライゼーションが実現され、従来の静的な地形生成とは一線を画す表現が可能となった。

  2. 結論
    本研究では、Perlinノイズに基づいて、カラフルかつ動的な地形アニメーションを生成する手法を提案した。時間軸を導入することで、地形が周期的に変化し、視覚的なダイナミズムを持たせることに成功した。また、フルスクリーン対応により、ユーザーのデバイスに応じた最適な表示が可能となった。本手法は、インタラクティブなコンテンツやゲーム開発における地形生成への応用が期待される。将来的には、さらに高度なノイズ関数や、複数の色彩パターンを組み合わせることで、より複雑で美しい地形の生成を目指す。

参考文献

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>カラフルなPerlin Noise地形</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
</head>
<body>
    <script>
        let cols, rows;
        let scale = 20;  // グリッドサイズ
        let w, h;
        let terrain = [];
        let flying = 0;

        function setup() {
            // ウィンドウのサイズでキャンバスをフルスクリーンに設定
            createCanvas(windowWidth, windowHeight, WEBGL);
            w = windowWidth * 2;  // 地形の幅
            h = windowHeight * 2;  // 地形の高さ
            cols = w / scale;  // 列数
            rows = h / scale;  // 行数

            // 2次元配列を初期化
            for (let x = 0; x < cols; x++) {
                terrain[x] = [];
                for (let y = 0; y < rows; y++) {
                    terrain[x][y] = 0;  // 初期値
                }
            }
        }

        function draw() {
            flying -= 0.25;  // ゆっくりしたアニメーション速度
            let yoff = flying;
            for (let y = 0; y < rows; y++) {
                let xoff = 0;
                for (let x = 0; x < cols; x++) {
                    // Perlinノイズで高さを生成し、-100から100にマッピング
                    terrain[x][y] = map(noise(xoff, yoff), 0, 1, -150, 150);
                    xoff += 0.1;
                }
                yoff += 0.1;
            }

            background(0);  // 背景を黒に設定
            stroke(255);  // 線の色を白に設定
            noFill();  // 面の塗りつぶしを無効

            // 地形を回転させて3Dの見え方を調整
            rotateX(PI / 3);
            translate(-w / 2, -h / 2);

            // カラフルな描画
            for (let y = 0; y < rows - 1; y++) {
                beginShape(TRIANGLE_STRIP);
                for (let x = 0; x < cols; x++) {
                    // 高さに基づいて色を変える(カラフルさを追加)
                    let c = map(terrain[x][y], -150, 150, 0, 255);
                    stroke(c, 255 - c, 255);
                    fill(c, 100, 255 - c, 150);

                    // 各頂点を描画
                    vertex(x * scale, y * scale, terrain[x][y]);
                    vertex(x * scale, (y + 1) * scale, terrain[x][y + 1]);
                }
                endShape();
            }
        }

        // ウィンドウがリサイズされた時にキャンバスもリサイズ
        function windowResized() {
            resizeCanvas(windowWidth, windowHeight);
            w = windowWidth * 2;
            h = windowHeight * 2;
            cols = w / scale;
            rows = h / scale;
        }
    </script>
</body>
</html>

解説

HTML部分:

基本的なHTMLの構造を定義し、タグを使用してp5.jsのライブラリを読み込んでいます。

JavaScript部分:

変数の定義:
colsとrowsはグリッドの列と行の数を保持します。
scaleは各グリッドのサイズを指定し、wとhは地形の幅と高さを設定しています。
terrainは2次元配列で、地形の高さ情報を格納します。
flyingは時間経過による動きを制御するための変数です。

setup関数:
createCanvas(800, 800, WEBGL)で3D描画を可能にするキャンバスを作成します。
colsとrowsの値を計算し、地形の高さを格納する2次元配列terrainを初期化します。

draw関数:
flying変数を更新して、地形の動きに時間経過を反映させます。これにより、4次元目の時間を表現します。
yoffとxoffを使って、noise(xoff, yoff)で各地点の高さを生成します。noise関数はPerlinノイズを利用して滑らかな地形を生成します。
map関数で、ノイズ値を高さの範囲(-100から100)にマッピングします。
背景を黒くし、rotateXを使って視点を調整、地形の位置を中央に配置します。
TRIANGLE_STRIPを使って、3Dの地形をメッシュとして描画します。

視点と描画:
rotateX(PI / 3)で視点を斜め上からにし、立体的な地形を表示しています。
TRIANGLE_STRIPを使って、頂点をつなげて地形の表面を描画しています。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3