夜風のMixedReality

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

Unityでシェーダーエラーが発生する場合のトラブルシューティングフローについて

本日はShader学習枠です。

筆者の所属している会社では良くも悪くもグラフィックエンジニアは筆者が一人で担当しており、社内で使用するシェーダーも筆者が担当していることが多いのですが、先日外部で公開されていたシェーダーを社内で利用したところMetaQuestで動作しなかったというほかのエンジニアからの報告を受け、トラブルシューティングを行いました。

今回はトラブルシューティングの中でQuestで動作しないようにコンパイルが行われていたことが判明したためシェーダーが動かない場合のトラブルシューティングとともに紹介します。

〇シェーダーが動かない場合のトラブルシューティング

 筆者がシェーダーのデバッグを行う際は最初に以下の2点で大きく分類します。

A シェーダーエラーのピンク

一般的にシェーダーエラーといえばこちらになります。

 

B 何も描画されない

シェーダーエラーすら起こさず何も描画されない場合です。


多くの場合はAの現象が発生します。

Aの場合も問題の原因が幅広いため原因を特定するために考えることがあります。

〇URPを使用している場合のSurfaceShader

次に筆者が確認する点は使用しているシェーダー関数です。

URPの場合はSurface関数はサポートされていないため#pragma surface ○○との記載がある場合はURPで動かない可能性があります。

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"
  ・・・
        }

redhologerbera.hatenablog.com

またURPの場合はライト関連のネームスペースのコンフリクトの関係でLitなシェーダーが動かないことがあります。

〇Fallbackの機能の利用

デバッグをするうえでFallbackの機能を使用することもあります。

Shader "Unlit/TutorialShader"
{
    Properties
    {    }
    SubShader
    {
        Pass
        {
         ・・・
        }
    }
    Fallback "Hidden/InternalErrorShader"
}

Fallbackはこのシェーダーが実行されない場合に実行するシェーダーを指定します。

 デフォルトでHidden/InternalErrorShaderが使用されており、このシェーダーがよく見るシェーダーエラーのピンクを表示させています。

次のように自身がわかりやすいシェーダー名を指定することでシェーダーの構文等に問題があるのか? 実行環境に問題があるのかを判別することができます。

            Fallback "Graphics Tools/Standard" 

この方法はエディタと実機で違って見えるような場合や実機だとエラーを吐いてしまうなどの場合に試しています。

このFallbackが正常に機能している場合はシェーダー内でコンパイル制限などが行われている可能性があります。

冒頭の仕事でのMetaQuestで動かない場合はこちらで実機の環境で構文などに問題はないが動かないことがわかり調べたところ次の一文が追加されていました。

#pragma exclude_renderers glsl

docs.unity3d.com

このpragmaを指定することでglsl用のグラフィックスAPIを使用している環境ではコンパイルされないようになります。

〇デバッグ用のreturnの使用

筆者の場合どうしても動かない原因がわからない場合フラグメントシェーダー部に一行ずつデバッグ用のreturnを入れていきます。

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = float4(1,1,1,1);

     hoge1

                  hoge2
                return col;
            }

たとえばフラグメントシェーダー部が上記のような例で、最終的なcolの出力がおかしい場合は筆者の場合次のようなテクニックを使用しています。

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = float4(1,1,1,1);

     hoge1
                return col;
                  hoge2
                return col;
            }

処理を挟むごとにreturn colを挟み、色として出力を行います。

場合によっては色の出力が判別できないことがあるので return float(1,0,0,1)などのように明らかに判別できる色を出力としていれ、デバッグを行っています。

本日は以上です。