InstaMAT事始め

現在のCG業界では物理ベースレンダリング(PBR)が主流となり、そのためのテクスチャを編集するツールとしてSubstance 3D製品が大きなシェアを持つようになりました。
Photoshopのような画像編集ソフトでは複数の関連する画像を編集しづらく、また、実際の3Dオブジェクトをチェックしながら編集することが難しいです。
Substance 3D製品はその点、Substance 3D Painterで3Dメッシュに対するテクスチャリングができますし、Substance 3D DesignerやSamplerを使うことでタイリングテクスチャの生成もできます。
他にも似たようなツールがないわけではないのですが、Substance 3Dほど気軽に、かつ網羅的に使えるツールは他にありませんでした。

そんな中に登場したのがドイツにあるAbstract社がリリースした『InstaMAT』です。
この会社は『InstaLOD』という3Dモデルのリダクションツールもリリースしています。いわゆる『Symplygon』の競合ツールですね。

InstaMATはSubstance 3DのPainter / Designer / Samplerを合わせたようなツールです。
Substance 3Dではこれらの3つのアプリはそれぞれ別々のアプリとなっています。
これに対してInstaMATは同じアプリ内でこれらの機能を利用することができます。
と言ってもやはり役割が違うため、それぞれの機能ごとにUIの差があります。
これは場合によっては混乱するかもしれませんが、1つのパッケージ内にグラフのプロジェクト、ペイントのプロジェクトといったものをまとめておくことも可能です。
最近リリースされたばかりのツールではありますが、かなり機能は充実していて実戦投入も可能だろうと考えます。

というわけで、今回はInstaMATの紹介として、簡単な操作案内とElement Graphを用いたタイルマテリアルの作成をやってみます。

まずはアプリを立ち上げ、新規プロジェクトを作成してみます。
使用するバージョンは1.5で、ちょうど昨日アップデートしたようです。このバージョンで日本語対応もされました。
新規プロジェクト作成時は以下のようなウィンドウが表示されます。

LayeringはPainter、Material LayeringとMaterialize ImageはSampler、そこからしたがDesignerといった感じです。
今回は普通のDesignerと同等のElement Graphを利用します。

テンプレートを選択します。
とりあえずPBRマテリアルを作成する場合はPBRテンプレートを選択したほうがいいです。
今回はテンプレートを使用せず、空の状態からスタートします。

ノードも何も無いシンプルな画面ですが、この状態だとマテリアルの確認ができません。
左上の赤枠で示す3Dキューブをクリックします。これで左側に3Dペインが表示されます。
SDと違って、3Dウィンドウの操作にはALTキーが必要になります。SubstanceでもPainterなんかは必要なのですが、SDばかり使ってる人間としてはちょっと面倒です。

まず適当なノードを配置してみます。
真ん中のグラフペインでスペースキー、もしくはマウス右クリックをします。
検索ウィンドウが表示されますので、[Solid Color]と入力してノードを選択します。SDと同様、スペースキーも名称に含まれるので注意が必要です。
右のノードパラメータペインで適当な色を選択します。[Color]パラメータを右クリックすればカラーパレットが表示されます。
このノードの[Output]コネクタをクリックするか、ノードを選択してVキーを押すと左下の2Dペインに画像が表示されます。
また、ノードを右クリックして[マテリアルチャンネルとしてプレビュー]→[Output]→[BaseColor]と選択して3Dペインへ反映させることができます。

SDと違ってノード自体をダブルクリックしてしまうとノードの実装にジャンプしてしまうので注意しましょう。
手癖でダブルクリックしてしまって開くつもりがなかったノード実装を開いてしまうことがどうしても多いです。
また、グラフエディタの操作も結構SDと違うので、慣れるまでは戸惑うと思います。というか、全然慣れないです。

さて、いちいち右クリックして出力先を選ぶのは面倒なので、出力ノードを作成してしまいましょう。
SDではOutputノードを配置していましたが、InstaMATではグラフのパラメータとして出力を作成することでOutputノードが生まれます。
グラフエディタでノードのない場所をクリックし、右のパラメータペインで出力を追加します。

出力右の+ボタンを押して、型を選択して追加します。
出力の型は[ElementImage]か[ElementImageGray]にします。これはイメージ情報として出力することを意味します。
BaseColorとNormalはElementImage、RoughnessとMetalnessとHeightはElementImageGrayにします。 追加された段階では"Parameter"というパラメータ名になっていますが、これを適切な出力名に変更する必要があります。
名前をダブルクリック、もしくはF2キーでリネームします。このとき、マテリアルパラメータとして登録されているものは検索可能です。
BaseColorであればbと入力した段階でBaseColorが候補に出てきますので、選択すればOKです。
しかもマテリアルパラメータの場合はパラメータ名右側のカテゴリー名も自動的にMaterialに変更されるので便利です。
とりあえず必要そうなパラメータを追加し、グラフエディタでノードを整頓しましょう。
追加した出力ノードをまとめて選択、右クリックからの[コメント]を選択するとSDのフレームと同等のものを追加できます。

それではタイルを作っていきましょう。
まずは以下のようにノードを追加、接続します。

[Tile]ノードは入力イメージをタイル上に配置するノードで、SDでも同様のものがありますね。
入力イメージとしては[Rounded Box]を利用します。サイズやタイルの数は適当に調整します。

この段階ではノードは高さ情報ですので、カラーではなくグレースケールとして設定します。
SDではアトミックノード以外はカラーとグレースケールで別々のノードとなっていましたが、InstaMATはノードに切り替えスイッチが存在しています。
パラメータペインの[インスタンスのプロパティ]カテゴリーの[グレースケール]スイッチを入れることでグレースケールに変更できます。便利。

また、[Tile]ノードは[Flood Fill]スイッチを入れることでタイルのFlood Fill情報を出力してくれます。
これを利用すれば[Flood Fill]ノードを省略することができます。
そして[Flood Fill to Gradient]ノードでランダムな傾斜を求め、[Blend]ノードで乗算して少し傾斜をつけます。
最後に[Height to Normal]ノードでノーマルを生成してノーマルの出力ノードに接続します。
これで3Dペインにノーマルが反映されればOKです。

ここから表面の調整、クラックの作成を行います。

表面のノイズは適当に作成して適用しますが、特に難しいことはしていません。
[Histogram Edit]ノードはSDの[Histogram Scan]とほぼ同等だと思えばOKです。

クラックは[Voronoi]ノードからスタートです。SDのセルノイズ的なもので、[Cracks]コネクタでエッジ部分を取得できます。
[Slope Blur]はSDでも存在しますが、パラメータや挙動がどうもSDと違っていて調整が難しい印象があります。
クラックのズレやマスクは[Flood Fill to Color]と[Directional Warp]を適当に利用しています。

