CrossRoad

XRを中心とした技術ブログ。 Check also "English" category.

【2023/9/16webpackエラーについて追記】ES6以降の仕様でBabylon.jsのコードを記述する方法について

JavaScriptは、ECMAという言語仕様のバージョンによって書き方が変わります。いろいろ調べたところ、2015年に策定されたES2015 (ES6) で大きく変化し、Mozilla Hubsなど、JavaScriptのOSSの多くはES6以降の仕様で書かれている印象です。

一方、Babylon.js公式ドキュメントやPlayground (サンプルコードの共有サイト) では、まだES2015 (ES6) の仕様で書かれていない記事が多いです。私はBabylon.jsから本格的にJavaScriptの勉強に入ったため、ES6の仕様については曖昧なところが多いままでした。

今回は勉強を兼ねて、比較的よく知っているBabylon.jsでのコーディングをES6の仕様で書く方法をまとめました。

1. JavaScript、ECMAScriptについて

まず、JavaScriptとは何かについてです。

JavaScriptという言葉は狭義にはMozillaが仕様を策定し実装しているスクリプト言語を指す。このスクリプト言語はEcmaインターナショナルでECMAScript (ECMA-262) として標準化されており、多くのウェブブラウザ等はこの標準化されたECMAScriptを実装している。
ECMAScriptは仕様自体に独自の拡張を条件付きで認める記述があり、現在主要なブラウザが実装しているスクリプト言語はすべてECMAScriptに準拠していることになる。広義の意味でこれをJavaScriptと呼ぶ場合、主要なブラウザが実装しているスクリプト言語はマイクロソフトやGoogle、アップルの実装も含めてJavaScriptである。

引用元:JavaScript - Wikipedia

次にECMAScriptについてです。

ECMAScriptはECMA Internationalのもとで標準化されているJavaScriptの仕様です。
JavaScriptは1995年にBrendan Eich氏によって開発され、Webとともに急速に普及していきました。 しかし、当初はブラウザベンダーが独自に言語仕様を拡張していたため、ブラウザ間の互換性が低い状態でした。
そこで、1997年にECMA Internationalが中心となり、JavaScriptの中核となる機能を抜き出して標準化したものがECMAScriptです。 ECMAScriptによる標準化によってブラウザ間の互換性もある程度確立され、以降JavaScriptは多くのWebブラウザで使用されるようになっていきます。
その後、2009年5月に公開されたES5では、言語仕様の解釈を明文化し各ブラウザの実装として標準化されました。 このES5が現在のブラウザがサポートしている標準仕様となります。

引用元:ES2015(ECMAScript 2015)とは何か | Think IT(シンクイット)

ECMAScriptは言語仕様、策定された仕様のバージョンをES1、ES2、ES3、、と呼びます。ただし、2015年から、バージョン表記にリリース年を含むことになり、ES2015と変わったようです。2015年は従来であればES6に相当するリリースでした。 つまり、ES1、ES2、ES3、ES4、ES5、ES2015、ES2016、、となるのが厳密には正しいですが、海外のサイト(今回のBabylon.jsも)を含め、ES2015のことは習慣的にES6と書かれることが多いようです。(この記事ではES6で表記します)

ES6の名称の方がエンジニアコミュニティに中では浸透しているらしく、ES6と記載されていることが多い。

引用元:ES2015(ES6) 入門 - Qiita

ES6によるコードの書き方は、たとえば下記にまとまっています。

github.com

thinkit.co.jp

qiita.com

html5experts.jp

2. ES6 (以降) の仕様でBabylon.jsのコードを書く手順

この章は、以下の公式ドキュメントの手順を補完したものです。なお、Node.jsとNPMは既知として説明します。

Babylon.js ES6 support with Tree Shaking | Babylon.js Documentation

ES6の仕様で書くためには、まずnpm (Node Package Manager) を使って、Babylon.jsのコードがまとまったjsファイルをフォルダに配置する必要があります。

これは、今まで下記のようにまとまっていたものを、もっと細かい単位で個別の.jsファイルに分けたものです。

        <script src="https://preview.babylonjs.com/babylon.js"></script>
        <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
        <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
        <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>

以下、Babylon.jsをES6のルールで使う手順のApplication Creation Summaryに沿って説明します。

1. Create new folder MyAwesomeApp

まずは任意の場所にフォルダを作ります。ここでは、フォルダの名称を"MyAwesomeApp"としています。

2. Open GitBash (or similar) for MyAwesomeApp

GitBashとは、Windows用のgit環境です。ここではターミナルソフトがあればよいので、Windows Powershellや、Macのターミナル、Visual Studio Codeについているターミナル機能などでも問題ありません。

3. npm init

これは、作ったフォルダをnpmで管理できるようにするという初期設定です。この辺りは多数の記事が出ているので省略します。

例:

開発前の下ごしらえ(npm init) - bnote

npm よく使うコマンドまとめ - Qiita

4. npm install webpack webpack-cli webpack-dev-server --save-dev

Webサーバ環境を作るため、webpackという仕組みを導入 (npm install) します。webpackとは、複数のJavaScriptファイルをまとめて1つのJavaScriptファイルにする仕組みです。この辺りがわかりやすいです。

qiita.com

qiita.com

webpack-cliとは、webpackをコマンド実行するために導入します。webpack-dev-serverは、開発環境でサーバを立てるための仕組みです。導入後、webpack-dev-serverを起動するだけで、作ったコードがWebサーバ上で動きます。たとえば、この辺りがわかりやすいです。

qiita.com

qiita.com

5. npm install --save-dev @babylonjs/core

引き続き、npm installを使って、ES6に対応したBabylon.jsのコア機能のパッケージを導入します。


2020/10/24追記

