Unity - Shader の書き方の基本
初めに
Shader(シェーダー)は描画方法を記述したプログラムであり、1つの Material に1つのシェーダーを設定します。本記事では、Shader の書き方の基本をまとめます。
概要
Unity のシェーダーを作成する際には、HLSL と ShaderLab という言語を使用します。
Shader の書き方
Assets 内で右クリック > Create > Shader から選択して、Shader を作ります。
(例:デフォルトの CustomRenderTexture)
Shader "CustomRenderTexture/MyShader" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex("InputTex", 2D) = "white" {} } SubShader { Blend One Zero Pass { Name "MyShader" CGPROGRAM #include "UnityCustomRenderTexture.cginc" #pragma vertex CustomRenderTextureVertexShader #pragma fragment frag #pragma target 3.0 float4 _Color; sampler2D _MainTex; float4 frag(v2f_customrendertexture IN) : COLOR { float2 uv = IN.localTexcoord.xy; float4 color = tex2D(_MainTex, uv) * _Color; // TODO: Replace this by actual code! uint2 p = uv.xy * 256; return countbits(~(p.x & p.y) + 1) % 2 * float4(uv, 1, 1) * color; } ENDCG } } }
文構造
Shader の構造は次のようになっています。
Shader "Examples/ShaderSyntax" //Shaderの定義 { CustomEditor = "ExampleCustomEditor" //CustomEditorの割り当て Properties { // プロパティの定義 } SubShader { // SubShaderの残りの部分をここで定義 Pass { // Passの定義 } } Fallback "ExampleFallbackShader" }
Unity の Shader は、主に次の3つのブロックで構成されています。
ブロック | 説明 |
---|---|
Properties | シェーダーのプロパティを定義する場所。プロパティには、float、vector、color、textureなどが含まれる。 |
SubShader | 複数のプラットフォームで動作するシェーダーを定義する場所。複数のSubShaderブロックを使用することで、プラットフォームごとに異なるシェーダーを定義できる。 |
Pass | シェーダーがレンダリングパイプラインにどのように組み込まれるかを定義する場所。通常、シェーダーには複数のPassブロックがあり、それぞれが異なるレンダプロパリングステージで使用される。 |
CustomEditor の割り当てができます。これにより Inspector の表示を変更などができます。記述しなくても問題はありません。
SubShader はプラットフォームごとに適切なものが選ばれます。適切な SubShader が見つからなかった場合、FallBack で割り当てた Shader を使用します。
Properties
Properties では、float や color などプロパティを定義することができます。
Properties { //_Colorが変数名, "Color"がInspectorへの表示, Color が型名, 右辺が初期値 _Color ("Color", Color) = (1,1,1,1) _MainTex("InputTex", 2D) = "white" {} }
Material に Shader を割り当てたとき、Inspector からプロパティを変更することができます。
SubShader・Pass
Shader 内には、1つ以上の SubShader を記述します。SubShader 内に Shader の設定を記述していきます。
SubShader の中では、Pass や Tags 記述していきます。Pass 内に実際の処理を記述します。
(例:単色シェーダー)
Shader "Unlit/SingleColor" { Properties { // マテリアルインスペクターの Color プロパティ、デフォルトを白に _Color ("Main Color", Color) = (1,1,1,1) } SubShader //SubShaderの定義 { Pass //レンダリングを行う { //CGPROGRAMからENDCGまでが実際の処理の記述 CGPROGRAM //関数をどのシェーダーに利用するか記述 #pragma vertex vert //vert関数をvertex(頂点)シェーダーとしてコンパイル #pragma fragment frag //frag関数をfragmentシェーダーとしてコンパイル // 頂点シェーダー // 今回は、 "appdata" 構造体の代わりに、入力を手動で書き込みます // そして v2f 構造体を返す代わりに、1 つの出力 // float4 のクリップ位置だけを返します float4 vert (float4 vertex : POSITION) : SV_POSITION { // クリップスペースへの変換位置 // (モデル*ビュー*プロジェクション行列で乗算) return mul(UNITY_MATRIX_MVP, vertex); //mulは行列の掛け算, UNITY_MATRIX_MVPは現在のモデルビュー行列×射影行列 } // マテリアルからのカラー fixed4 _Color; // ピクセルシェーダー、入力不要 fixed4 frag () : SV_Target { return _Color; // 単に返します } ENDCG } } }
Pass 内に CGPROGRAM / ENDCG を記述し、その中にシェーダーコードを記述します。CGPROGRAM / ENDCGブロック内のコードは、HLSL言語(Cg言語)で記述されており、GPUに最適化されたコードにコンパイルされます。
〇 #pragma:プラグマディレクティブ
#pragma を使って、関数をどのシェーダーとして利用するか、指定します。
//関数をどのシェーダーに利用するか記述 #pragma vertex vert //vert関数をvertex(頂点)シェーダーとしてコンパイル #pragma fragment frag //frag関数をfragmentシェーダーとしてコンパイル
シェーダー | 説明 |
---|---|
vertex | 頂点シェーダー。3D モデルの各頂点で実行されるプログラムです。多くの場合、それは特に何もせず、頂点の位置を「クリップスペース」に変換し、渡すのみです。クリップスペースは、GPU が画面上のオブジェクトをラスタライズするために使用するものです。 また、入力テクスチャ座標を変更しないで渡します。フラグメントシェーダーのテクスチャをサンプリングするために、これが必要になるようです。 |
fragment | フラグメントシェーダー。オブジェクトが画面上で占めるすべてのピクセルでそれぞれ実行されるプログラムで、通常、各ピクセルの色を計算して出力するために使用されます。通常、画面上には何百万ものピクセルがあり、フラグメントシェーダはそれらのすべてに対して実行されます。 |
上の単色シェーダーでは、次の処理をしたことになります。
〇Tags
SubShader では、タグを使用して、いつどのようにしてレンダリングするか指定することができます。
(タグの書き方)
Tags { "TagName1" = "Value1" "TagName2" = "Value2" }
(例)
Shader "Transparent Queue Example" { SubShader { Tags { "Queue" = "Transparent" } Pass { // シェーダーのボディの残りの部分... } } }
Queue (キュー)によりオブジェクトを描画する順番を判定することに使われます。Queue のほかにも、RenderType タグや IgnoreProjector タグなどがあります。詳細は下のドキュメントをご覧ください。
docs.unity3d.com
(補足)
Shader には、上記コードの UNITY_MATRIX_MVP のように定義済みの値があります。(通常のコードでは、Vector3.left や Mathf.PI のようなものが定義済みの値)下のドキュメントにまとめてあります。
docs.unity3d.com
参考になるかもしれない過去記事
最後に
本記事のまとめ
- Shader は Properties、SubShader、Pass で構成されている
- Properties には、Inspector に表示されるプロパティを記述
- SubShader の Pass 内に基本的な処理を記述する
ShaderGraphを使って、コードを書かずに、Shader を作る機能もあります。機会があれば紹介します。