タイルの色はタイルごとのグレースケールを利用して[Gradient Map]ガチャを使います。

SDにあるデスクトップの画面のどこからでもカラーを取得できる機能がこちらにもあります。
ただ、ポイントとして利用できるのは16点までのようで、これを超えるポイント数になると[Gradient Map Dynamic]に自動的にコンバートされます。

後は適当にRoughnessとAOを調整して、できたのがこちら。

短時間で雑に作ったものなのでクオリティは低いですが、SDでできることは結構できるのではないかと思います。
しかし、慣れの問題もあってSDの方が楽に作れるというのは間違いなくあります。

ただ、InstaMATはメッシュをノードとして利用することができるというのが面白いです。
FBXファイルをD&Dでノードとして取り込むことができ、そこから[Mesh Bake]ノードでメッシュノーマルやAOといった情報を作成できます。

SDのグラフでは、ベイク自体は外(Painterなど)で行い、その結果を入力として受け取るという方式ですが、InstaMATではメッシュそのものを入力とすることができ、そこからベイク→ベイクされたマップの利用というところまで可能です。
ベイクの精度がどの程度かは不明ですが、InstaLODで培われた技術が流用されているものと考えられるのでそれなりのクオリティは出るのではないでしょうか?
メッシュを利用した処理は他にもたくさんあるので、少しずつでも検証していこうかと思っています。

これからも検証進めて、面白い機能やらがあったら記事にしていこうと思います。

While Loopを利用したSymmetric Nearest Neighborフィルタ (Substance 3D Designer 13.0)

久しぶりのブログ更新

FunctionグラフのWhile Loop

つい先日のバージョンアップで待望の[While Loop]ノードが追加されました。
今はFunctionグラフでしか使用できませんが、個人的にはかなり大きな追加要素だと思っています。
今回の更新ではこのノードの使い方を解説し、ついでに以前作成したSymmetric Nearest Neighbor (SNN) フィルタを[While Loop]ノードを使って実装してみます。

While Loop解説

利用法

[While Loop]は前述の通り、Functionグラフノードとして提供されています。

入力コネクタは3つ、出力コネクタは1つです。
[Init]入力コネクタは[While Loop]に入る前の処理です。ループを行う前の初期化などを接続します。
[Exit Cond.]入力コネクタは[While Loop]を抜ける条件を指定します。C++のwhile命令はループを継続する条件を指定しますが、こちらは逆を指定する点に注意が必要です。
[Loop Body]は実際のループ処理そのものです。ここに接続した処理が指定条件を満たすまでループされます。
また、パラメータとして[Max Iterations]が存在します。これは無限ループを抑制するためのパラメータで、[Exit Cond.]が必ずfalseになるような条件であっても、このパラメータで指定された回数以上はループが回らないようになっています。

では実際に使ってみましょう。
わかりやすさ重視のため、[Value Processor]をグラフに配置し、[Edit]ボタンを押してFunctionグラフ内に入ります。
そして以下のようにノードを組んでみましょう。

[While Loop]を利用する際、一時変数を設定する[Set]ノードは非常に重要となります。
[Exit Cond.]の条件式内で一時変数を取得し、条件を調べたりする必要が出てくるためです。

まず、[Init]ノードには[Set]ノードで変数iを0で初期化します。
終了条件の[Exit Cond.]は[Get Float]ノードでiを取得し、この値が10以上になったら終了するようにしています。 [Loop Body]はiを取得して1を加算、それをiに再度設定します。つまりインクリメントしているだけです。
[While Loop]の唯一の出力は[Loop Body]の出力となりますので、これをグラフの出力として設定すると結果は最後にiに設定された値、つまりループ終了条件の10という数値になります。
実際に[Value Processor]の結果は"10"となっているはずです。

さて、次はもう少し複雑な処理を行いましょう。1~10までの整数を加算した合計を求めるだけのグラフです。
C/C++Pythonなどを使えば簡単に作れる処理ですが、グラフで再現しようとするとやや面倒です。
答えは以下のようになります。

ここで大切なのは[Sequence]ノードです。
このノードは複数の処理を別個に行うためのノードで、入力コネクタの[In]に最初の処理、[Last]に次の処理を接続します。出力は[Last]の入力結果となります。
Substance 3D DesignerではUEのBlueprintのような、実行コネクタは存在しません。
[Set]ノードを見るとわかりやすいですが、入力は設定する数値、出力は入力に接続した結果をそのまま返します。
ここにさらに[Set]ノードを配置しても、別の変数に同じ数値を入れることしかできず、別の数値を設定することができません。
そのため、[Init]コネクタに接続しているように、2つの[Set]ノードを別々に用意し、[Sequence]ノードで接続する必要があります。

この処理は[Loop Body]でも同様です。
ループで実行する処理は変数viを加算する処理(つまり v += i)と、ループカウントであるiをインクリメントする処理の2つです。
どちらも最終的に[Set]ノードで変数を設定するため、[Init]と同様に[Sequence]を利用する必要があります。

また、[While Loop]の先でも[Sequence]を利用します。
[While Loop]の出力は[Loop Body]への入力で、これはその前の[Sequence]の[Last]ですので、当然変数iの値となります。
最終的に欲しいのはvの値ですので、[Sequence]の[In]に[While Loop]の出力を接続し、[Last]で変数vを取得して接続します。

この結果は"55"となります。[Value Processor]の結果を確認してみてください。

注意

[While Loop]を使用する場合、[Loop Body]に接続したノードとその他の処理で利用するノードの共有に注意が必要です。
どうやら[Loop Body]と[Exit Cond.]は独立したブロックとして処理されなければならないようで、別の部分で使用しているノードを利用すると正常に処理されないようなのです。

以下の画像は先程の処理ですが、①と②と書かれたノードに注目してください。

①は定数である1を設定しているノードで、②は変数vを取得するノードです。
パッと見ではどちらも共有することが可能に見えますので、どちらか一方を削除してもう一方に接続してみてください。
①と②のどちらかだけでも共有してしまうと、[Value Processor]の結果は"0"となってしまいます。
どうやら処理が正常に実行されず、必ず"0"が入ってしまうようです。

ただし、[Loop Body]と[Exit Cond.]は同じブロック扱いのようで、[Exit Cond.]に接続している変数iを取得するノードを[Loop Body]で共有しても問題なく動作しました。 しかしながら、混乱の元になるのできちんとブロック分けはしておくことをおすすめします。

do whileを実現する

[Loop Body]と[Exit Cond.]が同一ブロック扱いなのであれば、[Loop Body]の内容を[Exit Cond.]で処理しても問題ないのでは?
と思ったのでやってみました。

