PR

ブラウザに3Dモデルを輪郭線と表示。CADっぽいビューアを作る方法【babylon.js】

3D CG

「Babylon.js」という3Dエンジンを使って、WEBブラウザに輪郭線付の3Dモデルを表示する方法を紹介します。
方向の操作ボタンを付けたり、WEBサイトに埋め込んでビューアのように使えます。

3DCADのような見た目になるので、機械要素などの構造を伝えやすいと思います。

スポンサーリンク

動作デモ

この記事では、「Babylon.js」という3Dエンジンを使い、以下のようなビューアを作ります。

  • 右側は、ホームや各方向を表示するための操作ボタンです。
  • マウスでグルグルできます。

▼ 上のデモが表示されていない場合、別ウィンドウで表示できます。

Babylon.js で作るCADっぽいシンプルビューア サンプル

「3DCADっぽく表示する」というコンセプトで、以下のように調整しました。

  • 3Dモデルを輪郭線付で表示する
  • HOME、側面表示などの方向操作ボタンを付ける
  • マテリアル(素材の見た目)はあえてシンプルな単色にする

このデモで使った言語は、主にJavaScript、HTML、CSSです。記事の最後に、製作時に読んだ本を紹介しています。

「Babylon.js」とは

今回のビューアが実現できたのは、「Babylon.js」という3Dエンジンのおかげです。
「Babylon.js」は、3Dゲームなどを開発するための、オープンソースのJavaScript フレームワークです。

Microsoftが提供していて、2022年の5月には5.0がリリースされています。

Babylon.js 5.0: Key Engine Advancements – Part 3
Our mission is to create it one of the most powerful, beautiful, and simple web rendering engines in the world. The late...

▼ 公式サイトです。ページの最下部で、BABYLON.JSを使ったデモも見られます。

Babylon.js: Powerful, Beautiful, Simple, Open - Web-Based 3D At Its Best
Babylon.js is one of the world's leading WebGL-based graphics engines. From a new visual scene inspector, best-in-class ...

最終的に作るファイル

この記事のビューアは、以下の2つだけのファイルで実現できます。
コードの中に書く項目については、後述します。

  1. HTMLファイル
  2. 3Dモデル(.glTF)

▼ 動作デモのコードは、以下のGithubに置いています。

GitHub - mechanoboyu/babylonjs-cad-like-viewer: Babylon.js で作るCADっぽいシンプルビューアのデモ
Babylon.js で作るCADっぽいシンプルビューアのデモ. Contribute to mechanoboyu/babylonjs-cad-like-viewer development by creating an account ...

開発環境

今回の記事の作成には、以下のソフトウェアを使いました。

No.ソフトウェア名分類作業内容
1Visual Studio Codeテキストエディタコードを書く
2Live ServerVscodeの拡張機能ローカルサーバーを起動する。1クリックで実行できる
3FUSION 3603DCAD3Dモデルを作る
4Blender 3.3.1CGソフト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のデシメート機能を適用している様子

あんまりやりすぎると、ガビガビボコボコになってしまうので、ご注意ください

▼ Blender デシメート モディファイアーのドキュメントです

Decimate(デシメート)モディファイアー - Blender 4.3 Manual

(必要に応じて)分離する

  • 使用ソフト:Blender

デフォルトでは、オブジェクトが一体化した状態だと思います。

▼ もし、部品ごとにオブジェクトを分けたい場合は、以下の方法で分離可能です。

  • Tabキーを押して、「編集モード」に切り替えます。
  • Aキーで全てを選択 → Pキー →「構造的に分離したパーツで」を選択すると、分離できます。
  • 分離が終わったら、Tabキーを押すと、「編集モード」から「オブジェクトモード」に戻ります。
Blenderで、オブジェクトを分離している様子
Blenderで、オブジェクトを分離している様子

.glTFへエクスポートする

  • 使用ソフト:Blender

軽量化などの調整が済んだら、最後にエクスポートします。

  • エクスポートしたいオブジェクトをすべて選択し、ファイル → エクスポート → glTF 2.0 をクリックします。
  • 保存場所、フォーマット(glTF embedded)、内容などを適宜指定したら、右下の glTF 2.0 をエクスポート ボタンをクリックします。
    • 今回は、フォーマットは「glTF embedded」、内容は「選択したオブジェクト」を指定しました。
Blenderでgltfファイルへエクスポートしている様子
BlenderでglTFファイルへエクスポートしている様子

これで、.glTFファイルの作成が完了しました。

コードの全体像

次に、ビューアを作るためのコードを書いていきます。

▼ 今回書いたコードの全体像はこんな感じです。

  • 最終的にはHTMLファイルを作ります。
  • <head>内でCSSの記述とbabylonのパッケージのインポートを行います。
  • <body>の中に、操作ボタンのHTMLタグと、babylon.jsのためのjavascriptコードを記述します。
babylon.jsを記述したhtmlファイルの構成
babylon.jsを記述したhtmlファイルの構成

書いたコード

