まずは本書を手に取っていただき、誠にありがとうございます。
本書は、Babylon.js勉強会の活動の一環としてBabylon.jsをもっと広めたいという有志の熱意から生まれ、2023年5月の「技術書典14」で発売した「Babylon.js レシピ集 Vol.2」をもとに、加筆修正されました。
Babylon.jsについてのさまざまな知見が集まっていますので、ぜひ一読いただき「こんなこともできるんだ」と思っていただければ幸いです。また、ちょっとでも気になるなと思われたら、ぜひ Babylon.js 勉強会1 にも参加してみてください。
Babylon.js レシピ集 Vol.2 著者代表 / 藤原貴之
本書に記載された内容は、情報の提供のみを目的としています。したがって、本書を用いた開発、製作、運用は、必ずご自身の責任と判断によって行ってください。これらの情報による開発、製作、運用の結果について、著者はいかなる責任も負いません。
本書では、Babylon.jsの基本的な説明について一部省略することがあります。公式ドキュメント2や「Babylon.js レシピ集 Vol.1」3をご覧いただければ幸いです。
本書では、3次元形状をもつ図形について、以下のように定義しています。
・メッシュ:テクスチャや色はついておらず、単に形状がわかるもの(例:直方体、球)
・3Dモデル:メッシュにテクスチャや色がついていて、客観的に何かを認識できる
また、Playgroundを既知の情報として扱います。Playgroundとは、ブラウザで表示されるサイトです。
Babylon.jsのコードを記述すると動作確認ができます。
Playground上で保存された情報は公開されるので、誰でも確認できます。
本書に記載されている会社名、製品名などは、一般に各社の登録商標または商標、商品名です。会社名、製品名については、本文中では©、®、™マークなどは表示していません。
本章では、ChatGPTにBabylon.jsで3Dシーンの作成や開発の手助けをしてもらう例をいくつか紹介します。
ChatGPTプロンプトはGPT-3.5の言語モデルで動作するものもありますが、基本的にはGPT-4を推奨致します。
ChatGPTは、OpenAI社によって開発された対話型のAIのことです。GPTは、ChatGPTで使われる言語モデルのことで以下の略称となります。
・Generative : 生成型
・Pre-trained : 事前学習済み
・Transformer : トランスフォーマー(言語を理解し、文章を生成するためのAI技術)
意訳すると、「訓練された学習データからテキストを生成する変換器」といったところでしょうか。
ChatGPTは2023年4月時点では、GPT-3.5とGPT-4の言語モデルが公開されています。数字はバージョン情報のようなもので、数値が大きな程モデルの規模が大きく高性能といえるでしょう。
特徴 | GPT-3.5 | GPT-4 |
モデルサイズ |
175B(1750億) パラメータ |
非公開 |
米国司法試験の模擬試験 |
不合格 (受験者の下位10%) |
合格 (受験者のトップ10%) |
幻覚性(ハルシネーション) |
多い |
少ない (GPT-3.5に比べて40%低減) |
応答速度 | 速い | 遅い |
価格 | 無償 | 有償(月額20ドル) |
・出典:GPT-4 Technical Report1
百聞は一見に如かずということで、GPT-3.5と4の性能の違いを視覚的に表してみました。
以下は単純に、「Babylon.jsで雪だるまを作るサンプルを教えてください」とした結果です。比較しやすいよう、できあがった雪だるまを10体並べてみました。
GPT-4の方が、誤りの少ない安定した結果が得られることがわかるかと思います。
以下は、本章の筆者が触ってみて感じた、ChatGPTが「得意なこと」と「苦手なこと」になります。
・得意なこと
─サンプルコードの提示
─異なる言語やライブラリからの移植
─関数やヘルプの逆引き
─機能の違いの一覧化
─提案やアイデア等の提示
─ソースコードの解説
─バグの指摘や修正
・苦手なこと
─絵を描くこと(ChatGPTがテキスト用途のAIであるため)
─一度に多くの要望・条件を設定できない(設定しても何か忘れる)
─最新機能に関する情報の提供(2021年9月以降の情報を持たないため)
─同じものができない(毎回異なる結果が生成される)
ChatGPTは膨大な学習データの内容から、さまざまなサンプルコードを生成できます。しかし、あいまいな依頼だと自分が望むサンプルが得られない場合があります。基本的には、より具体的な指示をした方が望む結果が得られることが多いです。
本書ではBabylon.jsをテーマにしていますので、もう少しBabylon.js向きのテクニックを紹介したいと思います。
・Babylon.js向けのコードを教えてもらう際のコツ
─言語モデルはGPT-3.5ではなくGPT-4を使う
─提示してもらうコードをcreateScene関数に限定する
─できるだけ指示は具体的にする
─間違えそうな箇所や特別注意が必要な部分を事前に指摘しておく
─一度に多くの要望・条件を設定しすぎない(何回かに分けて修正依頼をしていく)
先ほどの「1.1.1 GPT-3.5とGPT-4の違い」の例にあるように、「Babylon.jsで雪だるまを作るサンプルを教えてください。」だけでもサンプルコードを提示してくれます。とはいえ、条件の指定がないと十人十色な回答をしてくるため、自分の想定している結果にならないことがあるでしょう。そのような場合は、追加の条件を指定すると結果が安定してきます。
たとえば、雪だるまは日本と海外ではスタイルが異なるため、どちらのスタイルを希望するかといった情報は事前に与えておく方がいいでしょう。
実行結果
雪だるまを作るサンプルの実行結果2
Babylon.jsで雪だるまを作るサンプルを教えてください。
条件は以下とします。
・雪だるまは日本式(3段ではなく2段)でお願いします。
・雪だるまの各パーツを洗い出してください。
・洗い出した各パーツはツリー構成で教えて下さい。形状と色も記載してください。
・コードはcreateScene関数の部分を提示ください。
① 雪だるまは日本式(3段ではなく2段)でお願いします。
→ 雪だるまは日本と西洋でスタイルが違います。日本式に限定したい場合は、そのように指定するのがいいでしょう。
② 雪だるまの各パーツを洗い出してください。
洗い出した各パーツはツリー構成で教えて下さい。形状と色も記載してください。
→ 事前にパーツの洗い出しをお願いすることで、ミスを減らすことができるようです。レシピの材料を揃えることに似ていますね。
③ コードはcreateScene関数の部分を提示ください。
→ Babylon.js Playgroundで使うコードがほしい場合は、この条件を加えるといいでしょう。
以下のサンプルコードは、Babylon.jsを使用して日本式の雪だるまを作成するものです。
雪だるまの構成は、以下の通りです。
・体 (body)
・下半身 (lowerBody) : 球体 (sphere) - 白色 (white)
・上半身 (upperBody) : 球体 (sphere) - 白色 (white)
・顔 (face)
・目 (eyes)
・左目 (leftEye) : 球体 (sphere) - 黒色 (black)
・右目 (rightEye) : 球体 (sphere) - 黒色 (black)
・鼻 (nose) : 円錐 (cone) - 橙色 (orange)
・口 (mouth) : 線 (line) - 黒色 (black)
以下に、Babylon.js Playgroundで動作するコードを記載します。
(以下省略※)
※実際のソースコードと実行結果は下記URLを参照ください。
https://playground.babylonjs.com/#39K7GF
筆者の主観ですが、物理演算はChatGPTと相性がいいと感じます。物理世界の中で実現したい内容を話し言葉で伝えると、そのように動いてくれるためです。
実行結果
簡単な物理演算のサンプルの実行結果3
Babylon.jsの簡単な物理演算のサンプルを教えて下さい。
条件は以下とします。
・ボールをひとつ床の上から落下させてください。
・コードはcreateScene関数の部分を提示ください。
Babylon.jsでは、物理演算を実現するためにAmmo.jsやCannon.jsなどの外部物理エンジンを利用できます。
この例では、Cannon.jsを使って床とボールの物理シミュレーションを実行します。
以下は、Babylon.js Playgroundで実行できる簡単なサンプルコードです。
このコードでは、床とボールを配置し、ボールが落下するシーンを作成します。
(以下省略※)
※実際のソースコードと実行結果は下記URLを参照ください。
https://playground.babylonjs.com/#3ZR98C
Babylon.jsでは、いくつかの機能でシェーダが使えます。ChatGPTにシェーダのサンプルを提示してもらう際には、どの機能のことなのか事前に指定しておくのがいいでしょう。
Babylon.jsの機能名 | 対応するシェーダ |
Shader Material | 頂点シェーダおよびフラグメントシェーダが使用可能 |
Procedural Texture | テクスチャーにフラグメントシェーダが使用可能 |
Post Process | エフェクトにフラグメントシェーダが使用可能 |
今回は、Post Processでシェーダを使う際のサンプルを教えてもらおうと思います。
実行結果
簡単なシェーダのサンプルの実行結果4
Babylon.jsでモザイクのポストエフェクトを追加するサンプルを教えて下さい。
条件は以下とします。
・シェーダは事前にShadersStoreに格納してから使用してください。
・コードはcreateScene関数の部分を提示ください。
Babylon.js Playgroundでモザイクのポストエフェクトを追加するサンプルを以下に示します。
まず、シェーダをShadersStoreに格納してから、ポストエフェクトを適用します。
(以下省略※)
※実際のソースコードと実行結果は下記URLを参照ください。
https://playground.babylonjs.com/#6LTTVJ
Babylon.jsのパーティクルの機能は、炎や煙といった効果で使うことができます。ここでは、火山の噴火と噴煙にパーティクルを使うサンプルを教えてもらおうと思います。
パーティクルはパラメータが多く、一度に希望する効果を実現するサンプルを返してくれるのは希です。まずはサンプルを動かして、それに対して追加で修正依頼して調整するのがいいでしょう。
実行結果
火山のサンプルおよび修正依頼後の実行結果5
Babylon.jsで火山と噴火を表現するサンプルを教えてください。
条件は以下とします。
・火山はパーティクルを用いて噴火と噴煙を表現してください。
・噴火の炎のテクスチャはtextures/flare.pngを使用してください。
・噴煙のテクスチャはtextures/cloud.pngを使用してください。
・コードはcreateScene関数の部分を提示ください。
Babylon.jsを使用して、火山と噴火を表現するサンプルコードを以下に示します。
このコードは、Babylon.js Playgroundで動作することが前提です。
要求された条件に従って、パーティクルを使用して噴火と噴煙を表現し、指定されたテクスチャを使用しています。
Q1:煙が黒すぎるようです。色を修正するにはどうしたらいいですか?
A1:煙の色を修正するには、smokeParticleSystem.color1とsmokeParticleSystem.color2の値を変更します。
Q2:噴煙を左から右方向に風で流されるように調整するには、どうしたらいいですか?
A2:噴煙が風に流されるようにするには、パーティクルシステムのgravityプロパティを変更して、風の影響をシミュレートします。
Q3:噴煙が上昇する勢いが強いです。弱くするにはどうしたらいいですか?
A3:噴煙の上昇速度を調整するには、smokeParticleSystem.direction1およびsmokeParticleSystem.direction2のy成分を変更してください。これにより、噴煙の上昇速度が変わります。
※実際のソースコードと実行結果は下記URLを参照ください。
https://playground.babylonjs.com/#SSJPF1
ChatGPTはテキストベースのAIですが、ある程度グラフィカルなゲームも作ることができるようです。とはいえ、提案してくれるのはあくまでもサンプルコードのレベルですので、あまり過度な期待はしない方がいいです。
実行結果
インベーダ風ゲーム6ブロック崩し風ゲーム7コイン落としゲーム8
Babylon.jsを使ったインベーダー風のゲームのサンプルを教えてください。
以下の条件を満たすようにしてください。
・敵キャラクターを5行10列に配置してください。
・各行の敵キャラクターにカラフルな色をつけてください。
・マウス操作ではなく、キーボード操作でプレイヤーを動かせるようにしてください。
・キーボードの「a」キーまた「←」キーで左に移動、「d」または「→」キーで右に移動し、「スペース」キーでレーザーを発射できるようにしてください。
・レーザーが敵に当たったら、敵キャラクターを破壊するようにしてください。
・Babylon.jsでブロック崩しサンプルを教えてください。
・操作はキーボードで行えるようにしてください。
・キーボード操作がカメラに影響してしまう可能性があるため、カメラのコントロールを無効にしてください。
・ブロックは5行10列で配置ください。
Babylon.jsの物理演算の機能を使ったコイン落としゲームのサンプルを教えてください。
three.jsはBabylon.jsと同様に、Webで3Dグラフィックスを扱うためのJavaScriptライブラリです。ChatGPTがthree.jsとBabylon.jsの違いをどの程度知っているか、聞いてみることにしました。まずは、基本機能であるメッシュとマテリアルについて相違点を聞いてみました。
three.jsとBabylon.jsで使えるメッシュを比較できるよう、表形式で一覧化してください。
それぞれ公式ドキュメントにある記載を参考にお答えください。
three.jsはクラス名、Babylon.jsはMeshBuilderのメソッド名で記載してください。
関数の引数は記載不要です。
こちらが、Three.jsとBabylon.jsのそれぞれで使用可能なメッシュの表形式の一覧です。
公式ドキュメントを参考にしましたが、2021年9月時点の情報であるため、最新の情報とは異なる可能性があります。
表1.3: three.jsとBabylon.jsのメッシュの違い
Three.js | Babylon.js |
BoxGeometry | CreateBox |
CircleGeometry | CreateDisc |
ConeGeometry | CreateCylinder |
CylinderGeometry | CreateCylinder |
DodecahedronGeometry | CreatePolyhedron |
ExtrudeGeometry | ExtrudeShape |
IcosahedronGeometry | CreatePolyhedron |
LatheGeometry | CreateLathe |
OctahedronGeometry | CreatePolyhedron |
ParametricGeometry | N/A |
PlaneGeometry | CreatePlane |
PolyhedronGeometry | CreatePolyhedron |
RingGeometry | CreateTorus |
ShapeGeometry | ExtrudeShape |
SphereGeometry | CreateSphere |
TetrahedronGeometry | CreatePolyhedron |
TextGeometry | N/A |
TorusGeometry | CreateTorus |
TorusKnotGeometry | CreateTorusKnot |
TubeGeometry | CreateTube |
関数の引数は記載していませんが、必要に応じて公式ドキュメントを参照してください。
Three.js: https://threejs.org/docs/index.html
Babylon.js: https://doc.babylonjs.com/divingDeeper/mesh/creation
同様にマテリアルについても表形式で一覧化をお願いできますか?
もちろんです。以下に、Three.jsとBabylon.jsのそれぞれで使用可能なマテリアルの表形式の一覧を示します。
公式ドキュメントを参考にしましたが、2021年9月時点の情報であるため、最新の情報とは異なる可能性があります。
表1.4: three.jsとBabylon.jsのマテリアルの違い
Three.js | Babylon.js |
MeshBasicMaterial | StandardMaterial |
MeshDepthMaterial | N/A |
MeshDistanceMaterial | N/A |
MeshLambertMaterial | PBRMaterial |
MeshMatcapMaterial | N/A |
MeshNodeMaterial | N/A |
MeshNormalMaterial | N/A |
MeshPhongMaterial | SpecularMaterial |
MeshPhysicalMaterial | PBRMetallicRoughnessMaterial |
MeshStandardMaterial | PBRMaterial |
MeshToonMaterial | N/A |
LineBasicMaterial | LineMaterial |
LineDashedMaterial | N/A |
PointsMaterial | PointMaterial |
RawShaderMaterial | ShaderMaterial |
ShaderMaterial | ShaderMaterial |
ShadowMaterial | N/A |
SpriteMaterial | N/A |
関数の引数は記載していませんが、必要に応じて公式ドキュメントを参照してください。
Three.js: https://threejs.org/docs/index.html
Babylon.js: https://doc.babylonjs.com/divingDeeper/materials
見たところ、対応は概ね合っているように思いました。これだけ知っているのであれば、three.jsからBabylon.jsへの移植もできそうですね。
先ほどの「1.3.1 three.jsとBabylon.jsの違いを教えてもらおう」で見てきたように、ChatGPTはthree.jsとBabylon.jsがどのように対応しているのか理解していそうです。そこで、three.jsからBabylon.jsにソースコードの移植が行えるか試してみました。
移植結果
three.js→Babylon.jsへサンプルを移植する実験9
以下は、three.jsでいくつかのメッシュを表示するサンプルです。
Babylon.jsの場合はどうなるか教えてもらえますか?
Babylon.js Playgroundで動作する形式でお願いします。
(以下省略※)
以下は、Babylon.jsを使用して同様のメッシュを表示するサンプルコードです。
Babylon.js Playgroundで動作するように書かれています。
(以下省略※)
※実際のソースコードと実行結果は下記URLを参照ください。
変換元のthree.jsのサンプル
https://cx20.github.io/webgl-test/examples/threejs/primitive/
変換後のBabylon.jsのサンプル
https://playground.babylonjs.com/#G3R62V#1
ぱっと見は合っていそうですね。違うところとしては、
・球体の大きさ
・テクスチャの向き
・トーラスの向き
と、いったところでしょうか。
球体についてはthree.jsの場合、大きさを決める単位が「半径」、Babylon.jsの場合は「直径」となっているため、そのあたりの違いが正しく学習できていないように思いました。
ChatGPTはテキストに特化したAIであるため、ソースコードを読み解くのも得意なようです。試しに、「1.2.3 シェーダの例」で教えてもらったシェーダコードについて解説してもらいました。
以下は、Babylon.jsのモザイクのポストエフェクトで使用されているシェーダです。
シェーダコードについて解説をお願いできますか?
```
precision highp float;
varying vec2 vUV;
uniform sampler2D textureSampler;
uniform vec2 screenSize;
uniform float mosaicSize;
void main(void) {
vec2 uv = vUV;
vec2 mosaicUV = vec2(
floor(uv.x * screenSize.x / mosaicSize),
floor(uv.y * screenSize.y / mosaicSize));
vec2 pixelUV = (mosaicUV * mosaicSize) / screenSize;
vec4 color = texture2D(textureSampler, pixelUV);
gl_FragColor = color;
}
```
このシェーダは、Babylon.jsのモザイクのポストエフェクトに使用されているフラグメントシェーダです。
フラグメントシェーダは、ピクセルごとに色情報を計算することで画像にエフェクトを適用します。
このコードでは、モザイクエフェクトが適用されており、各ピクセルがモザイクの一部として扱われます。
コードの各行の説明は以下の通りです。
precision highp float;
// 浮動小数点数の精度を高精度 (high precision) に設定します。これにより、シェーダ内での計算の精度が向上します。
varying vec2 vUV;
// 頂点シェーダからフラグメントシェーダへの情報の受け渡しを宣言します。この場合、テクスチャ座標(UV座標)が渡されます。
uniform sampler2D textureSampler;
// テクスチャサンプラーの宣言です。これは、元のテクスチャ(画像)を参照するために使用されます。
uniform vec2 screenSize;
// 画面のサイズを格納する2次元ベクトルです。これは、シェーダ外部から渡されます。
uniform float mosaicSize;
// モザイクのサイズを制御する浮動小数点数です。これもシェーダ外部から渡されます。
void main(void) {
// フラグメントシェーダのメイン関数の開始です。
vec2 uv = vUV;
// 頂点シェーダから受け取ったテクスチャ座標(UV座標)をローカル変数uvに代入します。
vec2 mosaicUV = vec2(
floor(uv.x * screenSize.x / mosaicSize),
floor(uv.y * screenSize.y / mosaicSize));
// モザイク化されたUV座標を計算します。これにより、各ピクセルがモザイクの一部になります。
vec2 pixelUV = (mosaicUV * mosaicSize) / screenSize;
// モザイク内のピクセル座標を計算します。これは、モザイク化されたUV座標を元のUV座標に戻す際に使用されます。
vec4 color = texture2D(textureSampler, pixelUV);
// 元のテクスチャからモザイク内のピクセルの色を取得します。
gl_FragColor = color;
// 計算された色をフラグメント(ピクセル)の最終色として設定します。
ChatGPTは公式ドキュメントのほかにもQAサイトも学習対象にしているらしく、よくあるエラーの原因について対処方法も理解しているようです。今回は、Babylon.jsでメモリリークが発生するケースについて、原因と対処方法を聞いてみました。
以下の関数はBabylon.jsでGUI部品を生成する関数です。
この関数を複数回呼び出した場合、メモリリークが発生します。
メモリリークを解消するにはどうしたらいいでしょうか?
```
function createInfoButton(pickedMesh){
let guiCanvas
= BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
let infoButton
= BABYLON.GUI.Button.CreateSimpleButton(
"infoButton", "ID:"+ pickedMesh.id);
infoButton.width = "300px"
infoButton.height = "80px";
infoButton.top = "50px";
infoButton.color = "white";
infoButton.cornerRadius = 5;
infoButton.background = "green";
infoButton.verticalAlignment
= BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
infoButton.horizontalAlignment
= BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
guiCanvas.addControl(infoButton);
}
```
この関数にはいくつかの問題があるため、メモリリークが発生しています。以下の手順で解決できます。
1. guiCanvasをグローバル変数に変更し、関数が呼び出されるたびに新しいAdvancedDynamicTextureインスタンスを生成しないようにします。
2. 以前に作成したinfoButtonを削除する処理を追加します。
修正後のコードは以下のようになります。
```
let guiCanvas = null;
let infoButton = null;
function createInfoButton(pickedMesh){
if (guiCanvas === null) {
guiCanvas
= BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
}
if (infoButton !== null) {
guiCanvas.removeControl(infoButton);
}
infoButton
= BABYLON.GUI.Button.CreateSimpleButton(
"infoButton", "ID:"+ pickedMesh.id);
infoButton.width = "300px"
infoButton.height = "80px";
infoButton.top = "50px";
infoButton.color = "white";
infoButton.cornerRadius = 5;
infoButton.background = "green";
infoButton.verticalAlignment
= BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
infoButton.horizontalAlignment
= BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
guiCanvas.addControl(infoButton);
}
```
この変更により、guiCanvasとinfoButtonは関数が呼び出されるたびに新しいインスタンスを生成せず、以前のinfoButtonは削除されるため、メモリリークが解消されます。
本章のタイトルは「ChatGPTで気軽にBabylon.jsを体験してみよう」ということでしたが、いかがでしたでしょうか。ChatGPTを使うことで、Babylon.jsを利用する際のハードルがかなり下がったと感じていただけたなら幸いです。
ChatGPTは登場してまだ半年足らず(2023年4月時点)の技術ですが、一般向けのメディアでも紹介され、多くの人が興味を持っているのではないでしょうか。
今回紹介したテクニックは、ChatGPTの利用例のごく一部です。ほかにも本書で紹介しきれなかった利用例を公開していますので、興味がありましたら、scrapbox.ioにあるBabylon.js Tips集10を参照ください。QRコードより当該ページにアクセスいただけます。
今後も、何かよさそうな利用例を発見したら公開していきたいと思います。