これでも正常動作しました。
[While Loop]ノードは[Init]→[Exit Cond.]→[Loop Body]→[Exit Cond.]→[Loop Body]→...→ループ後処理という順序で処理をしているようです。
ですので、このような接続方法にすることで、C/C++のdo while的な処理も可能ということになります。
ただし、[Loop Body]に何も接続していないとループが回らないようですので、害のないノードを接続しておく必要はあります。

しかし、現在の仕様では可能な処理というだけで、今後も問題なく利用できるかどうかは未知数です。
通常であれば[Loop Body]内で繰り返し処理を行うべきなので、どうしてもという場合以外は使用しないことをおすすめします。

実例 Symmetric Nearest Neighbor

というわけで本題です。
Symmetric Nearest Neighbor (SNN) は絵画っぽい画像フィルタです。
解説とHLSL実装についてはもんしょの巣穴を参照してください。

sites.google.com

このフィルタは以前もSDで作成したのですが、ループ処理がなかったため5x5、7x7、9x9のカーネルサイズで頑張って1つ1つ丁寧に実装していました。
当時作成した9x9の[Pixel Processor]は以下です。

ノード数はそんなに多くないように見えますが、定数を変更して接続して…を繰り返して発狂しそうになりましたね。
しかもカーネルサイズが変更できないですし、これ以上のカーネルサイズは心が折れて実装できませんでした。

では、ループを使って実装したものを見てみましょう。

ノード数はそれなりに多く見えますが、処理の流れも接続もわかりやすいかと思います。
なにより、これだけでカーネルサイズを16まで変更できるようになっています。
なお、カーネルサイズは片側のサイズで指定する形ですので、1を指定すると3x3、16なら33x33で処理します。

[While Loop]は3つ利用しています。これは元のHLSL実装でもforループを3つ使っているためです。
リアルタイム実装でなければ2重ループで全ピクセルに対して処理してもさほど問題ないとは思いますが、慣れるために元実装と似たような処理にしています。
3つの内2つは2重ループで使用しています。2重ループは分かりにくくなりやすいので注意が必要だと思います。
解説を…と思ったのですが、特に解説するところがないので、気になる方は以下からダウンロードして試してみてください。

www.dropbox.com

ご自由にお使いください。
Substance 3D Designerの教科書』で紹介しているKuwaharaフィルタも同様に作成することができるでしょう。
興味のある方は練習がてらチャレンジしてみてもいいのではないでしょうか?

UE4用NVIDIA Image Scalingプラグイン実装について

UE4 Advent Calendar 2021 12/5の記事です。

はじめに

PS4/XboxOne世代は1080p出力が、PS5/XboxSeriesX世代は4K出力が基本になっています。
しかし、大体の場合でレンダリング解像度はそれより低い解像度で行い、ハードウェアのアップスケーラーを利用するか、もしくは何らかのアップスケール技術を使うのが割と基本です。
残念ながら、これからもその状況はあまり変わらないでしょう。

そうなってくると、どのようなアップスケール技術を使うか?が問題になってきます。
現在、アップスケール技術としてよく取り沙汰されるのはNVIDIA社のDeep Learning Super Sampling (DLSS)です。
名前の通り、Deep Learning技術を利用した超解像技術で、Temporal Reprojectionも利用するためアンチエイリアシングの機能も兼ね備えているようです。
UE4でいうならTemporal AA Upsampling (TAAU)の代替手段になります。
ただし、この技術はGeforce RTX以上を必要とするため、ハードウェアが限定されます。
当然、コンソールゲーム機には使用できません。

そのような状況で新しく現れたのがAMD社のFidelityFX Super Resolution (FSR)です。
こちらはDLSSと違い、ハードウェアを限定しません。Shader Model 5.0?くらいが使用できれば使えます。
これは昨今のPCならほぼ全て使えますし、PS4以降のハードでも使用が可能です。
しかもUE4.27.1用ではありますが、すでにプラグインとして公開もされています。

https://gpuopen.com/learn/ue4-fsr/

また、FSRは入力として低解像度の最終レンダリング画像のみを求めます。
アンチエイリアシングは別途行う必要がありますが、FSR自体にゴースティングの心配はありません。

UE5ではTemporal Super Resolution (TSR)が追加されています。
こちらはUE4への移植も可能ではありますが、一応PS5/XboxSeriesX世代以降対応ということになっています。
PS4世代で動作するかは不明です。
この技術はTAAUの代替手段ですので、アンチエイリアシング機能も含まれます。

さて、つい先月、DLSSのバージョンが2.3になりました。
しかしそれと同時に、新しい超解像技術も発表されました。
それがNVIDIA Image Scaling (NIS)です。

https://github.com/NVIDIAGameWorks/NVIDIAImageScaling

このアップスケーラーもFSRと同様に、最終出力のみを受け取りアップスケールします。
アンチエイリアシングは行いませんが、やはりNIS自体にゴースティングは発生しません。
加えてコンピュートシェーダによる実装であり、Shader Model 5.1以上に対応していれば利用可能です。
今どきのPCならどんなGPUでも使えますし、PS4世代でも使えるはずです。

残念なことに、まだNISUE4プラグインは提供されていません。
発表されたばかりだからということもあるかと思いますが、そのうち出てくるんじゃないかとは思います。

プラグインを作った話

が、そのうち出てくるだろうと思っていまテストしてみたい!FSRと比較したい!
そう思ったので作ってみました。

https://github.com/Monsho/NISPluginForUE4

一応ライセンスはMITにしています。NIS SDKがMITライセンスなので。
インストールについてですが、Readmeを読んでください。
残念ですが、ビルド済みバイナリは含めていませんので、エンジンに突っ込んでビルドしてください。
プラグインの追加だけなのでエンジンコード自体は汚しません。

なお、UE4.27.1以上対象のプラグインです。
UE4.26以下では利用できません。UE4.27.0なら使えるかも。
というのも、FSRプラグインを参考にして作ったのですが、そこで使用されている機能がUE4.27で追加された機能なので。

以降ではその辺の機能や、プラグイン作成時の注意点について簡単に解説します。

プラグイン解説

ISpatialUpscaler

実は、FSRUE4.26から対応していたのですが、その頃はエンジンコードを変更するパッチとして提供されていました。
UE4.26ではTAAをサードパーティ製に置き換える手段は用意されているのですが、FSRは最終段のPrimary、もしくはSecondaryのUpscalerを置き換えるものなのでTAAの置換手段は利用できません。
なお、DLSSはこのTAAを置換する手段を用いてプラグインを実装しています。

