どっとライブ推しMMD初心者の備忘録

未来のやりおるマン達に捧げる、主にトゥーン調MMDに関するお話

ポストエフェクトを絶対壁エフェクト対応に改造する方法

  この記事では、MME(MikuMikuEffect)のエフェクトについて、絶対壁エフェクトをCroquis改v2等のポストエフェクトへ組み込むための手順を具体例として取り上げながら、一般に「モデルの頂点座標を変形させる」エフェクトを「モデルの頂点情報を処理の過程で利用する」エフェクトに組み込む際の基本的な考え方をまとめていきます。トゥーンシェーダに頂点変形系のエフェクトを組み込んだり、頂点変形系のエフェクト同士を合体させたりすることもできるはずです。

 HLSLを触ったことのない方向けにかなり詳細に書いているため、ある程度分かっている人にとっては何も得るところが無いと思われます。すでに基礎を理解されている方や、御託は良いから改造方法だけ教えろという方は、目次から直接「改造の方法」の項にジャンプして下さい。

 何か間違った記述をしてしまっている場合、ご教示頂けると大変助かります。

目次

 

 

改造の汎用性

 本記事ではDoltMePly 様の「絶対壁エフェクト」の バージョン1.1についての改造のみ取り上げておりますが、頂点を変形させるタイプのエフェクトであれば、同様の手順で組み込みできると思われます(多分)。

 具体例としては、P.I.P 様がPAToon2.96+βにおいて、「絶対壁」、「嘘パース」、「嘘視野角」のエフェクトを同様の手順でHAToonに組み込みされております。また、たじゃっぴ 様はこの手順でCroquis改v2に「嘘パース」を組み込みされております。(私はたじゃっぴ 様の改造を真似て今回の改造を行いました。)興味がある方はHAToonCore.hlslとPAToonCore.hlslを比較したり、通常版とたじゃっぴ 様版のCroquis改v2を比較したりしてみて下さい。

P.I.P様は以下の記事にて嘘パースや嘘視野角の組み込みの方法について書かれています。(やっていることはほとんど同じなので、この記事書く必要なかったかもしれない…)

記事

pip-mmd.hatenablog.com

pip-mmd.hatenablog.com

  私は以下の動画でAutoLuminous4、Croquis改v2、ExShadowSSAO、ExcellentShadow、XDOFに「絶対壁」の組み込みを行いました。何か細かい処理が間違っているかもしれませんが、少なくとも各エフェクトが絶対壁の位置に掛かるようにはなりました。

また、PostAlphaEyeとPostRimLightToonについては失敗しました(後述)。私がカメラとモデルと壁の間の位置関係を間違えていただけで、実際にはPostAlphaEyeとPostRimLightToonについても本記事の改造で実用可能でした。

www.nicovideo.jp

 この動画は、「死ぬ前に推しがディスプレイから飛び出してお迎えに来てくれたらいいな」というエヴァ旧劇の頃からあるようなオタクの普遍的妄想を映像化した(つもりの)もので、ペーパーマリオとかスマブラ版のMr.ゲーム&ウォッチとかのような「平面上から3次元の世界に出てきたキャラクター感」を出すために絶対壁エフェクトを導入しました。

絶対壁エフェクトの概要 

 このページに辿り着いた方にわざわざ説明する必要もないと思いますが、絶対壁エフェクトとは、モデルを平面上に貼り付けるエフェクトです。色々な使い方が出来る、非常にポテンシャルの高いエフェクトだと思います。今回の記事で使用するのは、純粋に絶対壁の機能しかないバージョン1.1のほうです。

 エフェクトの配布場所や使い方等は作者様の配布動画をご覧下さい。

配布動画

www.nicovideo.jp

www.nicovideo.jp

