3
4

ダイナミック ローレンツアトラクター が描かれた空間内を飛び回るゲーム。

Last updated at Posted at 2024-08-22

スクリーンショット 2024-08-23 042931.png

スクリーンショット 2024-08-23 042953.png

ローレンツ・アトラクターを3Dでプロットし、その空間内をカメラが飛び回る視点でアニメーションを行ってます。

import os
import webbrowser
from http.server import SimpleHTTPRequestHandler, HTTPServer
import threading

# HTMLコードを生成
html_content = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lorenz Attractor in 3D</title>
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script>
        // シーン、カメラ、レンダラーの設定
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // ローレンツアトラクターのパラメータと初期条件
        const sigma = 10, rho = 28, beta = 8 / 3;
        const dt = 0.01;  // 時間刻み
        let x = 0.1, y = 0.1, z = 0.1;  // 初期条件
        const points = [];  // 点の配列

        // ローレンツアトラクターの点を生成
        for (let i = 0; i < 10000; i++) {
            const dx = sigma * (y - x) * dt;
            const dy = (x * (rho - z) - y) * dt;
            const dz = (x * y - beta * z) * dt;
            x += dx;
            y += dy;
            z += dz;
            points.push(new THREE.Vector3(x, y, z));  // 点を追加
        }

        // ジオメトリとマテリアルを作成し、点群を作成
        const geometry = new THREE.BufferGeometry().setFromPoints(points);
        const material = new THREE.PointsMaterial({ color: 0xff0000, size: 0.1 });
        const lorenzAttractor = new THREE.Points(geometry, material);
        scene.add(lorenzAttractor);  // シーンに追加

        // カメラの初期位置とアニメーションの設定
        camera.position.set(0, 0, 50);  // カメラの初期位置
        const cameraSpeed = 0.02;  // カメラの移動速度

        // アニメーションループ
        function animate() {
            requestAnimationFrame(animate);

            // ローレンツアトラクターの経路に沿ってカメラを移動
            const pointIndex = Math.floor((performance.now() * cameraSpeed) % points.length);
            const point = points[pointIndex];

            camera.position.x = point.x;  // カメラのX座標を更新
            camera.position.y = point.y;  // カメラのY座標を更新
            camera.position.z = point.z + 10;  // カメラのZ座標を更新(オフセットを追加)

            // カメラが常にアトラクターの中心を見るように設定
            camera.lookAt(new THREE.Vector3(0, 0, 0));

            renderer.render(scene, camera);  // シーンをレンダリング
        }

        animate();  // アニメーションを開始

        // ウィンドウリサイズ時の処理
        window.addEventListener('resize', function () {
            renderer.setSize(window.innerWidth, window.innerHeight);  // レンダラーのサイズを更新
            camera.aspect = window.innerWidth / window.innerHeight;  // カメラのアスペクト比を更新
            camera.updateProjectionMatrix();  // カメラの投影行列を更新
        });
    </script>
</body>
</html>

"""

# HTMLファイルとして保存
html_file = 'galaxy_simulation.html'
with open(html_file, 'w') as file:
    file.write(html_content)

# サーバーをバックグラウンドで起動
def run_server():
    server_address = ('', 8000)
    httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)
    httpd.serve_forever()

# サーバーを別スレッドで実行
thread = threading.Thread(target=run_server)
thread.daemon = True
thread.start()

# デフォルトのブラウザでHTMLファイルを開く
webbrowser.open(f'http://localhost:8000/{html_file}')

# サーバー停止まで待機
try:
    thread.join()
except KeyboardInterrupt:
    print("Server stopped.")

各部分の説明
シーン、カメラ、レンダラーの設定: THREE.Scene()でシーンを作成し、THREE.PerspectiveCamera()で視点となるカメラを設定します。THREE.WebGLRenderer()を使用して、描画を行うレンダラーを設定し、renderer.domElementをHTMLに追加しています。
ローレンツアトラクターの点の生成: ローレンツ方程式のパラメータを設定し、時間刻みdtに従って次々と新しい点を計算し、点の配列pointsに追加しています。
ジオメトリとマテリアルの作成: ローレンツアトラクターの点をTHREE.BufferGeometry()とTHREE.PointsMaterial()で設定し、シーンに追加します。
アニメーションループ: requestAnimationFrame()を用いて、カメラがローレンツアトラクターに沿って動き回るようにアニメーションを行います。カメラは各フレームで現在のアトラクターの点を基準に移動し、常にアトラクターの中心を見続けます。
ウィンドウリサイズ時の処理: ウィンドウのサイズが変更された際に、レンダラーとカメラのアスペクト比を更新し、適切に描画が行われるようにします。
このコードで、ローレンツアトラクターの空間内をカメラが動きながら観察するアニメーションが実現できます。

3
4
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
3
4