しかしFSRプラグイン実装のためなのか、UE4.27ではこのPrimary、SecondaryのUpscalerを置換する手段が用意されました。
これを利用するにはISpatialUpscalerを継承したクラスを作成し、FSceneViewFamily::SetPrimarySpatialUpscalerInterface()、もしくはFSceneViewFamily::SetSecondarySpatialUpscalerInterface()で登録する必要があります。
これが登録されているとデフォルトのアップスケーラーの代わりに、プラグインで実装したアップスケーラー、つまりFSRNISを実行できるという仕組みです。

FSceneViewExtensionBase

ここで注意点。
FSceneViewFamilyは基本的に毎フレーム生成・削除が行われるようです。
そのため、ISpatialUpscalerを継承したクラスは毎フレーム登録する必要があります。
そこでFSceneViewExtensionBaseを利用します。

このクラスを継承したクラスは生成時に自動的にエンジンが持っているViewExtensionsに登録されます。
ViewExtensionsに登録されているクラスは、ViewFamilyのセットアップ時や描画の開始・終了時にViewFamilyに対して追加処理を行うことができます。
NISプラグインでは、FNISViewExtensions::BeginRenderViewFamily()関数が描画開始時に実行される関数で、ここでPrimaty UpscalerにFNISUpscalerを登録しています。

登録する場合は常にnewする必要があります。
FSceneViewFamilyが削除されるタイミングで登録したUpscalerも勝手に削除されるためです。
寿命管理はこちらで制限できなので、TSharedPtrなどで作成してポインタだけ登録する、というような手法は使えないと考えてください。

FNISUpscaler

実際にNISを実行しているのはこのクラスです。
FNISUpscaler::AddPasses()関数でNISを実行するパスを追加しています。

ここでもまた注意点があります。
FSRはコンピュートシェーダでもピクセルシェーダでも実装することができるのですが、NISはコンピュートシェーダのみの実装となっています。
つまり、NISの出力テクスチャはUAVでなければならないのですが、最終出力となるPassInputs.OverrideOutputはUAVとして使用できません。
そのため、NISプラグインではUAVとして使用できる2Dテクスチャを作成し、ここにNISレンダリングしてから最終出力にコピーするという手段を用いています。
ピクセルシェーダでも実装できるなら良かったのですが、NISはLDSを使用してるっぽいので無理なんですよね…

また、NISでは係数を保存したテクスチャを渡す必要があります。
この係数はNISが用意しているもので、入力画像によって変化するものではありません。
そのため最初に生成するだけでよいのですが、FNISUpscalerは毎フレーム削除されてしまうので、コンストラクタで生成・デストラクタで破棄とやるのは大変無駄です。
そこで、コンストラクタで外部から渡すという手法を用いているのですが、ここでちょっと面倒なことが…
この理由も含めて次節で解説します。

2つのモジュール

NISプラグインImageScalingImageScalingExtensionという2つのモジュールから成り立っています。
FSRも同様の仕様なのですが、わざわざ2つのモジュールに分けているのは初期化タイミングの問題のためです。

まず、FNISUpscalerはグローバルシェーダを利用するため、独自のシェーダを利用できるように登録する必要があります。
そのためにモジュール開始時にシェーダのディレクトリを登録することになるのですが、この場合のモジュールはPostConfigInitで実行されなければなりません。
このタイミングはエンジン初期化より前のタイミングであるため、この設定になっているモジュールの初期化段階ではエンジンの機能を利用することができないのです。

エンジン初期化の前にできないこととは何かというと、それはViewExtensionの登録とテクスチャの作成です。
FNISViewExtensionを作成してしまうと自動的に登録されてしまうわけで、その登録先はエンジンなわけです。
テクスチャ生成もRHIなどを利用するため、エンジンが初期化されていなければ実行できません。
グローバルシェーダを使うためにはPostConfigInitでなければならないが、ViewExtensionを生成するのはPostEngineInitでなければならないのです。

そのためにViewExtensionを生成するためのモジュールが必要になります。それがImageScalingモジュールというわけです。
テクスチャ生成もこのモジュール開始時に行い、FNISViewExtensionに登録しています。
FNISUpscalerが利用するテクスチャはさらにFNISViewExtensionから渡されるという形になっています。
面倒ではありますが、こうする以外の方法を見出すことができませんでした。

使い方の注意

NISプラグインを使う場合の注意点として、FSRとの併用はできないという点に注意してください。
プラグインを両方とも有効にすることはできますが、その状態でFSRNISを有効にするとISpatialUpscalerの登録時にチェックで引っかかります。
チェックを無視すれば先に進めることはできますが、多分メモリリークとなります。

FSRはデフォルトで有効になってしまうので、NISはデフォルトで無効にしています。
NISを利用する場合はまずFSRを無効にしてから(r.FidelityFX.FSR.Enabled = 0)、NISを有効にしましょう(r.NVIDIA.NIS.Enabled = 1)。 その逆もまた同じです。無効にしてから有効にする。これを守りましょう。

もう1つ。これはFSRでも同様ですが、テクスチャのミップレベル調整は自動的に行われません。
r.ScreenPercentageで設定したパーセンテージに合わせて、r.MipMapLODBiasの値を調整しましょう。

比較

1440pネイティブ f:id:monsho:20211205022850p:plain

720p->1440p デフォルトアップスケーラー f:id:monsho:20211205022946p:plain

720p->1440p FSR f:id:monsho:20211205023317p:plain

720p->1440p NIS f:id:monsho:20211205023241p:plain

さいごに

このプラグインは現段階ではWindowsPCのD3D12バージョンでしか動作を確認していません。
他の環境で動作するかという点については不明です。
多分動くんじゃないかとは思うのですが、シェーダコンパイルで失敗するとかの可能性はあると思います。
そうなった場合はバグを修正してプルリクでも投げてください。

というわけで今年のAdvent Calendar記事はこれにて終了!
前回の更新も去年のアドカレだったんだなぁ…

NVIDIA RTXブランチについて

Unreal Engine 4 アドベントカレンダーその1 2日目

はじめに

今年、Ray Tracing Night Week 2020にてUE4レイトレのアップデートについて講演を行いました。

UE4.25のレイトレーシングで出来ること/出来ないこと

この中で謎の半導体メーカーであるNVIDIA様のRTXブランチについて言及したところ、これについての質問が寄せられました。
質疑応答の際に答えはしたのですが、動画内で言葉だけで説明したのだとわかりにくいですし機能についてもよくわからないと思いますので、ブログにて簡単ですが紹介させていただこうと思った次第です。

この記事はRTXブランチに興味がある方向けのものですが、エンジンビルドについては言及しません。
エンジンビルドについて知りたい方は株式会社ヒストリア様の以下の記事を参考にしてください。

historia.co.jp

また、あくまでもRTXブランチ紹介記事ですので、以下のような方は対象としていません。

  • RTXブランチをすでに使っている方
  • NVIDIA社の中の人