エフェクト改造の必要性

 次の項でもう少し詳しく述べますが、一般的にMMEのエフェクトは、大別して、画面上の座標を取得し変換(移動とか回転とか)する操作と、取得した座標上の色を変換する操作の二つを行っています。

 バージョン1.1の絶対壁エフェクトは、大ざっぱに言うと、「指定されたpmxモデルの3次元的な頂点座標を取得し、その取得された座標を絶対壁のpmxモデルの平面上に移動させる変換を行ったあと、平面上でモデルの本来の色を再現して、結果を画面に出力する」、という処理を行っています。

 「pmxモデルを指定」と書きましたが、MMEのエフェクトには、個々のモデルの頂点座標等の情報を必要とするものと必要としないものがあります。両者の判別法を述べておきますと、基本的に、エフェクトを導入するときにメインタブでモデルやモデルの材質にfxファイルを読み込ませるタイプのもの(下の画像の一枚目)と、エフェクト読み込み用のアクセサリやpmxモデルを読み込むとMMEの割り当てウインドウ上でタブが増えるタイプのもの(下画像の二枚目)が、モデルの情報を読み取る必要のあるエフェクトです。*1その他のエフェクトは、基本的に私たちが見ている画面と同じ二次元平面のみを入力情報として受け取っています。

 f:id:Namuzoh_Quanto:20190326194549p:plain

f:id:Namuzoh_Quanto:20190326194612p:plain

例えば、今回取り扱う絶対壁エフェクトやトゥーンシェーダーなどのエフェクトはメインタブでfxファイルを読み込むタイプですし、Croquis改v2などのエフェクトはタブが増えるタイプですが、モデルを変形させたり影や輪郭線を付けるといったそれぞれのエフェクトの役割からして、これらは明らかにモデルの情報を必要としていそうですよね。一方で、o_Diffusionやo_selfOverlayなどそれら以外のタイプのエフェクトを思い起こしてみると、モデル単体ではなく画面全体の二次元情報を読み取っていそうですよね。

 ここで、絶対壁エフェクトとともに、タブが増えるタイプのモデル情報読み取り系エフェクトを同時に使用しようとすると、ある問題が起こってしまいます。MMEにおける「頂点の移動」の操作は、実はMMD側の座標の情報を複製してエフェクトの内部のみで使用しているだけで、MMD側が持っている座標情報そのものを書き換えているわけではないのです。つまり、絶対壁エフェクトによって頂点の情報を操作しても、絶対壁エフェクト以外の他のエフェクトは、MMD側が保有している、絶対壁の変形が行われる以前の座標を取得して処理を行ってしまうのです。これでは、絶対壁以外のエフェクトは、絶対壁上のモデル本体にではなく、何もないはずの空間上に掛かってしまうのです。

少しまどろっこしく書きましたが、要は下の画像のようになってしまうということです↓(絶対壁とCroquisを併用)

f:id:Namuzoh_Quanto:20190326200234j:plain

 

 このようなことを防ぐための一つの手段として、絶対壁エフェクトと同時に用いるモデル情報読み取り系エフェクトに対して、「MMD側から取得したモデルの座標情報に、絶対壁エフェクトと全く同じ頂点変形処理を施すことによって、エフェクトが処理の対象とする座標を、絶対壁上の座標に直す」という改造を行う方法があります。この方法では絶対壁エフェクトの処理をそのまま流用するので、ほとんどコピペのみで改造することが可能です。

この改造を行うと、下の画像↓のように、ちゃんと絶対壁上のモデルに他エフェクトが掛かるようになります。

f:id:Namuzoh_Quanto:20190326200459j:plain

 ちなみに、検索流入した方向けにダイマしておくと、この画像の子は、アップランド社の「.LIVE」に所属している、今を時めくVTuberの金剛いろはちゃんです。かわいさと面白さのバランスが絶妙で、トークも上手いのでおすすめです!!

金剛いろはちゃんの公式MMDモデル(ぽんぷ長 様によるモデリングです)↓

3d.nicovideo.jp

