「Babylon.js」という3Dエンジンを使って、WEBブラウザに輪郭線付の3Dモデルを表示する方法を紹介します。
方向の操作ボタンを付けたり、WEBサイトに埋め込んでビューアのように使えます。
3DCADのような見た目になるので、機械要素などの構造を伝えやすいと思います。
動作デモ
この記事では、「Babylon.js」という3Dエンジンを使い、以下のようなビューアを作ります。
- 右側は、ホームや各方向を表示するための操作ボタンです。
- マウスでグルグルできます。
▼ 上のデモが表示されていない場合、別ウィンドウで表示できます。
「3DCADっぽく表示する」というコンセプトで、以下のように調整しました。
- 3Dモデルを輪郭線付で表示する
- HOME、側面表示などの方向操作ボタンを付ける
- マテリアル(素材の見た目)はあえてシンプルな単色にする
このデモで使った言語は、主にJavaScript、HTML、CSSです。記事の最後に、製作時に読んだ本を紹介しています。
「Babylon.js」とは
今回のビューアが実現できたのは、「Babylon.js」という3Dエンジンのおかげです。
「Babylon.js」は、3Dゲームなどを開発するための、オープンソースのJavaScript フレームワークです。
Microsoftが提供していて、2022年の5月には5.0がリリースされています。
▼ 公式サイトです。ページの最下部で、BABYLON.JSを使ったデモも見られます。
最終的に作るファイル
この記事のビューアは、以下の2つだけのファイルで実現できます。
コードの中に書く項目については、後述します。
- HTMLファイル
- 3Dモデル(.glTF)
▼ 動作デモのコードは、以下のGithubに置いています。
開発環境
今回の記事の作成には、以下のソフトウェアを使いました。
No. | ソフトウェア名 | 分類 | 作業内容 |
---|---|---|---|
1 | Visual Studio Code | テキストエディタ | コードを書く |
2 | Live Server | Vscodeの拡張機能 | ローカルサーバーを起動する。1クリックで実行できる |
3 | FUSION 360 | 3DCAD | 3Dモデルを作る |
4 | Blender 3.3.1 | CGソフト | 3Dモデルのメッシュを調整したり、.glTFにエクスポートする |
では、これから具体的な作業手順を書いていきます。
3Dモデルを用意する
まず、ビューアに表示する3Dモデルを作ります。
この記事ではFusion 360とBlenderを使っていますが、最終的に.gltfという拡張子のファイルにエクスポートできればソフトは問いません。
モデリング後、.obj へ変換
- 使用ソフト:Fusion 360
▼ 3Dモデルができたら、OBJファイルとしてエクスポートします。最終的に欲しい.gltfへのエクスポートは、後からBlenderで行います。
ファイル → エクスポート → OBJファイルを選択 → 任意の保存場所を指定 → エクスポート ボタン押下で、エクスポートできます。
Blenderにインポートする
- 使用ソフト:Blender
Blenderに、先ほどFusion 360で作ったOBJファイルをインポートします。
- ファイル → インポート → Wavefront(.obj) をクリックし、ファイルを指定して読み込みます。
メッシュを軽量化する
- 使用ソフト:Blender
次に、ファイルサイズ削減のため、メッシュを軽量化します。Blenderの デシメートモディファイアー という機能を使うと簡単に行えます。
- 対象の物体を選択し、右下のプロパティパネルのスパナアイコンをクリックします。
- モディファイアーを追加 → 生成の列より「デシメート」を選択。
- 比率に任意の数値をいれます。今回は「束ねる」及び比率は「0.25」にしておきました。(設定欄左下の「面数」の値が変わります)
比率に応じてファイルサイズが軽くなるので、モデルに応じて決めて下さい。 - 「デシメート」の右の下向き三角をクリックし、「適用」を選択します。
あんまりやりすぎると、ガビガビボコボコになってしまうので、ご注意ください
▼ Blender デシメート モディファイアーのドキュメントです
(必要に応じて)分離する
- 使用ソフト:Blender
デフォルトでは、オブジェクトが一体化した状態だと思います。
▼ もし、部品ごとにオブジェクトを分けたい場合は、以下の方法で分離可能です。
- Tabキーを押して、「編集モード」に切り替えます。
- Aキーで全てを選択 → Pキー →「構造的に分離したパーツで」を選択すると、分離できます。
- 分離が終わったら、Tabキーを押すと、「編集モード」から「オブジェクトモード」に戻ります。
.glTFへエクスポートする
- 使用ソフト:Blender
軽量化などの調整が済んだら、最後にエクスポートします。
- エクスポートしたいオブジェクトをすべて選択し、ファイル → エクスポート → glTF 2.0 をクリックします。
- 保存場所、フォーマット(glTF embedded)、内容などを適宜指定したら、右下の glTF 2.0 をエクスポート ボタンをクリックします。
- 今回は、フォーマットは「glTF embedded」、内容は「選択したオブジェクト」を指定しました。
これで、.glTFファイルの作成が完了しました。
コードの全体像
次に、ビューアを作るためのコードを書いていきます。
▼ 今回書いたコードの全体像はこんな感じです。
- 最終的にはHTMLファイルを作ります。
<head>
内でCSSの記述とbabylonのパッケージのインポートを行います。<body>
の中に、操作ボタンのHTMLタグと、babylon.jsのためのjavascriptコードを記述します。
書いたコード
▼ 動作デモのコードは、以下のGithubのdocsフォルダに置いています。
使うツール
テキストエディタのVisual Studio Codeと、拡張機能のLive Serverを使うと快適です。
開発の際は、コードを書いて保存し、都度、HTMLファイルを実行してブラウザで動作確認する……という作業を繰り返します。ただしローカル環境では、ただ実行するだけでは正常に動作しないので、ローカルサーバーを立てる必要があります。
そこで、拡張機能のLive Serverを使うと、ポチっと一回クリックするだけで、ローカルサーバーを通してファイルを実行できるようになります。
▼ Live Serverを使っている様子です。エディタ右下のGo Liveボタンをクリックすると、サーバーを立てた状態で、ブラウザが立ち上がります。
babylon.js のためのコード
コードの主要な部分について、説明します。
- HTMLのひな形を用意する
- 各種パッケージをインポートする
- 見せたいものは、createScene関数の中へ
- カメラを設置
- カメラのオート調整機能を適用する
- ライトを設置する
- 3Dモデルを読み込む
- 子メッシュ(部品)を取得して、効果を適用する
- 輪郭はenableEdgesRendering メソッドで
- 部品全体から境界点を取得する
- 操作ボタンを作る
- 完成したコード
HTMLのひな形を用意する
初めてBabylon.jsでの3Dシーン作成に取り組む場合、そもそも何をどこに書けばよいか戸惑いますよね。
いきなり面倒に思われるかもしれませんが、ご安心ください。公式ドキュメントにテンプレートが用意されているので、基本的には、3Dシーンに関する記述(createScene関数の中身)だけに集中すればOKです。
▼ HTMLテンプレートです。
ページ下部には、「ココは変える必要のない部分」のようにコードが機能ごとに色分けされているので、分かりやすいです。
▼ 動作に必要なコードが含まれたHTMLファイルは、以下の「Playground」でも生成可能です。
Playground はbabylon.js専用の開発環境で、createScene関数の中身を書くだけで、シーンを作れます。
HTMLファイルは、上部メニューのダウンロードボタンをクリックすると、zipファイルとしてダウンロードできます。
▼ Playgroundの使い方
各種パッケージをインポートする
まずは、<head>
タグ内に、Babylon.jsでの3Dシーン作成に必要なパッケージをインポートしておきます。
必要に応じて、CDNからインポートできます。
▼ 今回は、以下のパッケージをインポートしました。
<!-- Babylon.js Core -->
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<!-- Babylon.js All Official Loaders (OBJ, STL, glTF) -->
<script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.js"></script>
▼ 用意されているパッケージの一覧は、以下のドキュメントをご覧ください。
見せたいものは、createScene関数の中へ
<script>
タグの中でcanvasや3D engineのオブジェクトを生成し、見せたいものはcreateScene関数の中に書いていきます。
▼ こんな感じ
<script>
const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);
const createScene = function () {
//この中に、カメラ設定、ライト、3dモデルなど見せたいものについて記述する。
};
//後略
</script>
カメラを設置
babylon.jsのプロジェクトでは、必ずシーンにカメラを設置せねばなりません。色々なカメラが用意されているので、目的に応じたカメラを呼び出して使います。
▼ babylon.jsで使えるカメラについては、以下のドキュメントをご覧ください。
今回は「3Dモデルをグルグル回すビューアを作る」のが目的なので、軌道カメラのArcRotateCameraを設置しました。
▼ 今回のコードはこんな感じです。名前、カメラ角度、カメラ半径、位置、所属するシーンを引数にしています。
const camera = new BABYLON.ArcRotateCamera("Camera", (135 / 180) * Math.PI, (60 / 180) * Math.PI, 50, BABYLON.Vector3.Zero(), scene); //カメラを生成
camera.attachControl(canvas, true); //生成したカメラをcanvasに接続
このArcRotateCameraクラス詳しい仕様は、以下のドキュメントをご覧ください。
カメラのオート調整機能を適用する
上記の方法でカメラを設置するだけだと、読み込む3Dモデルの大きさに合わせて、毎回カメラの半径などを引数に入力する必要があり、手間がかかります。
そこでFraming Behavior という機能を使えば、カメラの半径や原点位置などを自動的に調整できるようになります。
▼ useFramingBehaviorをtrueにすれば、有効になります。
camera.useFramingBehavior = true;
そして、各種プロパティに値をセットしていきます。
▼ 今回使ったのは、radiusScale というプロパティです。カメラ半径(radius)の数値は画面に対するオブジェクトの大きさに関わるので、ここに係数を入れておきます。
camera.framingBehavior.radiusScale = 0.8;
▼ 動作確認として、PlaygroundにBlenderでかいた3Dモデルを表示してみました。
- 左は、FramingBehaviorが無効です。オブジェクトが遠くに表示されてしまっています。
- 右は有効な状態です。オブジェクトの見え方が、ちょうどよくなりました。
動作している様子は、こちらのPlaygroundで確認できます。
▼ 設定できるプロパティの詳細は、以下のドキュメントをご覧ください。
ライトを設置する
次に、オブジェクトを照らすためのライトを設置します。光が無いと、物体が真っ黒なカタマリになってしまします。
▼ ライトが無い場合
Babylon.jsには複数のライトが用意されていますが、今回は半球ライト(HemisphericLight)を使いました。
▼ 以下のコードで設置できます。※ 半球ライトのプロパティなど仕様はこちら
//照明の設定
const light = new BABYLON.HemisphericLight("hemiLight", new BABYLON.Vector3(0, 1, 0), scene);
light.diffuse = new BABYLON.Color3(1, 1, 1); //メインライトの色
light.groundColor = new BABYLON.Color3(150 / 255, 150 / 255, 150 / 255);//メインとは反対側
light.intensity = 1;
▼ ライトを設置したら、こうなりました
▼ Babylon.jsで使えるライトについては、以下のドキュメントをご覧ください。
3Dモデルを読み込む
▼ 3Dモデルは、以下の1行のコードでインポート可能です。例えば「scenesというフォルダに入っているtest.gltfというファイル」ならこんな感じで。
BABYLON.SceneLoader.ImportMeshAsync("model_name", "scenes/", "test.gltf", scene);
▼ 3Dモデルのインポートに関して詳しくは、以下のドキュメントをご覧ください。
▼ 3Dモデルのインポートが完了しました。
とりあえず3Dを表示できましたね。以降は、輪郭線を付けたり見え方を調整したりしていきます。
子メッシュ(部品)を取得して、効果を適用する
先ほど読み込んだ3Dモデルは、3つの部品(歯車2つとモーター1つ)で構成されています。
しかしインポートした直後は_root_
というノードに子メッシュ(部品)が保存されている状態になっているので、_root_
から子メッシュを取得して、それぞれに対して処理を行います。
▼ こんな感じで、処理を行いました。
- 子メッシュは、getChildMeshesメソッドで取得できます。子メッシュの配列が返ってくるので、その要素に対し、forEachメソッドで順次処理を行います。
- ついでに、forEachの中でsetParentも実行しておきました。取得した子メッシュを、2行目で作った”parent”という親メッシュに収容しておきます。
//子メッシュの収容先を作っておく
let parent = new BABYLON.Mesh("parent", scene);
//_root_nodeを取得する
const rootMesh = res.meshes[0];
rootMesh.getChildMeshes(false).forEach(node => {
node.enableEdgesRendering(Math.cos(Math.PI / 4));//メッシュに輪郭線を描画する
node.edgesWidth = 10;//線の太さを指定
node.edgesColor = new BABYLON.Color4(0, 0, 0, 1); //線の色を指定
node.edgesShareWithInstances = true;
node.setParent(parent); //子メッシュの収容先( "parent" )を指定する
});
▼ .glTF File Loaderについての説明です。読み込み時の仕様などを確認できます。_root_
nodeに子メッシュが保存されている旨も、ここに書かれていました。
▼ AbstractMesh クラスの仕様です。使えるプロパティやメソッドを確認できます。
輪郭は enableEdgesRendering メソッドで
▼ 以下のコード(上のコードの6行目)のenableEdgesRendering
メソッドにより、輪郭線を描画できるようになります。
node.enableEdgesRendering(Math.cos((45 / 180) * Math.PI)); //法線ベクトル間の角度を45°に設定
引数は、2つの面の法線ベクトルの内積です。法線ベクトル間の角度をθとすると、内積は cosθ になります。
例えば、上のコードのように法線ベクトル間の角度が45°ならば、内積はcos45°なので、引数は≒ 0.707になります。
内積が1 (= cos 0°)に近づくと、描画される線は多くなります。
▼ enableEdgesRendering
メソッドの詳細です。Playgroundで動作を確かめることもできます。
部品全体から境界点を取得する
先述の「カメラのオート調整機能を適用する」で、Framing Behaviorというカメラ調整機能を有効にしました。そして、「子メッシュ(部品)を取得して、効果を適用する」では、取得した子メッシュ達を”parent“という親メッシュに収容しました。
しかし、いざ camera.setTarget(parent, true);
でカメラのターゲットをparentにセットしても、見え方が変です。
▼ 全体が良い感じにズームされるはずが、画面目一杯にオブジェクトが接近してしまっています。Framing Behaviorの対象が、一部分のみになっているようです。
そこで、子メッシュ達を収容したparentの境界情報を更新しました。
▼ すると、部品全体の大きさが認識され、画面にちょうどよくフィットするようになりました。
▼ 使うメソッドや処理の流れは、以下で詳しく説明されています。このドキュメントは「複数部品全体を包むバウンディングボックスを描く」という内容ですが、今回の用途でもピッタリ有効だったので、そのまま利用させて頂きました。
操作ボタンを作る
▼ すぐにホームポジションや各側面などを見られるよう、ボタンを設けました。今回は、HTML/CSSを使って作成しました。
HTMLとCSSでボタンを作り、htmlにidを振っておきます。そして、babylon.js側でJavaScriptのDOMを使ってボタンをクリックした際の動作を書きました。
▼ 例えば、ホームボタンのHTMLとJavaScript部分を抜き出すとこんな感じです。(CSS部は省略)
<!-- ホームボタンのHTML部分 -->
<div class="btn homebutton" id="home"><i class="fas fa-home icon"></i></div>
// ホームボタンのJavaScript部分
const home = document.getElementById("home");
home.addEventListener("click", () => {
camera.restoreState(); //保存したカメラの状態を復元する
});
なお、babylon.jsにGUIを追加する方法は、複数あります。専用のGUIライブラリを使って、3Dのボタンなども作れます。ただ今回の用途には合わないので、作りやすくて見た目をカスタマイズしやすいHTML/CSSを選びました。
▼GUIの作り方の詳細は、以下のドキュメントをご覧ください。
……少し長くなりましたが、これで、完成です!用意された既存のメソッドを組み合わせるだけで、手軽に実現できました。
完成したコード
▼ 動作デモのコードは、以下のGithubのdocsフォルダに置いています。
▼ 動作デモ
埋め込む場合
既存のサイトに埋め込む場合は、以下のような感じでiframeタグを使えば可能です。
<iframe src="filename.html" title="title" scrolling="no" frameborder="no"></iframe>
▼ 埋め込んだ場合のデモサイトです。
参考文献
Babylon.js について
- The Very First Step | Babylon.js Documentation
https://doc.babylonjs.com/journey/theFirstStep
題名の通り、最初の第一歩としてのチュートリアルです。コードの動作結果をすぐに確認できるオンライン開発環境「Playground」を使いながら、丁寧に段階を踏んで解説が進みます。まずはここから読み始めました。ごくシンプルな課題を触ったり眺めたりしているうちに、なんとなく馴染んできます。 - Introduction to Babylon.js Features | Babylon.js Documentation
https://doc.babylonjs.com/features/introductionToFeatures
具体的な機能についてのチュートリアルです。簡単な課題を通して、外部からの3Dデータの読み込みやカメラの追加など、Webでの3D表現に必須な機能の実現方法を体験できます。 - Diving Deeper | Babylon.js Documentation
https://doc.babylonjs.com/features/featuresDeepDive
各機能についての詳細マニュアルです。アニメーション、サウンド、カメラなどの項目別に、概要やAPIの使い方などを確認できます。
JavaScript/HTML/CSS
- HTML リファレンス – HTML: HyperText Markup Language | MDN
https://developer.mozilla.org/ja/docs/Web/HTML/Reference
HTMLのリファレンスだけではなく、学習コンテンツとしても重宝します。実行して動作を確認できるようになっているので、理解がスムーズで有難いです。 - JavaScript リファレンス – JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference
こちらは、上記のJavaScript版です。こちらも実行して結果を確認しながら読み進められるので、分かりやすいです。 - CSS リファレンス – CSS: カスケーディングスタイルシート | MDN
https://developer.mozilla.org/ja/docs/Web/CSS/Reference
同じく、CSSのリファレンスです。
おすすめ本
Babylon.jsで扱うJavaScript、HTML、CSSについて、以下の書籍を手元に置いて取り組みました。これらの言語はオンラインのドキュメントが充実していますが、紙の書籍があるとさっと確認しやすく、学習が捗りました。
▲ 30 mmほどの分厚い本です。わからないことが出ると、事典のように都度参照していました。
1冊通すとJavaScriptの基礎を体系的に学べますが、ボリュームが大きいので時間がかかってしまい、やりたいことに取り組むまでに時間がかかってしまうかもしれません。
私の場合は、まず1~3章を読み、JavaScriptの開発環境の導入や概要について学びました。その後Babylon.jsのチュートリアルを読み、不明な文法が出てきたら都度調べる、という方法を取りました。
▲ HTML/CSSの記述の際に、都度参照しました。タグやプロパティの説明だけではなく、文法について基礎の解説もあり、読み物としても役立つ便覧です。
動画版
この記事のダイジェスト動画を作りました。5分半ほどです。(注:音声あり)
関連記事
▼ こちらは、別のフレームワークの記事です。数行のhtmlタグだけで手軽にビューワを作れます。