ソースコードのダウンロード

RTXブランチのソースコードGitHubから行います。URLは以下です。

https://github.com/NvPhysX/UnrealEngine/tree/RTX-4.25

ブランチは他にもいくつかあり、RTX以外のブランチも多く存在していますが、今回はそちらの解説は行いません。
URLにアクセスしても見られないという方はGitHubのアカウントを作成し、Epic Games様のUE4ソースコードにアクセスできるようにしましょう。
ダウンロードからビルドの流れは前述の記事の通りです。

現在はUE4.25までしか対応していませんが、UE4.26が正式版になるとそちらへのマージ、対応が行われる可能性があります。

機能について

このブランチの目的はNVIDIA様がレイトレーシングの様々な機能のテスト、パフォーマンス調整を行うものと思われます。
ここで実装された機能がUE4本流にマージされている例もあります。 機能についての簡単な解説はREADME.mdファイルに記述されているので、とりあえずどんな機能があるかを知るだけならGitHubのWebページでも見ることが出来ます。

以下で各機能について解説を行いますが、一部の機能については少し詳しく解説を加えています。

Direct Optimizations

出力結果に変化がない、特にデメリットのない最適化です。
必ず高速化するわけではありませんが、使用することで映像に変化があるということは基本的にありません。

バウンス回数の固定

UE4のリフレクションではマルチバウンスに対応しており、バウンス回数は変更可能です。
リフレクションシェーダは内部にバウンス回数に対する動的なループを持っていますが、動的なループは基本的に負荷が高くなります。
シェーダコンパイル時にループ回数が固定できると動的ループが展開され、一般的には高速化します。
この修正はそのループ回数を固定してシェーダコンパイルが可能な修正ですが、現在はバウンス回数が1回のときのみ固定されます。

半透明マスキング

UE4のレイトレ半透明は画面全体にレイトレースを行いますが、半透明マテリアルにレイが衝突しないピクセルでもレイトレースします。
これは無駄なので、一旦半透明メッシュをステンシルバッファに描画し、ステンシルでマークされた部分以外はレイトレースをキャンセルします。
画面全体を半透明メッシュが覆うような状況では高速化しない可能性がありそうですが、r.RayTracing.Translucency.MaskのCVarでON/OFFを切り替えることができるので、これを使ってパフォーマンス計測しましょう。

インスタンススタティックメッシュ(ISM)のカリング最適化

FoliageのISMのカリングを最適化しています。
ISMカリングのCPU負荷が高い状況では有効な機能です。

動的メッシュのバッチ作成の並列化

レイトレ界に登録する動的メッシュは静的メッシュとは違った処理を行う必要があります。
そのためのコマンドを発行する部分は通常では並列化されていませんが、大量に動的メッシュがある場合に不利になります。
r.RayTracing.ParallelMeshBatchSetupのCVarをONにすることで動的メッシュの処理を並列化出来ます。

マテリアルバインドの高速化

r.RayTracing.BatchMaterialsでON/OFFできる機能で、マテリアルバインド処理を単純化することで高速化するもののようです。
バインドするマテリアル数が多い状況で高速化するのかな?

Quality Tradeoffs

これらの最適化は映像クオリティとのトレードオフを要求します。
コメントでは違いを見つけるのは困難な程度のしきい値で設定されていると書かれています。

シャドウレイのシザリング

ポイントライトなどの効果範囲が限定されるライトでは画面全体をレイトレースせずに効果範囲のみをレンダリングするほうが効果的です。
どうやらこの機能はレイトレースシャドウを効果範囲でシザリングする機能を提供しているようです。
単純なレイトレースシャドウであればトレードオフはありませんが、デノイザーが絡むとシザーボックス境界付近に問題が出ることがあります。

影を落とすライトの優先度付け

r.RayTracing.Shadow.MaxLightsr.RayTracing.Shadow.MaxDenoisedLightsがCVarに追加されます。
この指定によってシャドウを落とすライトの数を制限することが可能です。
制限されるとライトを距離や範囲で優先度付けして、優先度の高いものから順に制限数までシャドウを落とすようにします。
この設定はMovableライトには適用されず、Static, Stationaryライトに適用されます。

また、r.RayTracing.Shadow.FallbackToSharpを利用すると、エリアライトで本来ならデノイズが必要なレイトレースシャドウをシャープな影にしてデノイズを避けるようです。

ライトの優先度付け

リフレクションやGIではレイトレースしてヒットしたマテリアルに対してライティング計算を行います。
この際に影響するライトの数はエンジン側で256個で制限されていますが、シーン中にはそれを超えるライトの配置が可能です。
配置されているライト数が256を超える場合、デフォルトでは頭から順に256個を利用するようにしますが、この機能を使うことでライトに優先度を付けて上位から選択するようにします。
r.RayTracing.Lighting.MaxLightsは登録するライトの個数を指定します。優先度付けしたライトを指定個数まで登録するようになります。
r.RayTracing.Lighting.MaxShadowLightsはリフレクションなどのライト計算時にシャドウレイを飛ばすライトの個数を制限します。
これらの設定は単純なカリング処理となるので、大量にライトが配置されている場所ではポッピングするので注意してください。

f:id:monsho:20201122102039p:plain

ライトの優先度付けルールはr.RayTracing.Lighting.Priority.~である程度の調整ができますので、ゲームに合わせて対応すると良いでしょう。
例えば屋外の場合はフラスタムを重視するほうが良さそうですが、屋内の狭い部屋ならカメラ周辺やカメラ後方を重要視したほうがいいかもしれません。

ラフネスへの乗算値

ラフネスが高いと反射レイは様々な方向に飛んでノイズが大きくなります。するとデノイズでは間に合わなくなり、もやもやしたノイズが残ることになります。
ラフネス値をマテリアルごとに調整する事もできますが、大変ですしラスタライザでのライティング結果にも影響を及ぼします。
r.RayTracing.Reflections.RoughnessMultiplierを利用すると、レイトレリフレクションのときのみラフネス値に補正をかけることが出来ます。
r.RayTracing.Reflections.MaxRoughnessと違ってレイトレをキャンセルすることはありませんが、ノイズの調整には扱いやすいと思います。

Enhanced Features

UE4本流にはない機能を追加しています。
あなたのアプリケーションに必要な機能が見つかるかもしれません。
見つけてしまった場合、Epicさんにマージ要求するか、自前でマージしましょう。

Hybrid Translucency

Ray Tracing Night Week 2020でも言及した機能で、デフォルトのレイトレ半透明の代替として使用することが出来ます。

デフォルトのレイトレ半透明は半透明に対する反射と屈折を1つのレイトレシェーダ内で別のレイトレースで実現します。
この手法は高品位ではあるものの、処理負荷が高く、その上半透明が多重に重なっている場合に問題が発生することがあります。

