さやちゃんぐbotブログ

シェーダーで遊んだりするブログです。

MMDをレイマーチングエディタにする。

はぁい、どぅもぅ。さやちゃんぐbotです。

f:id:sayachang_bot:20200315204422p:plain

唐突ですがMMDでシェーダーお絵描きを始める方法を書きます。

これであなたのMMDはレイマーチングエディタに変貌します!

今回は環境の作り方から、レイマーチングを描くためのfxファイル(HLSL)サンプルの紹介までしていきます。

さっそくやって参りましょう!Windows環境があればすぐにMMDでレイマーチングを描き始めることができます!!

 

MMDでレイマーチングを動かすシェーダーのサンプルはこのリンクからご参照ください。

https://scrapbox.io/api/code/sayachang/MME/RaymarchSample.HLSL

MMD(MikuMikuDance)にはエフェクト(シェーダー)を使うための拡張ツールMME(MikuMikuEffect)があり、パーティクルやポストエフェクトを実装できます。

で、画面表示前に割り込んで処理するポストエフェクトのシェーダーが描けるということは、配置したモデルデータとかをまるっと無視して画面に直接シェーダーのお絵描きができるということです。

これでKodeLifeのようなツールでGLSLを描くのと同じノリで、MMD/MMEでHLSLを描くことができるようになります。

 

さて、はじめにMMEに馴染みがない人には、CodeZineの記事を読むことをオススメしておきます。今回のレイマーチング記事は、この連載記事を書いているビームマンPにいろいろ質問した結果を元に作成しております。ありがとうビームマン。

MikuMikuEffectで学ぶHLSL入門

codezine.jp

また、MMEにはHLSLを書く上での丁寧な説明を記載したREFERENCE.txtが同梱されているので、折に触れてこちらも参照すると良いでしょう。

 

が、これらを読まなくてもとりあえずシェーダーをいじる状態にするまでの手順はこの下に書いてあるので大丈夫です。いたれりつくせり。

まずはMMDとMMEをダウンロードし、zipをディスクに解凍します。

sites.google.com

w.atwiki.jp

f:id:sayachang_bot:20200315210017p:plain

また、今どきのWindows10マシンなどではVC++のランタイムが必要になります。

vcredist_x64.exeをインストールしましょう。

https://support.microsoft.com/ja-jp/help/2977003/the-latest-supported-visual-c-downloads

MikuMikuDance.exeが起動できて、ウィンドウ右上にMMEffectのメニューがあらわれればここまでの環境作成はOKです。

メニュー「背景->背景黒化」で背景を白から黒に変更しておくとエフェクトが確認しやすくなります。
ショートカットCtrl+Shift+EでMMEのオン/オフ切替ができます。エフェクトを切りたい場合はこのショートカットが便利です。

 

さて、MMEでシェーダーを使用する方法は2通りあります。

アクセサリでエフェクト(シェーダー)を使う

f:id:sayachang_bot:20200315210436p:plain

MMDではDirectXの3D形式であるxファイルが利用できます。モデル操作メニューでドロップダウンから「カメラ・照明・アクセサリ」を選択した状態にするとアクセサリ操作が使えるようになり、ここの読込ボタンからxファイルを読み込みます。

ポストエフェクトのfxファイルをxファイルと同名にしてあれば、そのシェーダーが読み込まれます。

xファイルはPMXエディタで編集できますが、今回はモデルデータを使うのではなくスクリーンスペースのレイマーチングを描くことが目的なので、xファイルはなんでも構いません。

「MikuMikuEffectで学ぶHLSL入門」からダウンロードできるサンプルをコピーしてリネームするのが手っ取り早いでしょう。

レイマーチングのサンプルはアクセサリから読み込んで使います。

https://scrapbox.io/api/code/sayachang/MME/RaymarchSample.HLSL 

 

メッシュにエフェクトをアサインする

MMDウィンドウの右上にあるMMEffectメニューからエフェクトファイル割り当てを使うと、特定のメッシュにシェーダーを適用できます。

f:id:sayachang_bot:20200315213018p:plain

板ポリに割り当てれば、シェーダーお絵描きで遊ぶことができます。

f:id:sayachang_bot:20200315213045p:plain

なお、こちらのやり方ではポストエフェクトのシェーダーを利用できない点だけはご注意ください。

 

シェーダーのコンパイル

MMEでのシェーダーコンパイルについては気にしておいた方が良いでしょう。少し重いシェーダーはMMEでは格段に遅くなります。レイマーチングのようなループ回数の多いものは対策が必要です。

