WebGL フレームワークである babylon.js には、モデルの材質表現を扱うクラスとして Material
があります。
このあたりのドキュメントで概要がつかめると思いますが、テクスチャや色などのパラメータを割り当てて(bind)、ポリゴンがどういう風に光を受け描画されるかを設定することが出来る機能です。
デフォルトでは StandardMaterial というマテリアルが適用されますが、これには様々な機能が搭載されています。
See the Pen babylon.js Variable Materials by 山岸 "あかいいぬ?" Masaru (@akai_inu) on CodePen.
例えばこのような感じで、手軽にマテリアルを設定可能です。視差マッピングがデフォルトであるのも面白いです。
これらのマテリアルは WebGL Shader
によって実現されています。マテリアルと 1 対 1 でシェーダーが Effect クラスの中に用意されています。
実行時はこの Effect
を使って、割り当てられたメッシュをレンダリングしていきます。
また、 物理ベースレンダリングマテリアルも実装されているので、 glTF で PBR 設定がされているものに関しては自動で適用されます。
さらに、別パッケージとして Materials Library があり、こちらで溶岩や水、セルシェーディングなどのカスタムマテリアルが用意されています。自作 Material を作る際の参考になりますね。
今回は私が実装した babylon-mtoon-material を作る際に参考にしたこと、注意したことをまとめておきます。
事前に、 WebGL シェーダを理解する必要があるので、 Introduction to Shaders - Babylon.js Documentation を読みます。今回は WebGL シェーダについての紹介は省略します。
Material を自作する方法
- CYOS を使う: ブラウザで手軽にシェーダーを書いてそれを ShaderMaterial としてエクスポートして利用
- ShaderMaterial を使う: 任意のシェーダーを読み込んで利用
- Material Library を使って拡張する: 公式の拡張マテリアル一覧に新しいマテリアルを追加して利用
- CustomMaterial を使って拡張する: StandardMaterial の特定のシェーダー部分を置換して利用
- 完全新規に作成する: Material を一から作成
- [WIP]NodeMaterial を使って視覚的に作成する
1. CYOS を使う
Put Shader Code in BJS - Babylon.js Documentation
babylon.js の Create Your Own Shader ページを利用すると、リアルタイムにシェーダーの変更を反映させながらシェーダーを作ることが出来ます。
結果を zip 出力すると、後述する ShaderMaterial を使って、書いたシェーダーを読み込めるようになります。
これは非常に簡単にシェーダーをいじることが出来るので楽ですが、シェーダーに入力する値を変更出来ないので拡張しづらいです。
2. ShaderMaterial を使う
Use ShaderMaterial - Babylon.js Documentation
ShaderMaterial を利用することで、任意のシェーダー文字列を読み込み、値をバインドし、動作させることが出来ます。
- の CYOS でもこの ShaderMaterial 用のスクリプトが出力されます。
// ファイル ./cyos.vertex.fx と ./cyos.fragment.fx を読み込むマテリアルを作成する
const shaderMaterial = new BABYLON.ShaderMaterial('cyos', scene, './cyos');
// <script type="application/vertexShader" id="cyosVertexShaderCode">
// <script type="application/fragmentShader" id="cyosFragmentShaderCode">
// のタグに書かれたシェーダを読み込むマテリアルを作成する
const shaderMaterial2 = new BABYLON.ShaderMaterial('cyos2', scene, { vertexElement: 'cyosVertexShaderCode', fragmentElement: 'cyosFragmentShaderCode' });
// 文字列からマテリアルを作成する
BABYLON.Effect.ShadersStore['cyosVertexShader'] = `
precision highp float;
// Attributes
attribute vec3 position;
attribute vec2 uv;
// Uniforms
uniform mat4 worldViewProjection;
// Varying
varying vec2 vUV;
void main(void) {
gl_Position = worldViewProjection * vec4(position, 1.0);
vUV = uv;
}
`;
BABYLON.Effect.ShadersStore['cyosFragmentShader'] = `
precision highp float;
varying vec2 vUV;
uniform sampler2D textureSampler;
void main(void) {
gl_FragColor = texture2D(textureSampler, vUV);
}
`;
const shaderMaterial3 = new BABYLON.ShaderMaterial('cyos3', scene, { vertex: 'cyos', fragment: 'cyos' });
最後の Effect.ShadersStore
にマテリアル文字列を代入してそれを読み込む方法が、環境に依存しなくなるので安全ですね(静的変数なので、名前だけ被らないように注意)。
3. Material Library を使って拡張する
Create a Material for the Materials Library - Babylon.js Documentation
パッケージは @babylonjs/materials となっていますが、同じリポジトリで開発されている materialsLibrary を拡張する形で、新しいマテリアルを実装出来ます。
まず、 BabylonJS/Babylon.js リポジトリ自体を git clone してきます(かなり重いので git clone --depth 1
で shallow clone する方が良いかもしれません)。
/Tools/Gulp
ディレクトリに移動し、下記を打ちます。
Babylon.js/Tools/Gulp $ npm install --global gulp
Babylon.js/Tools/Gulp $ npm install
...
Babylon.js/Tools/Gulp $ npm start
これで http://localhost:1338/materialsLibrary/
にアクセスすることで上記の画像のページを開くことが出来ます。
このページでは、 /materialsLibrary/src
内に記述された各種マテリアルを、任意のパラメータと共にテストすることが出来ます。
/materialsLibrary/index.html
を直接書き換えて自分のマテリアルを UI に表示する必要があるのが少し面倒ですが、比較的手軽にいくつかのメッシュに対してテストが可能になります。
4. CustomMaterial を使って拡張する
materialsLibrary
の中にある CustomMaterial を利用すると、 StandardMaterial
のシェーダコードの特定の部分を置換し、 StandardMaterial
に処理を加えることが出来るようになります。
正直、 StandardMaterial
自体を詳しく把握しないと追記することが難しいので、上級者向け(というか使う場所あるか?)です。
5. 完全新規に作成する
マテリアルは Material
クラスを継承していればなんでも良いので、 babylon.js が用意している環境に依存せず単体で作成していくことももちろん可能です。
babylon-mtoon-material は上記を検討した結果、ここにたどり着きました。
シェーダは webpack の raw-loader を利用して文字列として import
出来るようにし、 Material のコンストラクタで Effect.ShadersStore
に代入しています。
また、 babylon.js 独自の仕様で、シェーダ内に #include<instancesDeclaration>
などと書くことで別のファイルを読み込むことが出来ます(GLSL 系列は include 処理がないので、シェーダのコンパイル前にファイルを取得してきて文字列連結させています)。
include 出来るファイルは Effect.IncludesShadersStore
で管理されます。
マテリアルの値のテストを行う
開発時は、マテリアルに渡す値(色やテクスチャなど)をリアルタイムに変更して、見た目がどうなるか確認したくなります。
materialsLibrary のページではその機能がありましたが、単体でマテリアルを作成した場合は全て自前で GUI を用意しなければなりません。
それは面倒なので、 babylon.js のインスペクタを拡張することで実現しました。
Display and Use the Inspector - Babylon.js Documentation
material.inspectableCustomProperties
というプロパティに変更可能なプロパティを列挙することで、上記画像のようにインスペクタから値を変更することが出来るようになりました。
現在この方式でサポートされているのは Checkbox, Slider, Color3, Vector3, Quaternion
だけですが、ある程度はカバーできるのではないでしょうか。
テクスチャなどカバー出来ない範囲は別のメッシュに対してマテリアルを適用させて、それで確認出来るようにしています。
Babylon.js MToon Material Test
6. [WIP] NodeMaterial を使って視覚的に作成する
現在 v4.1 向けに、 Unity の ShaderGraph や UE4 の Node Graph のようなノードベースのマテリアル作成機能が開発中のようです。
Inspector と同様 React ベースのエディタが搭載されるようです。
ref. node based material - Questions - Babylon.js
[Update: 2019/07/04] author の david さんが NodeMaterial についての記事を medium に投稿していました。
Creating the Babylon.js Node Material - Babylon.js - Medium
現状では新しいマテリアルを作るのは結構大変です。 StandardMaterial が出来ることも移植しようとすると、 babylon.js と WebGL の知識がそれなりに必要になります。
ノードベースのマテリアル作成ツールがリリースされて、わかりやすくマテリアルが作成出来るようになれば良いですね。