Hybrid Translucencyは反射のみをレイトレで対応し、屈折についてはこれまでどおりのラスタライザで対応します。
反射は別バッファにレンダリングすることで対応しますが、複数の重なりに対してはレイヤー数を増やしてカバーします。
レイヤー数が少なければデフォルトのレイトレ半透明より負荷が軽くなる可能性が高く、また、半透明の重なりによるレンダリングエラーにも対応しやすいので映像作品よりゲーム作品向けと言えます。

詳しくはshikihuikuさんの記事をご覧ください。

UE4 RTX-4.23ブランチのHybrid Translucencyは何をしているのかshikihuiku.wordpress.com

ライトファンクション、ライトチャンネル

UE4本流では対応していないライトファンクションとライトチャンネルに対応する修正です。
これらの機能を多用しているアプリケーションではマージを検討したほうが良いでしょう。
特にライトチャンネルはパフォーマンスが上がることもあります。

余談ですが、UE4本流では使用されていないCallable Shaderがライトファンクションでは使われています。
自分も使ったことがなかった機能なのでちょっと感動したけど、PSやCSでもCallable Shader使いたい…

Cast Static Shadows/Cast Dynamic Shadows対応

デフォルトではリフレクションのシャドウキャスト設定はCast Shadowsフラグだけをチェックしていますが、RTXブランチではCast Static Shadows/Cast Dynamic Shadowsにも対応しています。
ただ、フラグに対応しているというだけで、静的/動的なメッシュにきちんと対応するわけではなく、この2つのフラグが落ちていたらシャドウを落とさない、という形になるだけです。

非対称ScreenPercentage

レイトレリフレクション/GIではScreenPercentage設定が存在しますが、この設定は細かく調整されているわけではなく100%(デフォルト)の後は50%、25%という順番で下がっていきます。
つまり、縦横が1/2、1/4という形でしか下がっていきません。

この修正では縦横比が変わる形での調整ができるようになっていて、70%では横だけが1/2になります。
50%だとどうしても汚くて困る、という場合に試してみると良いかもしれません。

Subsurfaceのバックフェースライトカリング

UE4本流では一部のシェーディングモデルにおいて、ライトの方向と法線方向が水平より下(つまり背面)になっている場合にシャドウレイの発射をキャンセルする機能があります。
DefaultLitでは特に問題ないようですが、Subsurfaceでは陰影のエッジが非常に汚くなってしまいます。
r.RayTracing.Shadow.CullTransmissivesを利用すると正しくシャドウレイを飛ばすようになり、陰影のエッジが綺麗になります。

f:id:monsho:20201122114505p:plain

Debugging & Visualization Features

デバッグ用の機能追加です。

BVHの視覚化

ShowFlag.VisualizeBVHComplexity/VisualizeBVHOverlapを利用してBVHの複雑さを視覚化出来ます。
レイトレーシングではオブジェクトやポリゴンが重なり合っている部分では処理負荷が高くなる傾向がありますので、できる限り分散して配置した方が有利です。
この機能を使って負荷が高い場所、つまり重なりが複雑な部分をチェックしてパフォーマンス改善に役立てることが出来ます。

f:id:monsho:20201122120758p:plain

レイトレーシング負荷の視覚化

ShowFlag.VisualizeRayTimingを利用してレイトレーシング自体の負荷を確認することが出来ます。
レイトレは様々な要素がパフォーマンスに複雑に関わってくるため、この視覚化はマテリアルの複雑性のみを視覚化しているわけではないことに注意してください。
また、レイの反射方向などによって結果が大きく変わるためか、かなりノイジーです。
しかし、明確に重い部分はわかりやすいので、最適化の指針としては十分使えるでしょう。

f:id:monsho:20201122121941p:plain

Miscellaneous Features & Fixes

その他の機能です。

半透明マテリアルのシャドウ対応

UE4本流では半透明マテリアルもシャドウを落とす設定になっています。
オブジェクト単位、マテリアル単位でシャドウキャストフラグを操作する方法ももちろんありますが、r.RayTracing.ExcludeTranslucentsFromShadowsを利用することで一括で半透明マテリアルのシャドウを削除できます。

ただ、エディタ上でON/OFFした場合、何故か即時反映はされず、メッシュのCast ShadowフラグをON/OFFし直したらそのメッシュだけ適用されるという状態になりました。
不具合なのか仕様なのかは不明ですが、やはり明示的にマテリアル側で指定するほうが良いでしょう。

シャドウの遮蔽面の統一

レイトレシャドウなどの遮蔽はデフォルトで表面、裏面ともにシャドウを落とします。これはr.RayTracing.Shadows.EnableTwoSidedGeometryをOFFにすることで片面のみシャドウを落とすようにすることが出来ます。
しかしこのシャドウを落とす面がシャドウマップとレイトレで逆になっているという問題があります。

f:id:monsho:20201122124629p:plain

r.RayTracing.OcclusionCullDirectionをONにすることで、この逆転現象を解消することが出来ます。

f:id:monsho:20201122124759p:plain

メッシュが閉塞されている場合は意味がない機能ではあるのですが、時折ペラ1枚の書き割りなどを利用することがあったりします。
このような場合で両面シャドウで代用できない場合には有効な機能ですが、かなり使用場面は限定されるのではないかと思います。

さいごに

先日ぷちコンゲームジャムでレイトレ半透明を利用してレンズ越しにのみ表示されるマテリアルという特殊な環境を作ってみました。
この際にRayTracingQualitySwitchReplaceを利用したのですが、OpacityMaskに利用したところ半透明越しじゃなくても表示されてしまうという不具合にぶつかりました。
この理由が普通に半透明部分以外もレイトレして、普通にライティング計算しているからだったわけなのですが、エンジン側のシェーダを修正して対応しました。

その後、この記事を書いていて気づいた。

RTXブランチの半透明マスキング使えばエンジン改造しないで済んだじゃん!

NVIDIA様、さすがでございます。

明日はUE4でアニメーションといえばこの人、”無敵の龍”ほげたつさんのControl Rigの記事です。 お楽しみに!

Substance Designerでシェーダを書いてみた話

ちょっと遅くなりましたが、先々週にあったSubstance Designerゆるゆる会で作成したマテリアルについてです。

ゆるゆる会のテーマはスタイライズドでした。
私が選んだのは『あつまれ どうぶつの森』に出てくる床の1つである”みなものゆか”でした。

f:id:monsho:20201101141808p:plain

この床はゲーム中で動きます。また、カメラを動かすと白っぽい部分(コースティクス的な?)と青い部分に視差があることがわかります。
いわゆるParallax Mappingを施されているテクスチャです。
で、まずは普通にそれっぽく再現するところから始めてみました。出来たのがこれ。

