夜風のMixedReality

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

MixedRealityGraphicsToolのNormalMapScaleが機能しない問題の解消 その①

本日はMRGT枠です。

MRGTのGitHubイシューに次のようなバグレポートが上がっていました。

github.com

NormalMapScaleの機能は筆者が提案、実装した機能です。

今回は気になったこともあり修正していきます。

〇バグの確認

バグレポートによるとUnity 2021.3.26f1c1 およびUnity2021.3.22で発生しているとあげられています。

このバージョンはLTSではないため、いったん筆者環境であるUnity2021.3.21f1で確認を行います。

バグレポートにはURP、ビルドインの報告は上がっていなかったため両方を確認する必要があります。

これはMRGTStandardShaderはURPとクラシックなビルドインパイプランで処理が分岐しており、2つのコードが混在しています。

①MRGTシェーダーを使用したマテリアルを作成します。

②任意のノーマルマップを適応しNormalMapScaleの値を弄ります。

ここで値を0にしましたがNormalMapの強さが変わらないことがわかります。これは提示されていたものと同様のバグになります。

〇NormalMapScaleの処理

MRGTStandardShaderではフラグメントシェーダー(PixelStage関数)で序盤にテクスチャ関連の処理を行っています。

ノーマルマップに関する処理は次のような形になります。

/// <summary>
/// Fragment (pixel) shader entry point.
/// </summary>
half4 PixelStage(Varyings input, bool facing : SV_IsFrontFace) : SV_Target
{
    UNITY_SETUP_INSTANCE_ID(input);
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);


// Texturing.
・・・

#if defined(_CHANNEL_MAP)
#if defined(_URP)
   ・・・
#else
    ・・・
#endif
 ・・・・    
#endif

#if defined(_EMISSION)
#if defined(_URP)
   ・・・
#else
          ・・・
#endif
#endif
 

・・・

    // Normal calculation.
#if defined(_NORMAL)
#if defined(_URP)
    half3 worldViewDir = normalize(GetWorldSpaceViewDir(input.worldPosition.xyz));
#else
    half3 worldViewDir = normalize(UnityWorldSpaceViewDir(input.worldPosition.xyz));
 #endif
#if defined(_REFLECTIONS) || defined(_ENVIRONMENT_COLORING)
    half3 incident = -worldViewDir;
#endif
    half3 worldNormal;

#if defined(_NORMAL_MAP)
#if defined(_TRIPLANAR_MAPPING)
#if defined(_URP)
    half3 tangentNormalX = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, uvX), _NormalMapScale);
    half3 tangentNormalY = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, uvY), _NormalMapScale);
    half3 tangentNormalZ = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, uvZ), _NormalMapScale);
#else
    half3 tangentNormalX = UnpackScaleNormal(tex2D(_NormalMap, uvX), _NormalMapScale);
    half3 tangentNormalY = UnpackScaleNormal(tex2D(_NormalMap, uvY), _NormalMapScale);
    half3 tangentNormalZ = UnpackScaleNormal(tex2D(_NormalMap, uvZ), _NormalMapScale);
#endif
    tangentNormalX.x *= axisSign.x;
    tangentNormalY.x *= axisSign.y;
    tangentNormalZ.x *= -axisSign.z;

    // Swizzle world normals to match tangent space and apply Whiteout normal blend.
    tangentNormalX = half3(tangentNormalX.xy + input.worldNormal.zy, tangentNormalX.z * input.worldNormal.x);
    tangentNormalY = half3(tangentNormalY.xy + input.worldNormal.xz, tangentNormalY.z * input.worldNormal.y);
    tangentNormalZ = half3(tangentNormalZ.xy + input.worldNormal.xy, tangentNormalZ.z * input.worldNormal.z);

    // Swizzle tangent normals to match world normal and blend together.
    worldNormal = normalize(tangentNormalX.zyx * triplanarBlend.x +
                            tangentNormalY.xzy * triplanarBlend.y +
                            tangentNormalZ.xyz * triplanarBlend.z);
#else
#if defined(_URP)
    half3 tangentNormal = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, input.uv), _NormalMapScale);
#else
    half3 tangentNormal = UnpackScaleNormal(tex2D(_NormalMap, input.uv), _NormalMapScale);
#endif
    worldNormal.x = dot(input.tangentX, tangentNormal);
    worldNormal.y = dot(input.tangentY, tangentNormal);
    worldNormal.z = dot(input.tangentZ, tangentNormal);
    worldNormal = normalize(worldNormal) * (facing ? 1.0h : -1.0h);
#endif
#else
    worldNormal = normalize(input.worldNormal) * (facing ? 1.0h : -1.0h);
#endif
#endif

今回はNormalMapScaleの値が機能しないという点です。

これは具体的にはUnpackNormalScale()を使用している部分が異常であるということになります。

UnpackNormalScale()はノーマルマップの画像から法線を抽出する機能です。

これはTriplanerMapplingを使用している条件分岐で2か所存在します。

・TriplanerMappingを使用する場合

#if defined(_URP)
    half3 tangentNormalX = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, uvX), _NormalMapScale);
    half3 tangentNormalY = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, uvY), _NormalMapScale);
    half3 tangentNormalZ = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, uvZ), _NormalMapScale);
#else
    half3 tangentNormalX = UnpackScaleNormal(tex2D(_NormalMap, uvX), _NormalMapScale);
    half3 tangentNormalY = UnpackScaleNormal(tex2D(_NormalMap, uvY), _NormalMapScale);
    half3 tangentNormalZ = UnpackScaleNormal(tex2D(_NormalMap, uvZ), _NormalMapScale);
#endif

・TriplanerMappingを使用しない場合

#if defined(_URP)
    half3 tangentNormal = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, input.uv), _NormalMapScale);
#else
    half3 tangentNormal = UnpackScaleNormal(tex2D(_NormalMap, input.uv), _NormalMapScale);
#endif

まずはTriplanerMappingを使用していないケースの方が単純のためこちらをベースにデバッグを行います。また、開発環境ではURPを使用していないため以下の一行を変えてみます。

#if defined(_URP)
    half3 tangentNormal = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, input.uv), _NormalMapScale);
#else
    half3 tangentNormal = UnpackScaleNormal(tex2D(_NormalMap, input.uv), 0);//変更
#endif

これで変化がありノーマルマップが適応されなくなった場合_NormalMapScaleの値が破断していることを意味しますが結果は変わりませんでした。

これはUnpackNormalScaleに問題がある可能性を疑います。

今回は問題の概要が分かったため次回バグの改善を行います。

本日は以上です。