金剛いろはちゃんのチャンネル(まずは自己紹介動画を見て、その後MMDの作業しながらでもいいのでラジオ感覚で雑談配信とか聴くと良いかもです)↓

www.youtube.com

 話を戻します。調子に乗りました。すみません。次の項で、このような方法を取る場合の改造について、具体的な方法を示します。

改造の方法

 組み込み改造の方法を示していきます。

基礎知識

 まず、改造に必要な前提知識です。一般的に、MMEにおけるエフェクト全体の構造は以下のようになっています。

  

パラメタや関数の定義、コントローラの読み込み

頂点シェーダ1

ピクセルシェーダ1

テクニック1

頂点シェーダ2

ピクセルシェーダ2

テクニック2

(繰り返し…)

 

 この構造の構成要素について、簡単に説明していきます。

 まず、シェーダの記述の前に、頂点シェーダやピクセルシェーダの内部で使われるパラメタや関数の定義が行われます。

 それらの定義の後に、頂点シェーダ、ピクセルシェーダ、テクニックの3つ一組のセットが一つ以上登場します。

頂点シェーダは、取得した座標の情報を変形したりしなかったりした後、最終的には二次元座標に変換して出力します。頂点を変形させる場合、この頂点シェーダ内において変形処理を行います。

ピクセルシェーダは、頂点シェーダが出力した二次元座標を受け取って、ピクセル単位で色情報の変換をしたりしなかったりしつつ、最終的に二次元座標の色を出力します。

テクニックは、頂点シェーダとピクセルシェーダを呼び出して、実際に処理を実行させます。

頂点シェーダ、ピクセルシェーダとテクニックについては、直前に

// 頂点シェーダ

のように、「このコードは頂点シェーダだよ」とはっきり明示されていることが多いです。このダブルスラッシュ「//」から始まる行は、エフェクトを実行する際には処理されない行で、「以下に続くソースコードはどんな処理をする為のものなのか」を私たちソースコードを読む側の人々に伝える役割を担っています。このようにダブルスラッシュが多用されているエフェクトでは、ダブルスラッシュに書かれている説明を積極的に読んでいくと、エフェクトの理解が深まり改造もしやすくなるので、どんどん活用していきましょう。

コピペ改造の方法

  それでは改造を行っていきます。「絶対壁エフェクトver1.1」と「Croquis改v2」を用意し、まずは、絶対壁エフェクトのフォルダ内の「AbsoluteWall.fx」と、Croquisのフォルダ内の「EdgeStrengthDraw.fxsub」を、メモ帳等のエディタで開いて下さい。(できればコードの行数が分かるものが望ましい)

seiga.nicovideo.jp

行数が付いてるエディタの例(メモ帳でも気合いで何とかなりますが一応)

eng-entrance.com

 まず、AbsoluteWall.fxの中の、コピーすべき三箇所を示します。

①:10行目~27行目までの部分丸ごと*2

// 平面のデータ取得

の行から

float Pparam_RangeON : CONTROLOBJECT < string name = PLANENAME; string item = "範囲 OFF⇔ON"; >;

の行までです。

この一連のブロックは、ダブルスラッシュの後に書かれている通り、絶対壁エフェクトのコントローラにより指定された、位置情報やモーフなどの各種パラメタの値を、エフェクトファイル内に取り込む働きをしています。

②:104行目~211行目までの部分丸ごと

//ベクトル内積

の行から

}

の行までです。

この一連のブロックは、絶対壁エフェクトの中核である「モデルの頂点座標を絶対壁の上まで移動させる」処理を行うAbsoluteWall関数を記述する部分です。169行目~211行目がAbsoluteWall関数の本体で、それより前の部分は、AbsoluteWall関数内で使用される関数が記述されています。

③:221行目

Pos = AbsoluteWall(Pos,Normal);