f:id:monsho:20201101143104p:plain

色味とかに差はありますが、まあ似た感じになったかなと。
しかし物足りない。
原因は2つ。動かない。視差がない。
え?再現性が低い?ごめんなさい…

とにかくこの2つをなんとかしたい。
動かない点についてはSubstance Designerの性質上仕方ない部分もありますが、timeパラメータを使って対応すると確認が難しい上に、パラメータが変更されるとテクスチャが生成し直しになるので時間がかかります。
これくらいのマテリアルならそこまで遅くはないものの、なめらかに動いているようには見えません。

もう1つの視差がない点については、Substance DesignerにはParallax Occlusion Mappingが存在しています。
これを使えば再現できるかというと、これは無理です。
POMは高さ方向でOcclusion、つまり遮蔽されてしまうので、例えば白い部分を高くするようにしてしまうとその部分が山になっているように見えてしまいます。

通常、この手の表現はシェーダ側で行います。UE4のマテリアルなんかが最終出力はシェーダですね。
しかしSubstance Designerの最終出力はテクスチャです。シェーダではありません。
テクスチャというのはシェーダで利用するリソースの1つでしかありません。実際、Substance Designerでもシェーダは使われていて、3DビューメニューのMaterialからプリセットのシェーダを選択することが出来ます。
しかしこの中にはみなものゆかを表現できるシェーダが存在しません。

ないなら作れ!

というわけで作ってみました。

f:id:monsho:20201101150925p:plain

似たような感じではありますが、カメラを動かすと水面と水底に視差があるように見えます。
そして水底の影が水面のコースティクスを参照するようになっています。
このように、Substance Designerは(Painterもですが)自作のシェーダを使用することが出来ます。

シェーダの解説は行いませんが、作成されているシェーダとこのマテリアルはゆるゆる会のTrelloにアップロードされていますので、興味ある人は試してみてください。

trello.com

Substance DesignerのシェーダはGLSLで書く必要があります。書けるのはオブジェクト表面用のシェーダだけで、ポストプロセス的なものは出来ません。マルチパスレンダリングも無理。
しかし環境マップやライト情報も取得できるのでライティングも出来ます。カメラ情報も取得できるのでカメラ角度に応じた変化も対応できます。

とはいえ、書き方やパラメータ設定の仕方はGLSLを知ってるだけでは難しいでしょう。
そんなあなたに朗報です。なんと、ビルトインシェーダのコードが読めます!
以下のフォルダを開いてみてください。

$(SubstanceDesignerインストールフォルダ)\resources\view3d\shaders

ここにビルトインされたシェーダが入っています。
このフォルダ直下にある.glslfxファイルはどのシェーダステージにどのシェーダコードを利用するか、パラメータはどんな名前で設定するか、テクスチャはどんなIDで設定するかといった内容を記述します。
実際のシェーダコードはこのフォルダ内の各マテリアル名のフォルダにあります。
頂点シェーダやテッセレーションはあまりいじることはないかもしれませんが、その場合はcommonフォルダ内にデフォルトのシェーダがあるのでそれを使うことが出来ます。
もちろん、頂点シェーダも作成することも可能ですが、多くの場合はそこまでする必要はないでしょう。

シェーダが書けるという点ではSubstance Painterでも書くことが出来ますが、SDとの互換性がなさそうな感じです。
なぜそこに互換性がないのか…謎。

もしシェーダの内容に質問などがあるようでしたらコメントなりいただければ追記しますが、特に難しいことはしてないです。多分。

でまあ、こんな感じでシェーダを書くことに意味があるのかという話をしてしまうと、多分ほとんどの場合では必要ないです。
しかしゲームエンジンを使うにしろインハウスエンジンを使うにしろSubstance DesignerやSubstance Painterと同じ結果にするというのはなかなか難しいです。
ポストプロセスの問題もありますが、ライティングモデルが別だったり、それこそトゥーンシェーダのようなPBRではないライティングを行っているものもあるでしょう。
そういった違いが制作効率を下げるような状況であれば十分使えるはずです。
とはいえ、SPならともかく、SDで使うことはほとんどないと思います。
こんな事もできるよ~という程度のものとして覚えておくくらいで良いでしょう。

Substance Designer + UE4でWangのタイルを実装してみる

3/14に開催した第6回Substance Designerゆるゆる会のテーマは地面でした。
特に自然か人工かは指定していない、一般的にGroundとして扱われるもの全般ということでいろいろな地面を参加者の方が作っていらっしゃいました。
SDの会だってのにHoudiniの解説しかしない人が出てくるという珍事もありましたが、盛況に終わったのではないかと思います。

さて、そのHoudiniの解説しかしなかったちょっとあれな人は骨折して会場に来れなかったということでリモートで参加されていたのですが、もんしょさんの作ったものはブログで解説してくれるんですよね?とか言ってきたわけで。
解説予定もなかったのですが、そう言われたら解説するしかないやろってことで解説します。

私はSandy Groundという名前で一応砂地に石が混じってるような地面を作ったのですが、割と簡単に作ったもので特筆すべき部分はありません。

f:id:monsho:20200315201942p:plain

こんな感じ。

砂地の地面の部分は凹凸もほとんどなく、砂粒のノーマルと荒野っぽさを少し出すためにちょっとした段差が入ってる程度です。
もちろん石の部分は高さがありますが、埋まってる設定なのでちょっと頭を出してる程度。
石は最近追加された [Atlas Scatter] ノードを使っていますが、Atlasで作成した石は本当に適当に作りすぎてヤバいレベルです。
この辺はゆるゆる会で解説したのでここでは割愛します。

このマテリアルには実はちょっとした仕掛けが施されています。
それがタイトルにあるWangのタイルです。
Wangのタイルとはどういうものかというと…面倒なので以下のサイトを参照してください。

www.pathofexile.com

図にあるようにテクスチャを16分割し、縦の青いライン、横の青いライン、縦の赤いライン、横の赤いラインはすべて接続が可能にします。
タイルに1~16の番号を付けた場合、 1番タイルの右側は赤いラインなので、赤いラインを左側に持つタイル(4番とか9番とか)と接続できるわけです。
このようにタイルごとの接続情報を利用していくらでも置き換えができ、かつ無限とも言えるような接続パターンで接続していける、いわゆるタイリングパターンを見せないでタイリングができるというわけです。

実際にUE4でやってみたのがこちら。

f:id:monsho:20200315205025p:plain

左は普通のタイリング、右はWangタイルです。
左はタイリングがバレバレですが、右はある程度のパターンが見えるものの、明らかにタイリングパターンがわかりにくくなっています。

