Shaderの基本についての調査
概要
Unity初心者の私がShaderの構造や関数のエントリーポイントについて調査したのでまとめる。
Shader
ShaderLabやHLSLの用語説明などは、ページによくまとまっているので、以降は個人的に気になったC# ScriptからShaderへのデータの渡し方や関数のエントリーポイント、Passについて知っておくべき知識などをまとめる。
Unity のシェーダの基礎を勉強してみたのでやる気出してまとめてみた - 凹みTips
Unity ShaderLab ノート - Qiita
構造
Shader クラス - Unity マニュアルには以下のように記述がある。
シェーダーオブジェクト
シェーダーオブジェクトには以下が含まれています。名前など、それ自体の情報
フォールバックシェーダーオブジェクト。Unity がこのシェーダーオブジェクトを使用できない場合に、フォールバックシェーダーオブジェクトが使用されます。
1 つまたは複数のサブシェーダー
また、共有シェーダーコードや、カスタムエディター を使用するかどうかなどの追加情報を定義することもできます。シェーダーオブジェクトの定義については、ShaderLab: シェーダーオブジェクトの定義 を参照してください。SubShader
SubShader (サブシェーダー) は、シェーダーオブジェクトを、異なるハードウェア、レンダーパイプライン、ランタイム設定に対応する部分に分離することができます。SubShader には以下が含まれています。
このサブシェーダーが対応できるハードウェア、レンダーパイプライン、ランタイム設定についての情報。
サブシェーダー タグ (サブシェーダーに関する情報を提供するキーと値のペア)。
1 つまたは複数のパス
また、すべてのパスに共通するレンダー状態などの追加情報を定義することもできます。サブシェーダーで定義できるすべての内容については、ShaderLab: サブシェーダーの定義 を参照してください。Pass
Pass (パス) には以下が含まれています。Pass タグ (パスに関する情報を提供するキーと値のペア)。
シェーダープログラムを実行する前にレンダー状態を更新するための指示
1 つまたは複数のシェーダバリアントにまとめられたシェーダープログラム
また、名前などの追加情報を定義することもできます。パスで定義できるすべての内容については、ShaderLab: パスの定義 を参照してください。
SubShader
公式ドキュメント
ShaderLab: SubShader の定義 - Unity マニュアル
Shaderを、ハードウェアごとやパイプラインごとに分けて記述するときに、SubShaderにわけて記述できる。
つまりTagやPass, そのほかBlendなどの情報をSubShaderごとに分けて書く。
実際のUniversal Render Pipeline/Litを見ると、Tag情報の中でShaderModelを4.5と2.0でわけてSubShaderで記述しているようだった。
Tagについて
分けて記載するSubShaderの目的や特性をつける。
記述例
SubShader{ Tag {"RenderPipeline" = "UniversalRenderPipeline" "RenderType" = "Opaque" } }
調べてみたところ、以下のような設定値があるらしい。
ShaderLab: タグを SubShader に割り当てる - Unity マニュアル
Tag | 値 |
---|---|
RenderPipeline | UniversalRenderPipeline |
HighDefinitionRenderPipeline | |
Queue | Background |
Geometry | |
AlphaTest | |
Transparent | |
Overlay | |
RenderType | Opaque |
Transparent | |
TransparentCutout | |
Background | |
Overlay | |
TreeOpaque | |
TreeTransparentCutout | |
TreeBillboard | |
Grass | |
GrassBillboard | |
ForceNoShadowCasting | True |
False | DisableBatching | True |
False | |
LODFading | IgnoreProjector | True |
False | PreviewType | Sphere |
Plane | |
Skybox | CanUseSpriteAtlas | True |
False |
Pass
Passとはグラフィックスのシェーダープログラム内で特定の描画処理を定義するためのセクションまたはブロックのこと。
Universal Render Pipeline/Litを見てみると、物体の描画や影の描画ごとにPassが作成されていた。
各Passにvertex関数とfragment関数があるので、どのPassも条件があえば実行される。
SubShader{ Tags{"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "Lit" "IgnoreProjector" = "True" "ShaderModel"="4.5"} Pass{ Name "ForwardLit" Tags{"LightMode" = "UniversalForward"} HLSLPROGRAM #pragma vertex LitPassVertex #pragma fragment LitPassFragment *** ENDHLSL } Pass{ Name "ShadowCaster" Tags{"LightMode" = "ShadowCaster"} HLSLPROGRAM #pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment *** ENDHLSL } Pass{ Name "GBuffer" Tags{"LightMode" = "UniversalGBuffer"} *** } Pass{ Name "DepthOnly" Tags{"LightMode" = "DepthOnly"} *** } Pass{ Name "DepthNormals" Tags{"LightMode" = "DepthNormals"} *** } Pass{ Name "Meta" //for lightmap baking Tags{"LightMode" = "Meta"} *** } Pass{ Name "Universal2D" Tags{ "LightMode" = "Universal2D" } *** } }
またHLSLでは、vertex shaderとfragment shaderのメイン関数のエントリーポイントはそれぞれ
#pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment
のようにして指定する。
メイン関数のエントリーポイントを間違えると、たとえばFowardLit Passだと
did not find shader kernel LitPassVertex to comile
が表示されてコンパイルに失敗する。
#pragmaディレクティブは下記に一覧が表示されている。
HLSL のプラグマディレクティブ - Unity マニュアル
その他のshaderの文法については以下に詳細が記載されている。
例えば、fragment shaderで色を出力する関数にはSV_Targetの指定が必要。
シェーダーセマンティクス - Unity マニュアル