Blender ~ glTF ~ Babylon.js 使ってみた

主業が雑務とWebエンジニアで、この間個人の興味・仕事のニーズともにあってブラウザの3Dレンダーに少し触った人です。

今回はBlenderモデルファイルからglTFフォマットに書き出して、Babylon.js でロードしてレンダーする流れを紹介しようと思います。

Babylon.js使うとはいえ、この文章では[Babylon.js sandbox](https://sandbox.babylonjs.com/) でglTFレンダーするだけで、コードは1行もありません。

グラフィックス関連の膨大した知識と比べて自分はどうも経験浅いため、気になることあればぜひコメントしてください。

## プレイヤー紹介

### Blender

3Dモデル編集、動画、オフラインレンダリングなど大量の機能を内蔵したオープンソースソフトウェア。

### glTF

3Dモデル界隈のファイルフォマットの1つ。obj, fbxより新しくオープン仕様のもので、個人はより多く利用しています。

Blenderがこのフォマットでの書き出し機能を内蔵していて、Babylon.jsもこのフォマットのloaderを内蔵しています。

ただし3Dレンダーのプロセスが複雑なものでして、同じフォマットといえど、レンダーに必要な情報がソフトウェアをまたいでキープ・認識されるわけではありません。こんなことが互換性問題を起こします。

この互換性問題とワークアラウンドについては正文でまた説明します。

### Babylon.js
ブラウザ用の3Dライブラリ。個人は入門の最初にこれのドキュメント見ていた、ソースコードがTypeScriptとかの理由でよく使っています。

この系のライブラリで、他にもthree.jsなどがあります。このあたりは https://qiita.com/kouta_vr/items/2665cf60d6a618fd3b4a の紹介もご覧ください。

## 正文

### 0. Blenderでモデルファイル開く

[free3d / Coca Cola bottle](https://free3d.com/3d-model/coca-cola-bottle-434255.html) からダウンロード・解凍した `Coca_Cola.blend` を開くと、[Blender: Default Workspace](https://docs.blender.org/manual/en/latest/interface/window_system/workspaces.html#default-workspaces) の状態に似た画面が見えます：

左: 3D viewport、各オブジェクトの位置と様子を見せる。モデルを編集する場合編集操作もここでする。
右上: Outline、オブジェクトの一覧
右下: Properties、選択中オブジェクト、及びグローバルの属性を編集できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64034/4fced3fb-8bb0-be1c-820f-043cb7b58565.png)

3d viewport最初は「Solid」モード（マテリアル適用しない高速モードみたいなもの）ですが、モデルの全貌を見るために ホットキーZ開いたメニューから「Rendered」モードを選ぶとこうなります：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64034/3ef5ee93-4fb4-affa-d6a2-7fa295726a6e.png)

### 1. glTFへの書き出し

右上のOutlineのオブジェクト一覧の中では、コーラ瓶の他にライト、カメラなどオブジェクトが存在します。今回では使わないので、瓶自体を構成したオブジェクトだけ書き出します。

OutlineでBottle / Sticker / Straw を選んだ状態で、メニューのFile > Export > glTF v2.0からこのダイアログ開きます：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64034/5d73c8d6-fe0a-beee-8e69-2982b7086d98.png)

1. 右上のFormatを `glTF Embedded (.gltf)` にする
2. Formatの下にあるIncludeに、`Limit to / Selected Objects` をチェックする

この状態で書き出した .gltf ファイルは選んだコーラ瓶オブジェクトだけ含めます。

### 2. Babylon.js でglTFをレンダーしてみる

Babylon.jsの公式サイトに [sandbox](https://sandbox.babylonjs.com/) というページがあって、このページではモデルファイルのプレビューができます。この前書き出したファイルをいれると、こんなレンダー結果になります：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64034/17cd76af-cdd3-fa04-046b-bd1b0ebcc158.png)

### 3. マテリアル互換性問題

BlenderのRendered状態と比べて、Babylon.js sandboxでコーラ瓶が色がついていません。この原因は、BlenderにあったマテリアルがBabylon.js まで留保されなかったからです。

BlenderにあったMaterialは右下の [Shader Nodes](https://docs.blender.org/manual/en/latest/render/shader_nodes/index.html) を使って、左下のテキスチャー画像をいくつかの処理に通して、Stickerに適用しています：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64034/c3f069ee-de5e-510d-389c-a1b49480a088.png)

ただしBabylon.js のInspectorで、コーラ瓶ラベルの部分見ると、マテリアル種類がBabylon.jsデフォルトのPBRMaterialになっているし、テキスチャーもついていない状態になります。

この違いの理由はこのStack Exchange解答によって解説されています： https://blender.stackexchange.com/a/57541/125507 

簡単に訳すると「マテリアルのデータ表現が難題であり、ソフトウェアを跨ぐ互換性は一般的に望めない。レンダー側でマテリアル作り直せ」ということです

### 4. テキスチャー画像も書き出して、Babylon.js sandboxで適用する

Blenderからテキスチャー画像をjpgファイルに書き出して、このjpgをBabylon.js sandboxの `Sticker` meshに繋がった `Material.003` マテリアルに「albedoTexture」として設定すると、ラベルがこうなります：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64034/ea9d2fcc-2c80-eb61-3463-8a641f9c70e8.png)

まだ見た目違いますが、UVマッピングはBlenderのときと一致するし、上のStackExchange回答にあった「UVマップまでは互換性いいがマテリアル・テキスチャーに難あり」は本当のようです。

※ここはPBRMaternalのalbedoTextureに適用しただけで、元のBlenderマテリアル同等になるわけではありません。元のマテリアルを理解して、Babylon.jsも理解していれば正確に再現する方法はあると信じますが、筆者はまだそのレベル以前にあります。

3Dグラフィックスは底なし深いけど、面白みもあるので勉強を続けたいと思います。