では、どのように作成しているかというと、上のサイトで使われているものをほぼそのまま踏襲しています。
ただしノーマルやラフネスなども同様にWangタイルを作成する方法で、上のサイトのようなベースカラーだけWangタイルをして、その結果からノーマルを求めるという形は採用していません。

縦/横の青/赤ラインの対応する部分はすべて同じ場所からテクスチャを持ってきます。
ただの長方形をそのまま割り当てるのは良くないので、接続部はノイズで歪ませたブレンドマスクを使ってブレンドしています。
また、四隅の部分はすべてのタイルで接続ができなければならないので四隅だけはすべての場所で同じ場所からテクスチャを持ってきてブレンドします。
こうすることでそれぞれのタイルの対応するラインが接続可能になります。

注意点としては、接続に使用するテクスチャはあまり特徴的すぎないほうがいいという点です。
あまりに特徴的すぎるとその特徴が縦横に連続することになるので割とバレます。
残念ながら今回作成したWangのタイル生成用グラフはそういう特徴が出ないように手で調整するという形を採用していますが、よりよい結果を求めるのであればDeep Learningなどを利用して自動的にいい感じの場所をいい感じにブレンドしてもらうようにすべきでしょう。
現在のSubstance Designerには出来ませんが、将来的にはSubstance Alchemistでできるようになるかもしれませんね。

UE4のマテリアルはこんな感じです。

f:id:monsho:20200315210811p:plain

Customノードを多用していたり、なにげにDetail Normalを使っていたりしますが、コピペすれば多分使えるはずです。
今回はタイルパターンが元のUV値に合わせて自動的に生成されるようになっていますが、自前のパターンテクスチャを使用することももちろん可能です。
その場合は接続が正しくなるようにパターンを生成する必要があるので注意してください。

また、この手法は普通にテクスチャサンプリングしてしまうと接続部分でミップレベルがおかしくなるという弱点がありますが、こちらもミップレベルを自前で計算するという手法で対応しています。
その関係でテクスチャのサイズを指定しなければならないのがちょっと面倒です。

以下はWangのタイルでリンク場所がバレバレな失敗例。

f:id:monsho:20200315212824p:plain

四角いタイル形状が非常にわかりやすいですね。
これは元マテリアルにPerlinノイズによる緩やかな傾斜を与えた場合の結果ですが、なぜこうなるかというとノーマルマップを見るとうっすらわかります。

f:id:monsho:20200315213221p:plain

緩やかな凹凸から生成されたノーマルが思いっきりずれてしまっていて、ノーマルの段階でタイルの接続部がバレるようになってしまっています。
今回のSandy Groundマテリアルはこのような問題に引っかからないように注意して作成されているのです。

というわけで適当ではありますが解説はこれで終了します。
マテリアルはTrelloの方で公開していますし、UE4のアセットも内包するReadmeにリンクを書いておいたので、そこからダウンロードできるようになっています。

trello.com

興味がありましたらDLして調べてみてください。

BlenderとDem Bonesでブレンドシェイプをボーンモーションにする

つい先日のことですが、Electronic ArtsさんがDem Bonesというライブラリを公開しました。
GitHub上で、BSD 3-Clauseライセンスとなっています。

github.com

ヘッダオンリーライブラリで、依存しているのもEigenとOpenMPくらいらしいので、自前ライブラリに組み込んだりDCCツールのプラグインを作ったりしやすいと思います。

GitHub上ではコードの他にサンプル的なコマンドラインツールも付属しているので、とりあえず試してみるということが簡単にできます。
というわけで、Blenderブレンドシェイプとそれを使ったアニメーションを作り、これをDem Bonesで変換するという一連の流れを試してみました。

Blenderでベースメッシュを作成する

まずはBlender上でベースメッシュを作成します。
といっても普通にメッシュを作るだけですが、その段階でブレンドシェイプも仕込んじゃいましょう。

とりあえずはスザンヌさんにご登場願い、これをベースメッシュとします。
そして、ブレンドシェイプを適当に追加。

f:id:monsho:20200130230228p:plain

追加したシェイプキーを選択した状態でEdit Modeで頂点を編集すればブレンドシェイプを作成できます。
編集後、Object ModeでValueの値をいじってみてブレンドシェイプが有効になっているかどうかチェックしましょう。

ここまでのデータをFBXで出力します。
ここで出力したFBXのベース形状がボーンを埋め込んだスキニングメッシュのベースポーズとなります。

出力時の注意ですが、FBX Export設定のScaleを0.01にしておきます。
BlenderでのFBX出力サイズとAlembic出力サイズがどうも異なっている (というか、Dem BonesがFBXの単位を考慮してない?) ようなので、これをやっておかないとDem Bonesで変換したFBXのモーションがおかしくなります。

f:id:monsho:20200130231244p:plain

ブレンドシェイプアニメーションを作ってAlembicを書き出す

次にブレンドシェイプを使ってアニメーションを作成します。
特に難しいことはなく、時間変化に合わせてシェイプキーのValueにキーを打つだけです。

f:id:monsho:20200130231211p:plain

満足したアニメーションが出来たらAlembic形式で出力します。
特に設定は必要ないので、ファイル名だけ指定して出力しましょう。

Dem Bonesで変換する

GitHubからDem Bonesをダウンロードしたら bin フォルダの中に DemBones.exe があることを確認します。
そしてコンソールウィンドウを出し (PowerShellでOKですし、batファイルを作ってもいい)、次のようにしてDem Bonesを実行します。

DemBones.exe -a="Alembic File.abc" -i="Base Mesh.fbx" -o="Skeletal Mesh.fbx" -b=n

オプションの指定方法は -x=~ で、ファイルパスを示す場合は "" で囲みます。
-a オプションは必須で、ブレンドシェイプアニメーションを施したAlembicファイルパスを指定します。
-iオプションも必須で、こちらがベースポーズを指定するFBXファイルとなります。
-oオプションも必須で、こちらがボーンを組み込んだ出力FBXファイルです。
-bオプションはボーンの組み込みが行われていないベースFBXを指定する場合は必須となり、ボーン数を指定します。
ベースポーズのFBXには予めボーンを仕込んでおくことも可能なようですが、これは1つのメッシュに複数のブレンドシェイプアニメーションを施す場合に使用するのではないかと思われます。

とりあえずこれでデータに問題がなければ-oオプションで指定したFBXファイルが出力されるので、Blenderで読み込んでみましょう。
Import設定でScaleを100倍するのを忘れずに。

f:id:monsho:20200130233139p:plain

こんな感じにボーンが埋め込まれてモーションしたら成功です。
出力時のScaleを設定しておかないと、モーションしたらメッシュがクシャッとなってしまうので注意しましょう。

というわけで、簡単なDem Bonesの使い方でした。