▼ 動作デモのコードは、以下のGithubのdocsフォルダに置いています。

GitHub - mechanoboyu/babylonjs-cad-like-viewer: Babylon.js で作るCADっぽいシンプルビューアのデモ
Babylon.js で作るCADっぽいシンプルビューアのデモ. Contribute to mechanoboyu/babylonjs-cad-like-viewer development by creating an account ...

使うツール

テキストエディタのVisual Studio Codeと、拡張機能のLive Serverを使うと快適です。

開発の際は、コードを書いて保存し、都度、HTMLファイルを実行してブラウザで動作確認する……という作業を繰り返します。ただしローカル環境では、ただ実行するだけでは正常に動作しないので、ローカルサーバーを立てる必要があります。

そこで、拡張機能のLive Serverを使うと、ポチっと一回クリックするだけで、ローカルサーバーを通してファイルを実行できるようになります。

▼ Live Serverを使っている様子です。エディタ右下のGo Liveボタンをクリックすると、サーバーを立てた状態で、ブラウザが立ち上がります。

VSCODEで、Live Serverを実行している様子

babylon.js のためのコード

コードの主要な部分について、説明します。

HTMLのひな形を用意する

初めてBabylon.jsでの3Dシーン作成に取り組む場合、そもそも何をどこに書けばよいか戸惑いますよね。

いきなり面倒に思われるかもしれませんが、ご安心ください。公式ドキュメントにテンプレートが用意されているので、基本的には、3Dシーンに関する記述(createScene関数の中身)だけに集中すればOKです。

▼ HTMLテンプレートです。
ページ下部には、「ココは変える必要のない部分」のようにコードが機能ごとに色分けされているので、分かりやすいです。

Babylon.js docs

▼ 動作に必要なコードが含まれたHTMLファイルは、以下の「Playground」でも生成可能です。
Playground はbabylon.js専用の開発環境で、createScene関数の中身を書くだけで、シーンを作れます。
HTMLファイルは、上部メニューのダウンロードボタンをクリックすると、zipファイルとしてダウンロードできます。

Babylon.js Playground
Babylon.js playground is a live editor for Babylon.js WebGL and WebGPU 3D scenes

▼ Playgroundの使い方

Babylon.js docs

コードの目次へ戻る

各種パッケージをインポートする

まずは、<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>

▼ 用意されているパッケージの一覧は、以下のドキュメントをご覧ください。

Babylon.js docs

コードの目次へ戻る

見せたいものは、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で使えるカメラについては、以下のドキュメントをご覧ください。

Babylon.js docs

今回は「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クラス詳しい仕様は、以下のドキュメントをご覧ください。

Babylon.js docs

コードの目次へ戻る

カメラのオート調整機能を適用する

上記の方法でカメラを設置するだけだと、読み込む3Dモデルの大きさに合わせて、毎回カメラの半径などを引数に入力する必要があり、手間がかかります。
そこでFraming Behavior という機能を使えば、カメラの半径や原点位置などを自動的に調整できるようになります。

▼ useFramingBehaviorをtrueにすれば、有効になります。

camera.useFramingBehavior = true;

そして、各種プロパティに値をセットしていきます。

▼ 今回使ったのは、radiusScale というプロパティです。カメラ半径(radius)の数値は画面に対するオブジェクトの大きさに関わるので、ここに係数を入れておきます。

camera.framingBehavior.radiusScale = 0.8;

▼ 動作確認として、PlaygroundにBlenderでかいた3Dモデルを表示してみました。

  • 左は、FramingBehaviorが無効です。オブジェクトが遠くに表示されてしまっています。
  • 右は有効な状態です。オブジェクトの見え方が、ちょうどよくなりました。
FramingBehaviorの動作の確認画像
FramingBehaviorが無効の場合
FramingBehaviorの動作の確認画像
FramingBehaviorが有効の場合

動作している様子は、こちらのPlaygroundで確認できます。

▼ 設定できるプロパティの詳細は、以下のドキュメントをご覧ください。

Babylon.js docs
Babylon.js docs

コードの目次へ戻る

ライトを設置する

次に、オブジェクトを照らすためのライトを設置します。光が無いと、物体が真っ黒なカタマリになってしまします。

▼ ライトが無い場合

Babylon.jsで、ライトが無い場合
照明が無いので、黒い塊になっています

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で、半球ライト(HemisphericLight)を設置した場合
半球ライト(HemisphericLight)を設置した場合

▼ Babylon.jsで使えるライトについては、以下のドキュメントをご覧ください。

Babylon.js docs

コードの目次へ戻る

3Dモデルを読み込む

▼ 3Dモデルは、以下の1行のコードでインポート可能です。例えば「scenesというフォルダに入っているtest.gltfというファイル」ならこんな感じで。

BABYLON.SceneLoader.ImportMeshAsync("model_name", "scenes/", "test.gltf", scene);

▼ 3Dモデルのインポートに関して詳しくは、以下のドキュメントをご覧ください。

Babylon.js docs
Babylon.js docs

