夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

MixedRealityGraphicsToolsのNPR機能の陰に画像を使用できるようにする その② 

本日は昨日に引き続きMRGTStandardShaderのトーン表現を拡張していきます。

redhologerbera.hatenablog.com

〇shader_featureの定義

URPではマテリアルから使用する機能だけチェックボックスを有効化して有効にするウーバーシェーダーシステムを使用するためにパラメータごとにshader_feature_localを使用しています。

/// <summary>
/// Features.
/// </summary>

・・・
#pragma shader_feature_local _ _DIRECTIONAL_LIGHT _DISTANT_LIGHT
#pragma shader_feature_local _NON_PHOTOREALISTIC
#pragma shader_feature_local _SHADOW_MAP//追加
・・・

 これで#if defined(_SHADOW_MAP)で条件コンパイルを行うことができるようになりました。

〇テクスチャの定義

 次にGraphicsToolsStandardInput.hlslに影ように使用するテクスチャを定義します。

 GraphicsToolsStandardInput.hlslではシェーダー内で使用される構造体および変数の定義を行っています。

多くの変数はURP用とビルドインシェーダー用の2つのパターンの定義を行う必要があります。

#if defined(_URP)
・・・
#if defined(_EMISSION)
TEXTURE2D(_EmissiveMap);
SAMPLER(sampler_EmissiveMap);
#endif
#if defined(_SHAODWMAP)
TEXTURE2D(_NPRShadowMap);
SAMPLER(sampler_NPRShadowMap);//追加
・・・
#else //ビルドインシェーダー用の記述
sampler2D _MainTex;
・・・
#if defined(_SHAODWMAP)
sampler2D _NPRShadowMap;
#endif
#endif

またテクスチャのサンプリングを行うためにはUVを使用する必要がありますが、これもテクスチャを使用する場合のみ定義されるようになっています。

そのため_SHADOW_MAPを使用している場合にもUVを使用するように定義します。

#if !defined(_DISABLE_ALBEDO_MAP) || defined(_TRIPLANAR_MAPPING) || defined(_CHANNEL_MAP) || defined(_NORMAL_MAP) || defined(_DISTANCE_TO_EDGE) || defined(_GRADIENT) || defined(_EMISSION)||defined(_SHADOW_MAP)
#define _UV
#else
#undef _UV
#endif

〇テクスチャのサンプリング

サンプリングは次のように定義します。

#if defined(_SHADOW_MAP)
#if defined(_URP)
    half3 shadowCol = SAMPLE_TEXTURE2D(_NPRShadowMap, sampler_NPRShadowMap, input.uv).xyz;
#else
    half3 shadowCol = tex2D(_NPRShadowMap,input.uv);
#endif
#endif

〇影に反映

 MRGTシェーダーでのライティングの処理はGTLightingNonPhotorealisticで行われています。

 これはGraphicsToolsLighting.hlslで定義されています。

#if defined(_NON_PHOTOREALISTIC)
    output.rgb += GTLightingNonPhotorealistic(brdfData, light.color, light.direction, worldNormal, worldViewDir);
#else
    output.rgb += GTLightingPhysicallyBased(brdfData, light.color, light.direction, worldNormal, worldViewDir);
#endif

 このため_SHADOW_MAPを使用している場合とそうではない場合で処理を分けます。

#if defined(_NON_PHOTOREALISTIC)
#if defined(_SHADOW_MAP)
    output.rgb += GTLightingNonPhotorealistic(brdfData, light.color, light.direction, worldNormal, worldViewDir,shadowCol);
#else
    output.rgb += GTLightingNonPhotorealistic(brdfData, light.color, light.direction, worldNormal, worldViewDir);
#endif
#else
    output.rgb += GTLightingPhysicallyBased(brdfData, light.color, light.direction, worldNormal, worldViewDir);
#endif

_SHADOW_MAPを使用している場合はGTLightingNonPhotorealisticの引数として新たにサンプリング結果であるshadowColを渡すようにしています。

 同時にGTLightingNonPhotorealisticも_SHADOW_MAPによって処理を分岐させます。

#if defined(_SHADOW_MAP)
half3 GTLightingNonPhotorealistic(GTBRDFData brdfData,
half3 lightColor, half3 lightDirectionWS,
half3 normalWS, half3 viewDirectionWS, half3 shadowCol)
{
#else
half3 GTLightingNonPhotorealistic(GTBRDFData brdfData,
half3 lightColor, half3 lightDirectionWS,
half3 normalWS, half3 viewDirectionWS)
{
#endif
   half NdotL = ceil(saturate(dot(normalWS, lightDirectionWS)));
#if defined(_SHADOW_MAP)
    NdotL += saturate(1-NdotL)*shadowCol;
#endif
   half3 radiance = lightColor * NdotL;

   half3 brdf = brdfData.diffuse;

   return brdf * radiance;
}

  今回は以下の処理を使用しています。

 NdotL += saturate(1-NdotL)*shadowCol;

これはNdotLがもともとライトが当たっている部分を出力しているため、逆数を取り影が1、ライトが当たっている部分が0になるように設定し、影の部分だけにShadowColを掛け合わせて画像を使用するようにしています。

最終的にもともとのNdotLに足し合わせることで画像の暗い部分のみが影として残るという仕組みで実装を行いました。

画像を差し替えることで様々な表現ができそうです。

本日は以上です。