ExcellentShadowを絶対壁に対応させる改変の記録

絶対壁が便利そうだけどそのままではExcellentShadowが使えないので改変を試みる記録。

 改変を思い立ったのはNamuzoh_Quantoさんの記事を見たせい。MMDとかMMEの話です。

図0. 絶対壁便利

 上の図0の袖(向かって右側)に絶対壁を効かせてるんだけどこういう状況で非常に便利、絶対壁。このミクさんの場合、袖にボーンが入ってないのでモーションで調整できないからモデル改造の必要が出てくるけどエフェクトで対応できると楽ちんですよね。ただ、このエフェクトはMMEのMainタブで割り当てるから他のエフェクトと共存できない場合があるのでエフェクト改変を決意したわけです。
 Namuzoh_Quantoさんの記事では「絶対壁エフェクトver1.1」と「Croquis改v2」の組み合わせだけど、ここでは「絶対壁エフェクトver2.1」と「ExecellentShadow ver2.4」の組み合わせを試みます。
 大まかな方針は参考記事と同様で絶対壁エフェクトの一部をExcellentShadowに組込みます。絶対壁エフェクトver1.1とver2.1は微妙に違うし、Croquis改v2とExcellentShadow ver2.4は全然別物なので不安しかありません。
 なお、私はプログラミングに関して素人でほとんど知識がありません。なので試行錯誤を繰り返すことになり最終的に完成するかは現時点ではわかりません。(改変しながらこの記事を書いてます→完成後におかしな所を修正してます)

作業開始

 参考記事に倣い AbsoluteWall_ver2.fx から①②③を抽出します。①②③ってなんのこっちゃ!ですが一応書いておくと①②③は参考記事の説明で使われていた番号で、①②はモデルの頂点を絶対壁変形させる関数?とかを定義?してる部分で③はそれらを頂点シェーダに渡す部分みたいです・・・よく分かっていませんが①②は一番最初に出てくる頂点シェーダの直前に1回、③はワールドビュー変換の直前に毎回それぞれ貼り付ければいいみたいです、多分。詳しくは参考記事をご確認ください。
 ①②は長いので割愛しますが AbsoluteWall_ver2.fx の13行目から46行目を①、124行目から243行目までを②としました。③は252行目とその次行の

ABSOLUTE_RET ret = (ABSOLUTE_RET)0;
ret = AbsoluteWall(Pos,Normal);

にしてみました。かなり不安です。
 次にExcellentShadowです。”頂点シェーダ”と”World”をキーワードにエフェクトファイルを調べ以下のファイルを改変することにしました。

  • ExcellentShadowObject.fxsub

  • ExcellentShadowZBufDraw.fxsub

  • ExcellentShadowZBufDrawFar.fxsub

  • full_ES_pmx.fx

 この4つのExcellentShadowのファイルに絶対壁の当該部分を組み込みます。元のファイルを直に書き換えるのは後で面倒になりそうなので上記4ファイルをコピーしてそれぞれ、”ExcellentShadowObject_AW2.fxsub” のようにリネームしておきます。”AW2” は Absolute Wall ver2 のこと。
 また同時に改変の効果を確認したいので AbsoluteWall.pmx とbump_tex.png を ExcellentShadow のフォルダにコピーしておき、MMDにモデル(ここではミクさん)と AbsoluteWall.pmx と ExcellentShadow.x を読み込んでミクさんには先程リネームした full_ES_pmx_AW2.fx 等4ファイルを割り当てておきます。

図1. 改変前の状態、ExcellentShadowが効いているだけ

 では、なんとなくなじみのある full_ES_pmx_AW2.fx から改変していきます。full_ES_pmx_AW2.fx 内の”頂点シェーダ”に着目してはじめから見ていくと129行目(行番号は全て改変前のもの)に最初の頂点シェーダがあるので AbsoluteWall_ver2.fx の①②を128行目に挿入します。①②の挿入はこれで完了。
 次に③の挿入場所は ”WorldViewProjMatrix” を目印に探します。これは何カ所かあって、133,162,199,391行目にありました。ここでちょっと怪しいのは ”WorldViewProjMatrix” に似たやつで ”LightWorldViewProjMatrix” というのが331,398行目にありますがここでは無視することにします。
 それぞれの行の手前に③を挿入します。例えば下のような感じで挿入箇所がわかりやすいように③の前後に空の3行も入れてます。