シェーダーファイルの拡張子はfxですが、この中身はテキストでもコンパイル済バイナリでもMMEで使うことができます。テキストの場合、エフェクトを適用した時や、pmmファイルを開いた時点でシェーダーがコンパイルされますが、ボリュームのあるシェーダーの場合、かなりの時間を待たされることになります。

シェーダーのコンパイラWindows SDKに含まれているので、そのコマンドをbatファイルに書いておき、コマンドプロンプトから実行できるようにしておくと良いでしょう。

"C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64\fxc.exe" D:\MMEShader\shdersource.fx /T fx_2_0 /Fo D:\MMEShader\shaderbin.fx

シェーダーファイルが更新されるとMMEは自動的に読み込み直します。

なお、コンパイル時にオプションのfx_2_0がDepricatedだと警告が出ますが、華麗にスルーします。

 

VSCode環境

f:id:sayachang_bot:20200316101945p:plain

シェーダーを描いている時は、コードを書き換えて即ルックを確認したくなります。

テキストエディタで保存してコマンドプロンプトでカーソルキー↑を押してエンターキーを叩いてもいいですが、やってるとやや面倒になります。

VSCodeを使うとこのあたりの手間が少し軽減されるハズです。さらにfxファイルは開くだけでHLSLにシンタックスハイライトがついていいかんじです。

f:id:sayachang_bot:20200316102417p:plain

バッチファイルを用意しておけば右下のコンソールですぐコンパイルできるので、これで作業が格段に楽になります。

 

MMEで書くHLSLについて

手っ取り早くポスプロのピクセルシェーダーを描くために、HLSLのサンプルを用意してあります。(DirectXでいうシェーダーステージのピクセルシェーダーは、OpenGLでいうところのフラグメントシェーダーと同じものです。)

https://scrapbox.io/api/code/sayachang/MME/RaymarchSample.HLSL

 

ピクセルシェーダー関数はPSという名前なので、ここを書き換えれば好きなシェーダーを描けます。

それ以外の箇所はおまじないだと説明を省略してしまいたいですが、ちょっとだけ触れておきます。

f:id:sayachang_bot:20200316095532p:plain

冒頭でポスプロと指定します。

 

float time : TIME;
float2 ViewportSize : VIEWPORTPIXELSIZE;
static float2 ViewportOffset = (float2(0.5,0.5)/ViewportSize);

シェーダーでお絵描きする際に必要な時間と座標です。

座標についてはピクセルシェーダーで以下のように加工して扱っています。

float2 p=2*IN.TexCoord + ViewportOffset-1;
p.y*=-1;
p*=ViewportSize/min(ViewportSize.x,ViewportSize.y);

時間を扱うセマンティクスは他にも、以下のように書いて使えるものがあります。

float ftime : TIME <bool SyncInEditMode=true;>;
float elapsed_time : ELAPSEDTIME; 

 

f:id:sayachang_bot:20200316100258p:plain

パスの処理で使うカラーバッファとデプスバッファの定義です。

f:id:sayachang_bot:20200316100515p:plain

パスは末尾にあるtechniqueで記載します。

ここのScriptに書き加えてあげるとマルチパスを実装できます。

マルチパスの描き方はbowlrollの「MMEサンプルエフェクト(ver6)」でガウシアンブラーの実装を読むとわかりやすいことでしょう。

https://bowlroll.net/file/14262

f:id:sayachang_bot:20200316101012p:plain

また、パス定義でコンパイルのオプションがvs_2_0だったりps_3_0と出てきていますが、今どきならだいたい3_0にしておくのが良いでしょう。2_0だと使用できるif文の上限数が少なくてコードを書くのが面倒になったりします。

 

ループと条件分岐

MMEではループはデフォルトでunroll(n)され、if文はflattenがはたらき分岐の両方が評価されます。軽くレイマーチを描いたつもりでも、MMEにとっては軽い処理ではないのです。
これを抑制するのにループでは[loop]が、条件分岐には[branch]が使えます。

f:id:sayachang_bot:20200316104357p:plain

 

グローバル変数の扱い

レイマーチングを描いていると稀によくあることですが、複数の関数からアクセスする変数をグローバルに置きたくなることがあります。

が、これはMME環境で動かすシェーダーではコンパイルが通りません。グローバルに置いた変数は、定数であるとみなされ、コンパイル時にエラーではじかれます。

面倒になる場合がありますが、丁寧に関数に引数を渡すように書きましょう。

 

これでシェーダーを描くのに必要なものが揃いました。あとは好きなレイマーチングを描くだけです!

 

いかがでしたでしょうか。

MMDを使ってレイマーチングが描けることが明らかになったと思います。Ray-MMDに触っている時の息抜きにレイマーチングしてみるのも楽しいかもしれません。

それでは、みなさまの良いレイマーチングライフを。

ではでは。