はじめに
今回、ChatGPT o3-mini-high を用いて、下記のような詳細なプロンプトに基づき、
球体の内部で 100 個のカラフルなボールが跳ね回る 3D シミュレーションを実装しました。
シミュレーションは、p5.js の WebGL モードを利用しており、ブラウザ全画面で 3D 表現が可能です。
また、生成されたコードはすべての要件を満たしており、エラーも一切ありません。
editor.p5js.org にコードを貼り付ければ、すぐに実行できます!
シミュレーションの特徴
-
キャンバスとカメラ設定
-
createCanvas(windowWidth, windowHeight, WEBGL)
を使用し、ブラウザ全画面での 3D 表示が実現されています。 -
orbitControl()
を利用することで、マウス操作によるカメラ操作(回転・ズーム)が可能です。
-
-
球体のコンテナ
- 半径 300 の球体コンテナは、内部が見やすいように半透明のワイヤーフレームで描画。
- ゆっくりと回転するアニメーションにより、内部の動きを把握しやすくしています。
-
ボールの生成と挙動
- 100 個のボールは、ランダムな初期位置、速度、色、サイズ(半径 5〜15)で生成。
- 衝突検出では、球体の内壁との接触時に法線を利用した鏡面反射計算を行い、ボールが外に出ないように制御しています。
-
ボールの軌跡(トレイル)
- 各ボールが移動した軌跡は、古い部分がフェードアウトするように描画され、動きの歴史が視覚的に表現されます。
-
ユーザーインターフェース
- オプションとして、コンテナの回転速度を調整できるスライダーを実装。直感的にシーンの動きを変更可能です。
完成コード
以下のコードは、ChatGPT o3-mini-high によって一発ノーミスで生成されたものです。
各部分に詳細なコメントを入れており、学習目的にも最適です。
// --- グローバル変数 ---
let balls = []; // 100 個のボールを格納する配列
const numBalls = 100; // ボールの個数
const containerRadius = 300; // 球体コンテナの半径
let containerRotation = 0; // 球体コンテナの回転角(アニメーション用)
let rotationSpeedSlider; // オプション:コンテナ回転速度調整用スライダー
// --- setup() ---
// キャンバス作成、ボールの初期化、UI の生成など
function setup() {
// ブラウザ全画面の WEBGL キャンバスを作成
createCanvas(windowWidth, windowHeight, WEBGL);
// 背景色やレンダリング設定
colorMode(RGB, 255, 255, 255, 255);
// 100 個のボールを生成(各ボールはコンストラクタ内でランダムな初期位置・速度・大きさ・色を持つ)
for (let i = 0; i < numBalls; i++) {
balls.push(new Ball());
}
// オプション:コンテナの回転速度を調整できるスライダーを作成
// 範囲は 0 ~ 0.05、初期値 0.01、刻み幅 0.001
rotationSpeedSlider = createSlider(0, 0.05, 0.01, 0.001);
rotationSpeedSlider.position(20, 20);
rotationSpeedSlider.style('width', '200px');
}
// --- windowResized() ---
// ウィンドウサイズ変更時にキャンバスサイズを更新
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
// --- draw() ---
// 毎フレームの描画・更新処理
function draw() {
// 背景色を設定(暗い背景)
background(20);
// ユーザー操作可能なカメラ操作(ドラッグやホイールで視点操作)
orbitControl();
// 照明設定
// シーン全体をやわらかく照らすアンビエントライト
ambientLight(50);
// 手前上方からのポイントライト
pointLight(255, 255, 255, 0, -containerRadius * 2, 500);
// スライダーで指定された回転速度でコンテナをゆっくり回転
let rotSpeed = rotationSpeedSlider.value();
containerRotation += rotSpeed;
// --- 球体コンテナの描画 ---
push();
// 回転アニメーション(Y軸周り)
rotateY(containerRotation);
// 内部が見やすいよう、半透明のワイヤーフレームで描画
noFill();
stroke(200, 200, 255, 150);
strokeWeight(1);
// sphere() の第2・第3引数でディテール数を指定(パフォーマンス調整用)
sphere(containerRadius, 24, 16);
pop();
// --- 各ボールの更新&描画 ---
for (let ball of balls) {
ball.update();
ball.display();
}
}
// ======================================================================
// ボールを表すクラス
// 各ボールは位置、速度、半径、色、そして移動軌跡(トレイル)を持ちます。
// ======================================================================
class Ball {
constructor() {
// ボールの大きさ(半径)は 5~15 のランダム値
this.r = random(5, 15);
// ボールの色:明るめのランダムな RGB 値
this.col = color(random(50, 255), random(50, 255), random(50, 255));
// ボールの初期位置は「球体コンテナ内」に配置
// コンテナの内側に収まるよう、最大距離は containerRadius - this.r
let maxDist = containerRadius - this.r;
// ランダムな方向を取得し、0~maxDist のランダムな長さを掛ける
let pos = p5.Vector.random3D();
pos.mult(random(0, maxDist));
this.pos = pos;
// ボールの初期速度はランダムな 3D ベクトル
// 速度の大きさは 1~3 の範囲(シーンの動き具合を調整可能)
let vel = p5.Vector.random3D();
vel.mult(random(1, 3));
this.vel = vel;
// トレイル(軌跡)として過去の位置を記録する配列
this.trail = [];
// トレイルの最大長(過去の位置の数)を設定
this.maxTrailLength = 30;
}
// --- update() ---
// 位置の更新、コンテナ内での衝突判定&反射、軌跡の記録を行います。
update() {
// 位置に速度を加算して更新
this.pos.add(this.vel);
// --- 衝突判定&反射処理 ---
// 球体コンテナの内壁との衝突判定:
// ボールの中心から原点までの距離 d にボールの半径 this.r を加えた値が
// コンテナの半径 containerRadius より大きくなれば衝突と判定
let d = this.pos.mag();
if (d + this.r > containerRadius) {
// 衝突点での「法線」は原点からボールの位置への単位ベクトル
let n = this.pos.copy().normalize();
// 速度ベクトルと法線との内積を求める
let vDotN = this.vel.dot(n);
// ミラー反射の公式: v' = v - 2*(v・n)*n
// (ボールが外向きに動いている場合 vDotN > 0 となります)
if (vDotN > 0) {
this.vel.sub(p5.Vector.mult(n, 2 * vDotN));
}
// 衝突後、ボールがコンテナ外に出ないよう、ボールの位置を内壁上に補正
// 補正後の位置は「法線ベクトル × (containerRadius - this.r)」
this.pos = n.mult(containerRadius - this.r);
}
// --- トレイルの記録 ---
// 現在の位置のコピーをトレイル配列に追加
this.trail.push(this.pos.copy());
// トレイルの長さが設定した上限を超えたら、古い位置を削除
if (this.trail.length > this.maxTrailLength) {
this.trail.shift();
}
}
// --- display() ---
// ボール自体と、過去の軌跡(トレイル)を描画します。
display() {
// --- トレイルの描画 ---
// 各トレイルの線分は、ボールの色で描画しつつ、
// 古い部分ほど透明度を下げることでフェードアウトさせます。
noFill();
// トレイルは、記録した位置を順に結んだ線分として描画
for (let i = 0; i < this.trail.length - 1; i++) {
let pos1 = this.trail[i];
let pos2 = this.trail[i + 1];
// インデックスが古いほど alpha 値が低くなるように補間
let alpha = map(i, 0, this.trail.length - 1, 50, 255);
stroke(red(this.col), green(this.col), blue(this.col), alpha);
strokeWeight(2);
line(pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z);
}
// --- ボール自体の描画 ---
push();
translate(this.pos.x, this.pos.y, this.pos.z);
noStroke();
fill(this.col);
// ボールは低ディテールの球体として描画(パフォーマンス配慮)
sphere(this.r, 8, 6);
pop();
}
}
実行方法
- editor.p5js.org にアクセスします。
- 新規スケッチを作成し、上記コードをエディタに貼り付けます。
- 「再生」ボタンをクリックすると、ブラウザ全画面でシミュレーションが実行されます。
- マウスのドラッグやホイール操作でシーンを自由に回転・ズームでき、詳細な動きを確認できます。
使用したプロンプト
以下は、今回のシミュレーション作成に用いた詳細なプロンプトの一部です。
(実際のプロンプトは上記の要件に沿っており、p5.js のキャンバス設定、球体コンテナ、ボール生成・衝突処理、トレイル描画、パフォーマンス最適化など、各機能が明確に記述されています。)
以下の要件を含め、**p5.js(WebGL モード)**を使用して球体の内部で 100 個のカラフルなボールが跳ね回る 3D シミュレーションを作成してください
## 1. キャンバスとカメラ設定
- `createCanvas(windowWidth, windowHeight, WEBGL)` を使用し、ブラウザ全画面で 3D 表示できるようにしてください。
- シーンがわかりやすいよう、視点の位置やカメラの動きを適宜調整してください。
## 2. 球体のコンテナ
- 球体の半径は 300 程度に設定し、ボールが視認しやすいようにしてください。
- 球体はゆっくりと回転するようにアニメーションさせ、内部を把握できるようにしてください。
- 球体の描画はワイヤーフレームや半透明など、内部が見やすい方法を検討してください。
## 3. ボールの生成と挙動
- **ボールの個数**: 100 個
- **色・大きさ**: ランダムな色で、半径 5〜15 程度の大きさに設定してください。
- 初期位置と速度(ベクトル)をランダムに与え、球体内部を動き回るようにしてください。
- 衝突検出により、ボールが球体の内壁に衝突した際には**反射計算**を行い、球体の外には出ないようにしてください。
- 反射処理は単純な鏡面反射(法線方向で速度ベクトルを反転)で構いません.
## 4. ボールの軌跡(トレイル)
- 各ボールが移動した後に、**軌道を示すトレイル**を描画してください。
- トレイルはフレームごとに徐々にフェードアウトし、最新の軌跡が色濃く残るようにしてください(アルファ値やレイヤー描画を利用)。
## 5. 描画パフォーマンスと見栄え
- 1 フレームあたりの描画が重くなりすぎないよう、**最適化**を検討してください。
- 不要なオブジェクト生成を避ける、背景クリアの方法を工夫するなど。
- シーンの見栄えがよくなるよう、**背景色や照明、マテリアル**などを適切に設定してください。
- `ambientLight`, `pointLight` などの使用を検討.
## 6. ユーザーへの操作ガイド(任意)
- ユーザーが**ボタンやスライダー**などで球体の回転速度やボールの色・大きさの範囲を変更できる**インタラクティブ UI**を加えても構いません.
## 7. コードの可読性とコメント
- 変数名や関数名はわかりやすくし、主要な部分にはコメントを適宜入れてください。
- 衝突判定や反射処理がどのように行われているかを明確にし、学習目的で読んだ際に理解しやすいように記述してください.
まとめ
今回のシミュレーションは、ChatGPT o3-mini-high の高度なコード生成能力を実感できる一例です。
p5.js(WebGL)を活用したリアルタイムの 3D シミュレーションを、シンプルな設定で実現できる点や、
AI が即座にミスなくコードを生成できるクオリティの高さをぜひ体験してください。