です。この文は、②のAbsoluteWall関数を頂点シェーダ内で実行する為の文です。後述しますが、この③については、単純なコピーだけでは駄目なことが多く、状況に応じて改変する必要があります。

  コピーすべき文が分かったところで、次はEdgeStrengthDraw.fxsubのどこにこれらをペーストするのか示していきます。

①と②:一番最初の頂点シェーダが出てくるちょっと前(例えば63行目あたり)

①と②については、関数を頂点シェーダ内で呼び出す必要があるので、頂点シェーダよりも前のところにペーストしておく必要があります。AbsoluteWall関数の内部で①のパラメタを使用するので、順番は必ず①→②の順になるようにして下さい。

③:ファイル内の全ての頂点シェーダ内の、ワールドビュープロジェクション変換などの変換が行われる直前(今回で言えば、78行目)

ワールドビュープロジェクション変換とは、ものすごくざっくりいうと、MMD側から読み取って頂点シェーダに入力した座標情報を、回転とか移動とかのいろいろな変換や操作などを行いやすい形に直しつつ、カメラとの位置関係を定め、さらに三次元だった座標を画面上の二次元座標に変換する、という処理をまとめて行ってくれる変換です。この処理を行う前に、座標に絶対壁エフェクトの効果を掛けてやれば、絶対壁エフェクトが適用された後の座標をエフェクトが使用してくれるようになるということです。

この変換はエフェクトによって若干形が違うこともあるかもしれませんが、

Out.Pos = mul( Pos,なんとか );

という形をした文が頂点シェーダ内にあったら多分それがそうです。「なんとか」のアルファベットに”World”とか含まれてたり、ダブルスラッシュの中にワールドとかビューとかいう単語が含まれてたら間違いなくそれでしょう。

 ③の改造には3つ注意点があります。

 まず一つ目は、「頂点シェーダの引数に必ずPOSITIONとNORMALを入れなければならない」ということです。引数とは何か、ということから説明します。EdgeStrengthDraw.fxsubの頂点シェーダは

VS_OUTPUT Basic_VS(float4 Pos : POSITION, float3 Normal : NORMAL, float2 Tex : TEXCOORD0)

という文になってます。(75行目)この文のうち、「Basic_VS」というのがこの頂点シェーダの名前です。この名前のすぐ後にある丸カッコのなかに、カンマで区切られてずらずら書かれているのが引数です。このようにして頂点シェーダに引数を渡すと、シェーダは内部で引数を使うことができるようになります。今回の場合は、「float4 Pos : POSITION」と「float3 Normal : NORMAL」と「float2 Tex : TEXCOORD0」の3つの引数が渡されています。

ところで、②でペーストしたAbsoluteWall関数は、処理の過程でPos(座標)とNormal(法線)の情報を使用するので、この頂点シェーダの引数の中に「float4 Pos : POSITION」と「float3 Normal : NORMAL」を渡してあげないと正常に動いてくれないのです。もしこれら二つのどちらかでも入っていなかったら、頂点シェーダの引数として追加しなければなりません。(カンマで区切るのを忘れずに!)

ちなみに、この「float4 Pos : POSITION」という引数こそが、MMD側から受け取った三次元座標です。

 二つ目の注意点は、「変数"Pos"は"pos"など別の名前になっていることもある」ということです。ワールドビュープロジェクション変換の引数が、もし

Out.Pos = mul( pos, WorldViewProjMatrix );

とか

Out.Pos = mul( tikuwa_dimyouzin, WorldViewProjMatrix );

とかいう形になっていたら、③の変換も、それに対応させて、それぞれ

pos = AbsoluteWall(pos,Normal);

とか

tikuwa_dimyouzin = AbsoluteWall(tikuwa_dimyouzin,Normal);

とかいった形に直してやる必要があるということです。

 三つ目の注意点は、「頂点シェーダは一つとは限らない」ということです。③の改造は、改造を行うfxsubファイルの中にある全ての頂点シェーダに対して行う必要があります。改造をしたはずなのにエフェクトの表示が改善されない場合、まずこれを見落としていないか再確認しましょう。