10/24時点でwebpackにバグがあり、npm i webpackでそのままインストールすると、以下のリンクに記載されているエラーが出てしまいます。

github.com

Cannot find module 'webpack-cli/bin/config-yargs'

解決策がはっきりしないので、解決までは本ブログ記事投稿時に合わせて公開したリポジトリで使ったwebpackのバージョンでインストールするのがよさそうです。

$ npm i webpack@4.43.0
$ npm i webpack-cli@3.3.11
$ npm i webpack-dev-server@3.10.3

また、公式ドキュメントでは説明の途中に書いていますが、この段階で以下も実行しておきます。

npm install --save-dev @babylonjs/materials

--save-devとは、今回のディレクトリだけに導入するという意味です。また、"@babylonjs/core"のように"@"がついているものは、babylonjsという中に複数のパッケージが含まれていることを指すようです。
今回の場合、babylonjsの中にcoreだけでなくloaders、materialsなどがありますが、上記のコマンドではcoreだけを選択してインストールしています。

6. Create index.html file in MyAwesomeApp as described in First App Section below

MyAwesomeAppフォルダにindex.htmlを作り、以下のコードを貼り付けます。

$ touch index.html

gist.github.com

7. Create Folder src in MyAwesomeApp

srcフォルダを作ります。

$ mkdir src

8. Create index.js file in src as described in First App Section below

srcディレクトリにindex.jsを作り、以下のコードを貼り付けます。

$ cd src
$ touch index.js

gist.github.com


2020/10/23 追記

Babylon.jsの公式ドキュメントでは次にnpx webpack-dev-serverを実行するように書いていますが、実際はwebpack.config.jsが必要です。
この記事後半で示したGithubのリポジトリには入れていますが、同じものを貼っておきます。

トップディレクトリで以下を実行してからこのコードを貼り付けておきます。

$ touch webpack.config.js

gist.github.com



2023/9/16 追記

WebPack 5.8.8の状態で同じことを実行すると、npx webpack-dev-serverコマンド実行時に以下のエラーが出ました。

gist.github.com

webpack v4以降でwebpack.config.jsの文法が変わったためです。(この記事を書いたときはv4で動いていたはずなのですが、、)

このエラーを解消するには、contentsBaseとwatchContentsBaseの記載を変更します。

修正したwebpack.config.jsはこちらです。

gist.github.com

以下を参考にさせていただいています。
qiita.com

github.com


9. npx webpack-dev-server to check result in http://localhost:8080/

$ npx webpack-dev-server

このコマンドを実行することで、index.jsの冒頭でimportしたEngineからGridMaterialまでの実体の.jsファイルが1つに統合されてmain.jsとなります。また、Webサーバが立ち上がります。index.htmlは、このmain.jsを読み込みます。Webブラウザで表示された結果です。

A sample project of Babylon.js ES6

なお、この時点のmain.jsは実体としては存在しません。

10. npx webpack _to create dist folder

$ npx webpack

このコマンドを実行すると、distというフォルダにmain.jsの実体が生成されます。

3. 自分で任意のモジュールを追加してみる

ES6以降の書き方を理解するため、上記のサンプルコードに2つの機能をもつ関数を追加してみました。
今回のソースコード全体は、以下のリポジトリに置きました。

github.com

3.1 任意の3Dモデルを読み込む機能

src/の中にmodelImport.jsを追加し、以下のコードを書きました。

gist4d0743e06ccaa54ed2630cb809188adc6

Babylon.jsでは3Dモデルを読み込むために、ImportMeshという関数を使います。この関数はAPI Documentationによると、SceneLoaderの階層で定義されています。そこで、import〜fromを使ってBabylon.jsのSceneLoaderを読み込み、SceneLoaderとして使います。

const ImportModel={〜 で定義した中には連想配列関数という形で具体的な処理を書いています。ここでは、importMeshModelという名前で実質的に関数の役割をしています。

SceneLoader.ImportMesh(〜 はBabylon.jsで提供されているAPIです。

最後の export は定義したものを他の.jsファイルでも使えるようにします。

ここまで書いてから、メインの処理 (index_mod.js) に処理を追加しました。

gistda098c525ba8cd05c3085fa8b4aa4602

別途assetsというディレクトリを作り、.glb形式の3Dモデルを入れました。結果、インポート指示をした3Dモデルが表示されるようになります。

An example of importmesh api on Babylon.js

3.2 指定したメッシュを光らせる機能

続けて、先ほどインポートした3Dモデルの特定部位だけ光らせる処理を追加します。

src/の中に、Effects.jsを追加し、以下のコードを書きました。

gistafd9db8368fdc324f9c8cf6f786bde6f

こちらは、Babylon.jsのGlowLayerをimportして使えるようにしています。特定のメッシュを光らせる処理は公式ドキュメントのControlling glow color per meshを参考にしています。

次に、メインの処理 (index_mod.js) に処理を追加しました。

gist.github.com

rootNodeというのは、Babylon.jsで管理されている3Dモデルと考えてよさそうです。配置されている順番は、Babylon.jsのSandBoxにアクセスして3Dモデルをインポートして、Inspectorを表示して、目のアイコンを選択して表示/非表示を切り替えれば、簡単に確認できます。

How to use Babylon.js Sandbox

今回は、赤枠で囲ったところが"CurveRail_0"でrootNode[0]でした。

Check rootNode[0] on Babylon.js Inspector

GlowLayer機能を使って、"CurveRail_0"だけを光らせた結果がこちらです。

Add GlowLayer effect o Babylon.js

4. おわりに

冒頭にも少し書いた通り、ES6以降の書き方がわかるとWebXRで使われているOSSの理解がしやすくなります。時間があれば、ES6以降の書き方について詰まったことをtipsとして書き出してみる予定です。