見出し画像

Q&A『AlternativFull改変シェーダーにLocal Shadowを適用したい』

画像11

こちら回答が遅くなった上に、完全には解決できず申し訳ありません。
AlternativeFullには、サポートツールが同梱されており、そこでLS対応できたような気がしていたんですが、なかったですね。
あれはHAToonの方だな...

私は、AlternativFullに対する苦手意識が強くて避けて通ってきたタイプのMMDerなんですが、今回かなり真摯に向き合いました。
その結果、完全には対応しきれなかったものの、なんとなくそれっぽく対応できているように見える、気がしなくもないものが出来上がったので、ひとまずそちらを公開いたします。

どの程度対応できているかは、一連のモーメントをご確認ください。
なお、私はC言語は書けない人間なので、別の言語をかじった人間がどうにかこうにかエラーしないものを書き足した、程度の期待値でお願いします。
https://twitter.com/i/events/1437034933034237957

また、不完全対応が心苦しいので、代替案についてもご提案させていただきます。
ということで、まずは改変からどうぞ。


AlternativeFullのLocalShadow対応

必要ファイル準備

1) シェーダーフォルダに「LocalShadow_Header.fxh」をコピー

画像3

2) 「AlternativeFull.fxsub」とシェーダー([シェーダー名.fx]あたり)をコピーし、それぞれ末尾に「_LS」と追加して名前変更

画像4


シェーダーの改変
続いて、シェーダーにLS対応版であることを定義する記述を追加します。
コピペ推奨

[シェーダー名_LS.fx]の最終行#include "AlternativeFull.fxsub"を以下の2行に書き換え

画像5

#define USE_LOCAL_SHADOW_SYSTEM
#include "AlternativeFull_LS.fxsub"


AlternativeFull_LS.fxsubの改変
通常は、シェーダ名.fxがエフェクト本体なんですが、AlternativeFullではこちらが本体になります。
ちょっと特殊なためLocalShadowのリドミ記載の方法ではエラーになるため、少々改変しております。

左が改変後の記述、右が改変前の記述になります。
また、画像内に行数の表示がありますが、作業前に私が字下げなどのコード整形を行ったため、オリジナルとは行数が異なるので、そこはあまりにあてにしないでください。

1) パラメータ宣言の追加
一番最初に以下のコードを追加

画像6

// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ LocalShadow対応 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ //
// LocalShadow用シャドウマップパラメータの取り込み
#include "LocalShadow_Header.fxh"
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //

2) LocalShadow用座標の追加
「オブジェクト描画(セルフシャドウON)」と検索し(必ずONまで含める)、「ZCalcTex」の1行下に以下のコードを追加

画像7

// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ LocalShadow対応 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ //
float4 ZCalcTex2	: TEXCOORD5;	// LocalShadow用Z値
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //

3) LocalShadow用ダミー照明の設定
射影のための照明に関する記述がまとまっている箇所の最後(// ライト視点によるワールドビュー射影変換の2行下)に、以下のコードを追加

画像8

// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ LocalShadow対応 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ //
// LocalShadow用ライト視点によるワールドビュー射影変換
Out.ZCalcTex2 = mul( Pos, LocalShadow_LightWorldViewProjMatrix );
// ライト方向修正
LightDirection = LocalShadow_GetLightDirection(LightDirection);
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //

4) LocalShadowの描写設定
_ShaderMain関数内画像の箇所にコードを追加

#ifdef USE_EXTRA_EXCELLENT_SHADOW_SYSTEM ~ #endifの下

画像9

// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ LocalShadow対応 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ //
// ライト方向修正
LightDirection = LocalShadow_GetLightDirection(LightDirection);
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //

シェーディング計算
「// テクスチャ座標に変換」の上

画像10

// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ LocalShadow対応 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ //
float LightNormal = dot(normalize(IN.Normal), -LightDirection);
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //

セルフシャドウ処理
#ifdef USE_EXCELLENT_SHADOW_SYSTEM ~ #elseの内の、#elseの直前

画像11

// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ LocalShadow対応 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ //
#elif defined(USE_LOCAL_SHADOW_SYSTEM)
	// テクスチャ座標に変換
	IN.ZCalcTex2 /= IN.ZCalcTex2.w;
	TransTexCoord.x = (1.0f + IN.ZCalcTex2.x)*0.5f;
	TransTexCoord.y = (1.0f - IN.ZCalcTex2.y)*0.5f;
	// Localシャドウマップによる遮蔽判定
	float comp;
	if( !any( saturate(TransTexCoord) - TransTexCoord ) ) {
	    comp = LocalShadow_GetSelfShadowRate(TransTexCoord, IN.ZCalcTex2.z);
	}
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //

セルフシャドウの適用
#ifdef USE_MATERIAL_TEXTURE ~ #endif内の#endifの直前

画像12

// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ LocalShadow対応 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ //
#elif defined(USE_LOCAL_SHADOW_SYSTEM)
	if ( useToon ) {
		comp = min(saturate(LightNormal*Toon), comp);
		ShadowColor.rgb *= MaterialToon;
	}
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //

明暗のブレンド
return Color;を以下に書き換え

画像13

// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ LocalShadow対応 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ //
#ifdef USE_LOCAL_SHADOW_SYSTEM
	// 影色に濃度を加味する
	LocalShadow_COLOR Out = LocalShadow_GetShadowDensity(Color, ShadowColor
useToon, LightNormal);
	// スペキュラ適用
	Out.Color.rgb += Specular;
	// 影の合成
	float4 ans = lerp(Out.ShadowColor, Out.Color, comp);
	if( transp ) ans.a = 0.5f;
	return ans;
#else
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //
	return Color;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ LocalShadow対応 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ //
#endif
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //

以上で、編集作業は終了です。
あとは、通常のLS対応シェーダーと同じようにお使いください。

今回のシェーダーではこんな感じになります。
顔以外は、LS対応前のシェーダーです。

画像14



代案:影傾向マップ

今回、代案としてご提案するのが、影傾向マップの利用です。
言葉にすると難しい感じがしますが、簡単に言えばテクスチャで予め影が出る場所を指定しようというものです。

AlternativeFullの他、PAToonやmsToonCoordinatorでも採用されています。

影傾向マップの作成
影傾向マップは、モデルの顔のUVを下敷きにして真っ白のキャンバスに黒で影を描きます。
モデルのUVの取得は、PMXEditorのUV展開図出力プラグインで取得が可能です。
https://bowlroll.net/file/13187

ここで1つ難点なんですが、モデルの顔材質が鏡面化されている場合、一度顔材質を分離して、片方のUVを反転してから再度、顔材質を結合して、顔全面のUVにする必要があります。
そこらへんは、以前に似たようなことを解説しているので、そちらをご参考ください。

そんなこんなで、今回ご用意した影傾向マップがこちらです。

画像15

この黒い部分ほぼそのまま出るので、少しだけ境界をぼかしておくと、影がジャギらないです。

影傾向マップはシェーディングヒントテクスチャと同じ場所に保存しておいてください。
私はモデルやエフェクトとテクスチャがごちゃごちゃになるのが嫌なので、基本的に1つフォルダを用意してその中に格納しています。
今回もシェーダーフォルダの中にシェーディングヒントテクスチャ用のフォルダを用紙してあるので、影傾向マップもそこに入れておきます。

画像15


シェーダーエフェクトの改変
つづいて、シェーダー側で影傾向マップを使用することを定義します。

1) シェーダー([シェーダー名].fxあたり)をコピーし、末尾に「_SM_face」と追加して名前変更

画像16

2) [シェーダー名]_SM_face.fxに以下の1行を追記します。

画像17

#define TEXTURE_SHADOW_BIAS "[フォルダ名]\\[画像ファイル名(拡張子含む)]"

シェーダーと影傾向マップ画像が同じ階層にある場合、「[フォルダ名]//」部分は不要です。
あとは、通常のシェーダーと同じようにお使いください。

今回の影傾向マップとシェーダーではこんな感じになります。
顔以外は、改変前のシェーダーです。

画像18



今回、途中で手持ちのAlternativeFullのバージョンが古いことに気づいたんですが、1.02移行では2Dドロップシャドウなるエフェクトが追加されていましたね。

こちらは指定した材質を影として落とせるようで、これでもいけるかなーと試してみたんですが、髪影を落とすことはできますが、LocalShadowのように専用の射影ライトを用意しているわけではないので、普通に顔に影がバンバンおちるのと、ドロップシャドウとして落とした髪影もマップが微妙だったので、LocalShadowの代替品としてはちょっと違うなということで、ご紹介は省略します。

ご興味のある方はlessさんのAlternativeFullの解説ページに記載があるので、そちらをご参照ください。
https://ch.nicovideo.jp/LessThanEqual/blomaga/ar1023498



Credit

Model:ろく様
Effect:less様 / 針金P様

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