【Ray-MMD1.5.2】アルファマップ画像を使って透過する部分を指定して、動画中でモデルのモーフから透過度を操作する方法
前置き
先日「Ray-MMD1.5.2でアルファマップにもAPPLY_SCALE機能を追加して更にモデルのモーフで動的に変化させる方法」という記事を書いたのだが、どうにも書き方が悪く、本人にしか理解できない悪文になってしまっていた。やりたいこと
Ray-MMDとMaterialなるもの
ALPHA MAP
マテリアル設定ファイルの編集
#define ALPHA_MAP_FROM 3
#define ALPHA_MAP_UV_FLIP 0
#define ALPHA_MAP_SWIZZLE 3
#define ALPHA_MAP_FILE "alpha.png"
const float alpha = 1.0;
const float alphaMapLoopNum = 1.0;
という部分が見つかるはず。これが適用された材質の透明度を指定する部分だ。
#define ALPHA_MAP_FROM 3 は材質のテクスチャ画像のアルファ値をそのまま使用する設定だ。
これを#define ALPHA_MAP_FROM 1 に書き換えると、#define ALPHA_MAP_FILE "alpha.png" の部分で指定した画像ファイルからアルファ値を取ってくるようになる。
"alpha.png" を作成した画像ファイルのパスに書き換えよう。ray-mmd-1.5.2/Materials/_MaterialMap/hair_alpha.png を今回用意した画像とすると、"../_MaterialMap/hair_alpha.png" と書き換えることになる。この意味がわからないなら、「相対パス」で検索すると良いだろう。
#define ALPHA_MAP_FROM 1
#define ALPHA_MAP_UV_FLIP 0
#define ALPHA_MAP_SWIZZLE 3
#define ALPHA_MAP_FILE "../_MaterialMap/hair_alpha.png"
const float alpha = 1.0;
const float alphaMapLoopNum = 1.0;
このmaterial_hair_dynamic_alpha.fxを髪に適用すれば、グラデ状に髪を透過させることができる。だがこれではまだ髪のテクスチャを直接弄ったときと何も変わらない(それどころかテクスチャで直に透過したときには発生しない問題まで発生してしまうことになる)。
そこで次に const float alpha = 1.0; の値で透過度を制御できるようにしよう。
APPLY SCALE 不在問題
material_common_2.0.fxsub を書き換える
#include "../material_common_2.0.fxsub"
#ifdef ALPHA_MAP_APPLY_SCALE
alphaValue=alpha*(alphaValue-1)+1;
#endif
モデルのモーフで透過度を制御する
#define ALPHA_MAP_FROM 1
#define ALPHA_MAP_UV_FLIP 0
#define ALPHA_MAP_SWIZZLE 3
#define ALPHA_MAP_APPLY_SCALE
#define ALPHA_MAP_FILE "../_MaterialMap/hair_alpha.png"
const float alpha = 1.0;
const float alphaMapLoopNum = 1.0;
float 「変数」 : CONTROLOBJECT<string name="「コントローラPMXのファイル名」"; string item = "「値を取得したいモーフの名前」";>;
という形式になっているようだ。なお「」で囲ってある日本語部分は意味を表すので、実際に使うときは適切な表記で置き換えられねばならない。
最終的に「変数」にモーフの値が代入される。
「コントローラPMXのファイル名」は文字通りファイル名のみで、パスを指定してやる必要はないようだ。おそらくMMDに読み込んだpmx名から取ってきているからだろう。
これを#define と const float alphaの間に追加する。
そしてalphaに変数値を代入する。
#define ALPHA_MAP_FROM 1
#define ALPHA_MAP_UV_FLIP 0
#define ALPHA_MAP_SWIZZLE 3
#define ALPHA_MAP_APPLY_SCALE
#define ALPHA_MAP_FILE "../_MaterialMap/hair_alpha.png"
float mAlpha : CONTROLOBJECT<string name="モデル.pmx"; string item = "髪透過";>;
static const float alpha = mAlpha;
const float alphaMapLoopNum = 1.0;
最終的にこうなる。これでモデル.pmxの髪透過モーフの値をmAlpha変数に読み込める。
気をつけるべきは const float alpha の先頭に static が必要なことだ。無いとエラーが出る。
alpha = 2*mAlpha にしてもいいかもしれない。まあ好きに弄るといいだろう。
これでアルファマップを使って透過度を指定し、動画中にモーフを弄ることで変化させられる。
目的の挙動が実現できた。
Mainの問題
#define ALPHA_MAP_FROM 3
#define ALPHA_MAP_UV_FLIP 0
#define ALPHA_MAP_SWIZZLE 3
#define ALPHA_MAP_FILE "alpha.png"
const float alpha = 1.0;
const float alphaThreshold = 0.999;
const float alphaMapLoopNum = 1.0;
となっている。
これをmaterialと同じように
#define ALPHA_MAP_FROM 1
#define ALPHA_MAP_UV_FLIP 0
#define ALPHA_MAP_SWIZZLE 3
#define ALPHA_MAP_APPLY_SCALE
#define ALPHA_MAP_FILE "../Materials/_MaterialMap/hair_alpha.png"
float mAlpha : CONTROLOBJECT<string name="モデル.pmx"; string item = "髪透過";>;
static const float alpha = mAlpha;
const float alphaThreshold = 1.0;
const float alphaMapLoopNum = 1.0;
とし、main.fxsub でも231行目に
#ifdef ALPHA_MAP_APPLY_SCALE
alphaValue=alpha*(alphaValue-1)+1;
#endif
を追加する。
これで問題ない。
つまり今回のようなmaterialを使うときにはmainも合わせて個別に用意しなければならないわけで、やや面倒だが仕方ない。
まとめ
#define ALPHA_MAP_FROM 3
#define ALPHA_MAP_UV_FLIP 0
#define ALPHA_MAP_SWIZZLE 3
#define ALPHA_MAP_FILE "alpha.png"
const float alpha = 1.0;
const float alphaMapLoopNum = 1.0;
これが、
#define ALPHA_MAP_FROM 1
#define ALPHA_MAP_UV_FLIP 0
#define ALPHA_MAP_SWIZZLE 3
#define ALPHA_MAP_APPLY_SCALE
#define ALPHA_MAP_FILE "../_MaterialMap/hair_alpha.png"
float mAlpha : CONTROLOBJECT<string name="モデル.pmx"; string item = "髪透過";>;
static const float alpha = mAlpha;
const float alphaMapLoopNum = 1.0;
こうなった。
使うときは"../_MaterialMap/hair_alpha.png" や "モデル.pmx"、"髪透過"の部分は適宜書き換えよう。
material_common_2.0.fxsubの追加部分を付近も含めて(太字が追加部分):
#if ALPHA_MAP_SWIZZLE == 0
float alphaValue = alphaValues.r;
#elif ALPHA_MAP_SWIZZLE == 1
float alphaValue = alphaValues.g;
#elif ALPHA_MAP_SWIZZLE == 2
float alphaValue = alphaValues.b;
#else
float alphaValue = alphaValues.a;
#endif
#ifdef ALPHA_MAP_APPLY_SCALE
alphaValue=alpha*(alphaValue-1)+1;
#endif
return saturate(alphaValue);
#else
return saturate(alpha * MaterialDiffuse.a);
#endif
次はMain。
main_hair_dynamic_alpha.fx のAlpha部分のビフォーアフター:
#define ALPHA_MAP_FROM 3
#define ALPHA_MAP_UV_FLIP 0
#define ALPHA_MAP_SWIZZLE 3
#define ALPHA_MAP_FILE "alpha.png"
const float alpha = 1.0;
const float alphaThreshold = 0.999;
const float alphaMapLoopNum = 1.0;
これが
#define ALPHA_MAP_FROM 1
#define ALPHA_MAP_UV_FLIP 0
#define ALPHA_MAP_SWIZZLE 3
#define ALPHA_MAP_APPLY_SCALE
#define ALPHA_MAP_FILE "../Materials/_MaterialMap/hair_alpha.png"
float mAlpha : CONTROLOBJECT<string name="モデル.pmx"; string item = "髪透過";>;
static const float alpha = mAlpha;
const float alphaThreshold = 1.0;
const float alphaMapLoopNum = 1.0;
こうなって、main.fxsubが
#if ALPHA_MAP_SWIZZLE == 0
float alphaValue = alphaValues.r;
#elif ALPHA_MAP_SWIZZLE == 1
float alphaValue = alphaValues.g;
#elif ALPHA_MAP_SWIZZLE == 2
float alphaValue = alphaValues.b;
#else
float alphaValue = alphaValues.a;
#endif
#ifdef ALPHA_MAP_APPLY_SCALE
alphaValue=alpha*(alphaValue-1)+1;
#endif
return alphaValue;
#else
return alpha * MaterialDiffuse.a;
#endif
これで終わり。長くなってしまったがこれでわかりやすくなったはず……多分。
まだわかりにくかったらTwitterとかで言ってください。