夜風のMixedReality

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

UnityでのHLSLファイルの作成法 ShaderでHLSLファイルを使用する理由

本日はShader勉強枠です。

本日インターン生でお仕事にかかわっている方からShaderに関して質問をもらいました。

良い内容だったのでこちらでも記事にします。

・質問内容

Shaderに関して学習を始めたが、Unity内でhlslファイルの作成方法がわからない。

ShaderGraphで冗長な処理をhlslファイルにまとめられたら良いと思ったがより良い方法があれば教えてほしい

〇Unityでのhlslファイルの作成方法

〇そもそもhlslとは?

hlslはHigh Level Shader Langage(ハイレベルシェーダー言語)という名前でMicrosoftによって開発されたDirectX向けのShader言語です。

UnityではUnity独自のShaderLab言語でShaderを記述します。これは●●.Shaderの拡張子を持っていますが、内部は次のようになっています。

Shader "Shader名"
{
    Properties
    {
       //Materialに表示される変数 C#でいうところのpublic変数 
    }
    SubShader
    {
        Tags { "RenderType"="Opaque"  }//Shaderの属性 透明度を扱うやレンダリング順等
        Pass
        {
////////////////////////////ここからhlsl文/////////////////////////////
            HLSLPROGRAM
            struct appdata
             {
               //3Dモデルから受け取る情報(頂点座標やuv等)を格納・宣言
              };
            v2f vert(appdata v)//モデルの頂点に関する処理 Unity座標への変換等
            {
               v2f o;
                //処理
               return o;
            }
             
            struct v2f
            {
                //頂点シェーダーでの処理結果を格納する
         //一般的にVertex to Fragment でv2f 
            };
            float4 frag(v2f i):SV_Target
            {
              //コンピュータの1ピクセルごとの色を処理する
            }
            ENDHLSL
///////////////////////////ここまでhlsl文/////////////////////////////////
        }
         
    }
}

このように ShaderLab内でhlsl言語を使用した処理を行っています。

〇なぜShaderLabでhlslかけるのにわざわざ別のhlslファイル作成しているのか?

 ShaderLab内でhlslの処理を記述することはできますが、よくShaderLabとhlslを別々のファイルとして作成し、ShaderLabの処理内でhlslファイルをインクルードすることがあります。

  #include "test.hlsl"

これは可読性と拡張性を引き出すために行われています。

可読性

ShaderLabでは2つの言語を同時に扱うという性質上、Editorのエラー検知や参照先・元、予測変換といった支援が受けれないことがあります。

 ShaderLabとhlslを別に記述して、ShaderLab側から読み込むことでコーディングのスピードを上げることができます。

Shader "Shader名"
{
    Properties
    {
       //Materialに表示される変数 C#でいうところのpublic変数 
    }
    SubShader
    {
        Tags { "RenderType"="Opaque"  }//Shaderの属性 透明度を扱うやレンダリング順等
        Pass
        {
            HLSLPROGRAM
            #include "Assets/hoge/hoge/test.hlsl"
            ENDHLSL
        }
         
    }
}
  struct appdata
             {
               //3Dモデルから受け取る情報(頂点座標やuv等)を格納・宣言
              };
            v2f vert(appdata v)//モデルの頂点に関する処理 Unity座標への変換等
            {
               v2f o;
                //処理
               return o;
            }
             
            struct v2f
            {
                //頂点シェーダーでの処理結果を格納する
         //一般的にVertex to Fragment でv2f 
            };
            float4 frag(v2f i):SV_Target
            {
              //コンピュータの1ピクセルごとの色を処理する
            }

また上記のように2つのファイルにすることによって1つのファイルの行数が減り、可読性および整備性が上がります

拡張性

C#ではネームスペースや継承によって汎用的な処理を全体で1つのファイルで管理できます。

Shaderの場合UnityCG.cginc(URPではPackages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl)が主な継承元となっており

以下のように読み込みます

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

これによって元のhlslで定義されている関数や定義を再定義せずに記述できます。 

 UnityCG.cgincやCore.hlslではUnity座標軸への変換(行列(Matrix))などの冗長な処理が記述されています。

〇Unity内でのhlslファイルの作成方法

Unity内ではShaderファイルを作成することはできますが、hlslファイルを作成することはできません。

そのためファイルエクスプローラーでhlslを作成したい階層でテキストファイルを作成します。

f:id:Holomoto-Sumire:20220308214849j:plain

作成したテキストファイルの名前を●●.hlslへ書き換えます。 拡張子をhlslに変換することでhlslファイルを作成できます。

f:id:Holomoto-Sumire:20220308215019j:plain

以上でUnityでhlslファイルを作成する方法になります。

初歩的なことではありますが、筆者も理解するまでShaderLab言語の中でhlslを使用している理由などがわからなかったりしたので今回質問をくれたインターン生の方のように初学者のかたの助けになればよいと思っています。