▼ 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に子メッシュが保存されている旨も、ここに書かれていました。

Babylon.js docs

▼ AbstractMesh クラスの仕様です。使えるプロパティやメソッドを確認できます。

Babylon.js docs

コードの目次へ戻る

輪郭は enableEdgesRendering メソッドで

▼ 以下のコード(上のコードの6行目)のenableEdgesRenderingメソッドにより、輪郭線を描画できるようになります。

node.enableEdgesRendering(Math.cos((45 / 180) * Math.PI)); //法線ベクトル間の角度を45°に設定

引数は、2つの面の法線ベクトルの内積です。法線ベクトル間の角度をθとすると、内積は cosθ になります。
例えば、上のコードのように法線ベクトル間の角度が45°ならば、内積はcos45°なので、引数は≒ 0.707になります。

内積が1 (= cos 0°)に近づくと、描画される線は多くなります。

babylon.jsで、enableEdgesRenderingの引数による違いを比較した
enableEdgesRenderingの引数による違いを比較。※括弧内は内積。

enableEdgesRenderingメソッドの詳細です。Playgroundで動作を確かめることもできます。

Babylon.js docs

コードの目次へ戻る

部品全体から境界点を取得する

先述の「カメラのオート調整機能を適用する」で、Framing Behaviorというカメラ調整機能を有効にしました。そして、「子メッシュ(部品)を取得して、効果を適用する」では、取得した子メッシュ達を”parent“という親メッシュに収容しました。

しかし、いざ camera.setTarget(parent, true); でカメラのターゲットをparentにセットしても、見え方が変です。

▼ 全体が良い感じにズームされるはずが、画面目一杯にオブジェクトが接近してしまっています。Framing Behaviorの対象が、一部分のみになっているようです。

parentメッシュをtargetにしたら、見づらくなった例
parentをカメラのtargetにしたら、見え方がおかしくなった

そこで、子メッシュ達を収容したparentの境界情報を更新しました。

▼ すると、部品全体の大きさが認識され、画面にちょうどよくフィットするようになりました。

parentメッシュの境界情報を再取得したら、正常に画面にフィットするようになった
parentメッシュの境界情報を再取得したら、正常に表示された

▼ 使うメソッドや処理の流れは、以下で詳しく説明されています。このドキュメントは「複数部品全体を包むバウンディングボックスを描く」という内容ですが、今回の用途でもピッタリ有効だったので、そのまま利用させて頂きました。

Babylon.js docs

コードの目次へ戻る

操作ボタンを作る

▼ すぐにホームポジションや各側面などを見られるよう、ボタンを設けました。今回は、HTML/CSSを使って作成しました。

babylon.jsのGUIとして、ボタンを表示している様子
babylon.jsのGUIとして、ボタンを表示している様子

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の作り方の詳細は、以下のドキュメントをご覧ください。

Babylon.js docs

……少し長くなりましたが、これで、完成です!用意された既存のメソッドを組み合わせるだけで、手軽に実現できました。

コードの目次へ戻る

完成したコード

▼ 動作デモのコードは、以下のGithubのdocsフォルダに置いています。

GitHub - mechanoboyu/babylonjs-cad-like-viewer: Babylon.js で作るCADっぽいシンプルビューアのデモ
Babylon.js で作るCADっぽいシンプルビューアのデモ. Contribute to mechanoboyu/babylonjs-cad-like-viewer development by creating an account ...

▼ 動作デモ

Babylon.js で作るCADっぽいシンプルビューア サンプル

コードの目次へ戻る

埋め込む場合

既存のサイトに埋め込む場合は、以下のような感じでiframeタグを使えば可能です。

<iframe src="filename.html" title="title" scrolling="no" frameborder="no"></iframe>

▼ 埋め込んだ場合のデモサイトです。

Babylon.js 埋め込みDemo

参考文献

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

おすすめ本

Babylon.jsで扱うJavaScript、HTML、CSSについて、以下の書籍を手元に置いて取り組みました。これらの言語はオンラインのドキュメントが充実していますが、紙の書籍があるとさっと確認しやすく、学習が捗りました。

▲ 30 mmほどの分厚い本です。わからないことが出ると、事典のように都度参照していました。
1冊通すとJavaScriptの基礎を体系的に学べますが、ボリュームが大きいので時間がかかってしまい、やりたいことに取り組むまでに時間がかかってしまうかもしれません。
私の場合は、まず1~3章を読み、JavaScriptの開発環境の導入や概要について学びました。その後Babylon.jsのチュートリアルを読み、不明な文法が出てきたら都度調べる、という方法を取りました。

▲ HTML/CSSの記述の際に、都度参照しました。タグやプロパティの説明だけではなく、文法について基礎の解説もあり、読み物としても役立つ便覧です。

動画版

この記事のダイジェスト動画を作りました。5分半ほどです。(注:音声あり)

関連記事

▼ こちらは、別のフレームワークの記事です。数行のhtmlタグだけで手軽にビューワを作れます。

タイトルとURLをコピーしました