どのファイルを改造するのか

  以上で改造の方法は分かって頂けたと思いますが、「どのファイルを改造すればいいのか」をまだ述べていません。

 タブが増えるタイプのエフェクトでは、原則として、頂点シェーダを含むfxsubファイルは全て上記の改造をする必要があります。(たまに改造すべきファイルの拡張子がfxやhlslの場合もありますので注意。)すなわち、Croquis改v2で言えば、

ColorMapCommon.fxsub

EdgeStrengthDraw.fxsub

SubDraw.fxsub

ColorDrawCanceler.fxsub

EdgeStrengthDrawCanceler.fxsub

EdgeStrengthDrawYoreyore.fxsub

SubDrawCanceler.fxsub

の7つのfxsubファイルです。ただし、CancelerとかYoreyoreとかの予備機能を使わないよという方は最初の3つだけ改造すれば大丈夫です。

 重要な注意ですが、これらのfxsubファイルを改造した後、保存する際は、上書き保存をせずに、必ず別名保存をするようにして下さい。これは、これらの改造を施したfxsubファイルを、絶対壁を適用したモデルや材質にのみ掛けることが出来るようにするためです。上書き保存をしてしまうと、今度は逆に全てのエフェクトの効果が絶対壁上に乗ってしまいます。別名保存をする際は、絶対壁改造を施したファイルだということが分かりやすいように、「EdgeStrengthDraw_AW.fxsub」みたいな名前にすると良いと思います。AWはAbsolute Wall(絶対壁)の略です。

 なお、もう一つ落とし穴(というほどでもないかもしれない注意点)があって、例えば今回のCroquis改v2では、頂点シェーダを含まない「ColorDraw.fxsub」というfxsubファイルがあると思いますが、このファイルの7行目に

#include "ColorMapCommon.fxsub"

 という記述があります。この文は、実は「このファイルのここにColorMapCommon.fxsubを読み込みますよ」というような意味の文章です。すなわち、ColorDraw.fxsubに対して、「7行目のファイル名を先程改造したファイル名に置き換える」という改造を行ったものを用意してあげないと、先程の改造が無意味になってしまうのです。頂点シェーダが無いからとおいそれと油断はできないのです。なお、改造したColorDraw.fxsubについても、上書き保存せずColorDraw_AW.fxsubなどとして下さい。

どうやって使うの

 以上で改造は終わりです。改造したfxsubファイルの使用方法ですが、これは簡単です。メインタブで絶対壁エフェクトを適用させたモデルや材質に対して、増えたタブにおいて通常版のfxsubファイルの代わりに改造版のものを適用させてあげればいいだけです。

 例えば、金剛いろはちゃんのモデルに絶対壁エフェクトとCroquis改v2を適用させたいとします。

まずは、通常のようにモデルとCroquisをMMDに読み込みましょう。そして、絶対壁のpmxモデルを読み込み、MMEのメインタブにおいて、いろはちゃんモデルにAbsolutewall.fxを適用させましょう。そしてCroquisや絶対壁のパラメタをいい感じにしましょう。ここまではいつもの通りです。

f:id:Namuzoh_Quanto:20190327194701p:plain

 ここまで出来たら、まずMMEのCM_ObjectColorMapタブを開き、いろはちゃんに適用されているColorDraw.fxsubのファイルを、ColorDraw_AW.fxsubなどと名付けた先程の改造済みファイルに置き換えましょう。同様にして、CM_EdgeStrengthMapタブでEdgeStrengthDraw.fxsubを、CM_NormalDepthMapタブでSubDraw.fxsubをそれぞれ改造済みに置き換えて下さい。