// 頂点シェーダ
float4 ColorRender_VS(float4 Pos : POSITION) : POSITION
{



    ABSOLUTE_RET ret = (ABSOLUTE_RET)0;   // 追加
    ret = AbsoluteWall(Pos,Normal);       // 追加



    // カメラ視点のワールドビュー射影変換
    return mul( Pos, WorldViewProjMatrix );
}

ここまでやったら”full_ES_pmx_AW2.fx”を上書き保存してMMDで確認します。当然の如くエラーが。

図2. ですよねー

 エラーの意味は分かりませんが改変したところに問題があるのでしょう。モデルにもエフェクトがかかっていません。
 ここで参考記事にあった注意点を確認すると次のようなことが書かれています。

頂点シェーダの引数に必ずPOSITIONとNORMALを入れなければならない
変数"Pos"は"pos"など別の名前になっていることもある
頂点シェーダは一つとは限らない

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

 思い当たることばかりなので先に挙げた一例を下のように書き換えてみました。

// 頂点シェーダ
float4 ColorRender_VS(float4 Pos : POSITION, float3 Normal : NORMAL) : POSITION 
{                                          // ↑ 追加



	ABSOLUTE_RET ret = (ABSOLUTE_RET)0;   // 追加
	ret = AbsoluteWall(Pos,Normal);       // 追加



    // カメラ視点のワールドビュー射影変換
    return mul( Pos, WorldViewProjMatrix );
}

頂点シェーダの引数に”float3 Normal : NORMAL”を追加しました。(引数が複数ある時はカンマで区切るようです)
 他の頂点シェーダの部分にも同様に追加しました。元々入ってるところもありましたが。で、その結果エラーは無くなりましたがMMDの表示は初めのExcellentShadowがかかっているだけの状態です。
 参考記事の2番目の注意点が反映されてない気がしたので次のように修正しました。

// 頂点シェーダ
float4 ColorRender_VS(float4 Pos : POSITION, float3 Normal : NORMAL) : POSITION 
{                                          // ↑ 追加



	ABSOLUTE_RET ret = (ABSOLUTE_RET)0;   // 追加
	ret = AbsoluteWall(Pos,Normal);       // 追加
	Pos = ret.Pos4;                       // 追加



    // カメラ視点のワールドビュー射影変換
    return mul( Pos, WorldViewProjMatrix );
}

”Pos = ret.Pos4;”を追加したのですがその理由は絶対壁エフェクトAbsoluteWall_ver2.fxの頂点シェーダの記述が

// 頂点シェーダ
float4 ColorRender_VS(float4 Pos : POSITION, float3 Normal : NORMAL) : POSITION 
{
	ABSOLUTE_RET ret = (ABSOLUTE_RET)0;
	ret = AbsoluteWall(Pos,Normal);
    // カメラ視点のワールドビュー射影変換
    return mul( ret.Pos4, WorldViewProjMatrix );
}

のようになっていてカメラ視点のワールドビュー射影変換に ret.Pos4 とあるのでそれを Pos に代入してみました。その結果新たなエラーが復活しました。(エラーが出てくれないと逆に不安になったりしますが)

図3. 新たなエラー

 エラーの意味は分かりませんが500行目に問題があるような感じです。その周辺を抜き出すと

technique MainTec7 < string MMDPass = "object"; bool UseTexture = true; bool UseSphereMap = true; bool UseToon = true; > {
    pass DrawObject {
        VertexShader = compile vs_2_0 Basic_VS(true, true, true);
        PixelShader  = compile ps_2_0 Basic_PS(true, true, true);
    }
}

今の私の環境では
VertexShader = compile vs_2_0 Basic_VS(true, true, true);
の部分が500行目になってます。何かの呪文のようで何がどうおかしいのかわかりませんが "AbsoluteWall_ver2.fx" の中にも "technique MainTec7" があってそこには、

technique MainTec7 < string MMDPass = "object"; bool UseTexture = true; bool UseSphereMap = true; bool UseToon = true; > {
    pass DrawObject {
        VertexShader = compile vs_3_0 Basic_VS(true, true, true);
        PixelShader  = compile ps_3_0 Basic_PS(true, true, true);
    }
}

とあります。違いは vs_2_0 と vs_3_0 , ps_2_0 と ps_3_0 です。"vs_2_0" を検索してみたらどうやら頂点シェーダのバージョンのようです。

 バージョンが違うから何なの?って感じですが図3のエラーが消えるまで "vs_2_0" を "vs_3_0" に書き換えていきます。すると新たなエラーメッセージが大量に!

