先週の予告通り、Unity で頂点カラーマテリアルを作る方法を習得しましたので、私のメンタルモデルを記録・共有します。
Unity のマテリアルは元となるシェーダーのインスタンスと捉えることができ、特殊なマテリアルが欲しい場合はシェーダーをカスタマイズすることになります。
作り方は現在2通り提供されており
1.直感的な方法で Shader Graph を使ってシェーダーを作成する方法
2.シェーダーコードの書式を理解して書き換える方法
があります。
順番に具体的な手順を追ってみましょう。
■Shader Graph
Shader Graph の導入と使い方について、こちらの記事を参考に実践してみてください。
nn-hokuson.hatenablog.com
そのあとは覚えた手順に従って
Create > Shader > Unlit Graph
を選択し、作成された Shader ファイルから
Shader Graph のエディタを開いて、ノード作成より
Input > Geometry > Vertex Color
を選び out を Unlit Master ノードの color に接続します。
Save Asset して、その Shader から Create > Material を行えば頂点カラーマテリアルが完成します。
ちょ… Shader Graph やばくない?
何がやばいって、頂点カラーシェーダー作るのが、簡単すぎ
直感的に何でもできそうですよ、ぜひ皆さんも触ってみてください。
■シェーダーコードの書き換え
Unity のシェーダーコードは Surface 形式とピクセルシェーダー形式の二通りの記述形式があります。
Surface 形式は Unity 独自のピクセル値のライティングお任せ書式です。
ピクセルシェーダー形式は最後のピクセル値の決定まで操作できる書式です。
頂点カラーは頂点情報のみに頼るので Surface 形式を使うのが楽に書けます。
ということで Surface 形式でテンプレートを作り、そこに手を入れていきます。
Craete > Shader > Standard Surface Shader
を選択して Shader ファイルを作成します。
これを開くと Visual Studio のテキストエディターになります。
その時の何もしていないテンプレコードは次の通り
Shader "Custom/VertexColor" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Standard fullforwardshadows // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; }; half _Glossiness; half _Metallic; fixed4 _Color; // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. // #pragma instancing_options assumeuniformscaling UNITY_INSTANCING_BUFFER_START(Props) // put more per-instance properties here UNITY_INSTANCING_BUFFER_END(Props) void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; // Metallic and smoothness come from slider variables o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
ここから頂点カラーシェーダに書き換えますが、参考にする記事はこちら
nn-hokuson.hatenablog.com
上記のシェーダーコードを頂点カラー用に書き換えた結果がこちら
Shader "Custom/VertexColor" { Properties { _Color ("Color", Color) = (1,1,1,1) _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Standard fullforwardshadows vertex:vert // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 struct Input { float4 vertColor; }; half _Glossiness; half _Metallic; fixed4 _Color; // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. // #pragma instancing_options assumeuniformscaling UNITY_INSTANCING_BUFFER_START(Props) // put more per-instance properties here UNITY_INSTANCING_BUFFER_END(Props) void vert(inout appdata_full v, out Input o) { UNITY_INITIALIZE_OUTPUT(Input, o); o.vertColor = v.color; } void surf (Input IN, inout SurfaceOutputStandard o) { o.Albedo = IN.vertColor.rgb; o.Alpha = IN.vertColor.a; } ENDCG } FallBack "Diffuse" }
注目するのは Input の構造体に color を入れたのと、 vert 関数を作り vert に vert を利用すると pragma で宣言しているところ
この時 surf 内で頂点カラーを出力するように書き換えています。
これで頂点カラーを利用するようになるはずです。
結果がこちら
Shader Graph で作った Unlit と異なり、Surface によりライティングが施されていることが確認できます。
■おまけ Scriptable Render Pipeline 対応
ライティングが Standard だと Light Weight Scriptable Render Pipeline で正常に描画されません。
ライティングを SRP 対応に書き換えるとうまくいきます。
ここを
#pragma surface surf Standard fullforwardshadows vertex:vert
↓
#pragma surface surf Lambert vertex:vert
こうすることで LWRP で正常に描画されるようになりました。
■参考
ちょっと頂点カラーより難しいですが、皆さんは次の水シェーダーのコードを読めますでしょうか?
こういう動きのあるシェーダーも書けるようになりたいですね。
baba-s.hatenablog.com