本日はShader枠です。
私事ですが、筆者の師匠に当たるかたとお会いしていました。話の中で8月にShaderに関するイベントを開催する流れになりました。
今回はShaderをゼロから学ぶ型や、自分自身が使いやすいように空のHLSLシェーダーのテンプレートを残します。
〇テンプレート
Shader "HoloMoto/HLSLTemplateShader"//このShaderの名前 { Properties//Unityのマテリアルに表示されるパブリックな変数 { _MainColor("MainColor",color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque" } Pass{ HLSLPROGRAM//ここからENDHLSLまではcg/HLSL言語で記述 #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl" struct appdata_t { }; struct v2f { }; v2f vert (appdata_t v)//頂点shader 頂点の処理を行う。 { v2f o;//V2f構造体をoと指す return o;//Oに出力 } float4 frag(v2f i):SV_TARGET { float4 col = (1,1,1,1);//RGBA=1,1,1,1=白 return col;//出力 } ENDHLSL } } }
〇HLSL
このShaderではURPで動かすことを想定しています。
URPでは[Package]の[com.unity.render-pipelines.universal/ShaderLibrary]にある[Core.hlsl]というHLSLファイルがあり、これがUnityでShaderを書く上で標準的な機能を提供します。
UnityにおけるC#の[Monobehavior]に当たるイメージです。
このHLSLを使用するためにCGPROGRAM~ENDCGではなくHLSLPROGRAM~ENDHLSLを使用しています。
〇Propertiesブロック
Properties { _MainColor("MainColor",color) = (1,1,1,1) }
PropertiesではUnityのマテリアルに表示したい変数を記述します。 このブロックに記述された変数はUnityのC#でスクリプト側から変更できたり、マテリアルでGUIで編集できます。
〇 SubShader
SubShaderは実際のShaderの処理を記述します。
このブロックの中にTagsブロックやPassなどがあります。
〇Tagsブロック
TagsブロックはShaderの性質を記述します。 α値(透明度)を扱うShaderやURP専用を意味するShader等属性を付けることができます。
〇Pass
Passは1回のレンダリングで処理されるShader処理を記述します。
Passブロックの中に頂点シェーダーやフラグメントシェーダーを記述します。
Passは複数記述することができ、以前記述したアウトラインを描くShaderではPassが二つ存在します。
[https://redhologerbera.hatenablog.com/entry/2021/05/27/211303:embed:cite]
これは一回目のレンダリング時にアウトラインを記述し、二回目でオブジェクト本来の姿を記述するというように処理しているためです。
Passをふやすことで複雑なShaderを記述することもできますが、レンダリング時の処理がその分増えることになるのでコストと引き換えになります。
〇HLSLPROGRAM~ENDHLSL
HLSLPRPOGRAM、ENDHLSLはShaderLab言語内で、この内部でCg/HLSL言語で記述することを意味します。
例えばHLSLPROGRAMの前にあるPropertiesブロックでは、次の様に変数の終わりに;が記述されていません。
Properties { _MainColor("MainColor",color) = (1,1,1,1) }
これはShaderLab言語と呼ばれるUnity独自の形式で記述しているためです。
HLSLPROGRAM~ENDHLSL間に記述される変数ではC、C#同様末尾に[;]を付ける必要があります。
float4 col = (1,1,1,1);
〇struct appdata_t
[struct]はC言語などで見られる構造体を指し、[appdata_t構造体]という意味になります。
[appdata]等表されることやそもそも記述が無く[include]で使用しているコアpackageからそのまま引用することもあります。
このブロックではShaderで描画されるオブジェクトの持つ基礎情報を保持します。
〇struct v2f
[v2f構造体]は一般的に使用される頂点シェーダーで処理したデータをフラグメントシェーダーに渡すために格納する構造体です。
vertex To fragmentを略し一般的にv2fと使用されることが多いです。
〇頂点シェーダー
頂点シェーダーでは3Dモデルの頂点を処理するShaderです。
ここではオブジェクトをUnityの座標系に処理し、オブジェクトとして描画できるようにすることなどを処理します。
v2f vert (appdata_t v) { v2f o; return o; }
例えば次のアウトラインを描画するShaderではPassの一つで頂点を法線(頂点の持つベクトル)に拡張展開し、元の3Dモデルより大きなオブジェクトを描画することでアウトラインを描画しています。
〇フラグメントシェーダー
フラグメントシェーダーでは色情報を処理します。
float4 frag(v2f i):SV_TARGET { float4 col = (1,1,1,1); return col; }
この色情報とはデバイスごとのピクセル(解像度の単位)ごとに処理されます。
例えば、100ピクセルがあった場合、100回に分けてピクセルごとの色を出力し描画します。
以上がテンプレートのShaderになります。
UnityではShaderを新規作成することでテンプレートを使用することができますが、ここでは筆者がゼロから学ぶ型に教えやすいように用意しました。
今後開催されるイベントに関しては本ブログでも情報を載せます。