図4. 大量のメッセージ

どれも同じようなことを言っていて、例えば

Error: vs_3_0 or ps_3_0 may not be used with any other shader versions. (pass: DrawEdge, technique: EdgeTec)

Google翻訳
エラー:vs_3_0またはps_3_0は、他のバージョンのシェーダーでは使用できません。 (パス:DrawEdge、テクニック:EdgeTec)

"Error: vs_3_0 or ps_3_0 may not be used with any other shader versions."っていうのは共通で違うのは
pass: DrawEdge, technique: EdgeTec
pass: DrawShadow, technique: ShadowTec
pass: DrawObject, technique: MainTec0
pass: DrawObject, technique: MainTec1
pass: DrawObject, technique: MainTec2
pass: DrawObject, technique: MainTec3
pass: DrawObject, technique: MainTec4
pass: DrawObject, technique: MainTec5
pass: DrawObject, technique: MainTec6
pass: DrawObject, technique: MainTec7
の部分。(10個もあった)
 ちなみにMMDの表示は絶対壁の効果が出ています。(完全ではないかもしれないけど)

図5. 絶対壁が!(絶対度弱めるモーフ=0.5、Y軸方向に50%程張り付いてる)

 もしかしてこれで完成?と思ったけど "絶対度弱めるモーフ" を動かすと影は絶対壁変形前のものが描画されているのが分かります。
 どうしたらいいのかわからず "ps_2_0" も "ps_3_0" に書き換えてみることに。そしたらエラーは出なくなったけどMMDの表示は図5のままでした。
 エラーが出てくれないと次の手が浮かばない・・・
 まだ、"full_ES_pmx_AW2.fx" しか改変してないので他のファイルも上記と同様の改変をした結果が下の図6。

図6. 影は落ちてるけど正常ではない様子

 ずっと上のほうで改変対象のファイルは下記の4ファイルとしてました。

  • ExcellentShadowObject.fxsub

  • ExcellentShadowZBufDraw.fxsub

  • ExcellentShadowZBufDrawFar.fxsub

  • full_ES_pmx.fx

しかし、”WorldViewProjMatrix” の記述がある頂点シェーダを対象にして ”LightWorldViewProjMatrix” がらみの部分は無視する方針だったので、実際に改変したのは

  • ExcellentShadowObject.fxsub

  • full_ES_pmx.fx

の2ファイルのみです。ここで今まで無視していた "LightWorldViewProjMatrix" を "AbsoluteWall_ver2.fx" 内で検索してみると、

// 頂点シェーダ
VS_ZValuePlot_OUTPUT ZValuePlot_VS( float4 Pos : POSITION, float3 Normal : NORMAL )
{
    VS_ZValuePlot_OUTPUT Out = (VS_ZValuePlot_OUTPUT)0;

	ABSOLUTE_RET ret;
	ret = AbsoluteWall(Pos,Normal);	

    // ライトの目線によるワールドビュー射影変換をする
    Out.Pos = mul( ret.Pos4, LightWorldViewProjMatrix );

    // テクスチャ座標を頂点に合わせる
    Out.ShadowMapTex = Out.Pos;

    return Out;
}

上記頂点シェーダで "ライトの目線によるワールドビュー射影変換をする" ところがあって、その直前にAbsoluteWall関数を実行しているので多分改変でも必要な部分な気がします。ということで "LightWorldViewProjMatrix" のところにも改変を加えた結果が下図7。

図7. だいぶいい感じ!

 しかし、まだカメラを動かすと不自然に影が切り替わったりします。
 更にしつこく "WorldViewProjMatrix" を探っていくと "InternalLightWorldViewProjMatrix" というのも出てきます。ここも改変しちゃいましょう。で、やってみたけど状態は図7と変わらずです。さらに気が付いたのは絶対壁のコントローラーモデルのモーフが機能しないものがある・・・色変えるやつとか。それらは今のところ使う予定はないのでいいんだけど(バンプマップが使いたい)、この辺で手詰まりな感じです。
 ExcellentShadowには付属のSSOA(ExShadowSSAO)があるのでそっちの改変に移ることにします。
 ちょっと長くなったので記事を改めます。


この記事が気に入ったらサポートをしてみませんか?