f:id:Namuzoh_Quanto:20190327194911p:plain

 これで輪郭線が上手く描画されるようになったはずです。上手くいっていない場合はもう一度改造を見直ししてみて下さい(私の記述が間違っている場合も考えられるので、間違えてる箇所を見つけたり、もし何度直しても上手くいかなかったりしたらご指摘下さい。)

 

f:id:Namuzoh_Quanto:20190327195020p:plain

補足:シェーダへの組み込み

 メインタブで適用させるタイプの各種シェーダへの絶対壁エフェクトの組み込みも、以上と同じ方法で出来るはずです。シェーダの場合はfxsubではなくfxファイルを改造することになると思います。

 試しに私が個人的に気に入っているかっつりトゥーンシェーダーの、「服.fx」に、絶対壁エフェクトを組み込んでみました。下の画像をご覧下さい。パラメタの調整をちゃんとしていないのと全材質服にしているのが原因で、トゥーン調的にはイマイチですが、少なくとも絶対壁エフェクトはちゃんと働いてますね。(見栄えの為に改造済みCroquisも入れております。)

トゥーン調MMDはとても良いものなので、皆さんも是非一度やってみて下さい。本ブログにもやり方をまとめてあります(ダイマ

f:id:Namuzoh_Quanto:20190327201757j:plain

 

トゥーン調のやり方の記事↓

namuzoh-quanto.hatenablog.com

改造ができなかった例 

 

 私が遭遇した、以上の方法の改造では上手くいかなかったエフェクトの例も挙げておきます。

 私がミスしていただけでした。すみません。

より詳しく知りたい方の為に

 

  fxファイルの内部構造に興味を持たれた方のために、今回の改造の為に私が参考にしたサイト様などを貼らせて頂きます。(ググればすぐ出るサイト様ばかりですが。)MMEのfxファイルなどは「HLSL」というプログラミング言語で書かれているので、HLSLで検索してみると情報が出たり出なかったりします。

・「MikuMikuEffectで学ぶHLSL入門」

非常に分かりやすいので、まずこれを読んでみましょう。

codezine.jp

・MMEに付属している「REFERENCE.txt」と「MMEffect.txt」

上の記事を読んだ後にこれらのファイルを読むと、なんだかMMEのことを理解出来た気になれます。MME独自のセマンティクスなどの仕様は全てこのファイルに載っています。

・HLSLの話が非常に詳しいサイト様(わからないことが出てきたときに見に行くと役立ちます)

marupeke296.com

・ワールドビュー射影変換の説明が分かりやすかったサイト様

whaison.jugem.jp

d.hatena.ne.jp

 HLSL講座とMME付属のテキストファイルを読んだ方なら分かっていただけると思いますが、MMEにおけるHLSL言語はわりと機能の制約が多く、書き方の型のようなものがある程度決まってしまっています。そのため、逆に言えば、ソースコードを読んで内容を理解するのがそこまで難しくないのです。(もちろん、自分の手で書くとなると初心者には難しいと思います。)MMD界隈のエフェクト製作者様はダブルスラッシュによるコメントでプログラムの意味をちゃんと書き残して下さる方が多いということも、解読のしやすさに繋がっていると思います。

 

おわりに

 わかりにくい説明だし、P.I.P様の記事とほとんどやっていることが同じなので(扱う対象を絶対壁エフェクトに変えただけ)、正直需要があったのか分からないのですが、何らかのお役に立てていれば幸いです。

 MMEのエフェクトを使用したり改造したりする際は、このように便利で扱いやすく内部処理も把握しやすいエフェクトを無料で公開して下さり、また(人によっては)改造やソースの流用の許可をして下さっている、エフェクト製作者様たちへの感謝の気持ちを忘れないようにしましょう。

 

*1:ここではエフェクトを操作するためのpmxコントローラについては考えておりません

*2:ソースコードの重要な部分を丸ごと載せるのはまずいと思うので、行数とソースのほんの一部分のみを記述していきます