はじめに
Unityのシェーダーへの理解を深めるため、Surfaceシェーダーとフラグメントシェーダーの違いを軽くまとめてみました。
Surfaceシェーダーとフラグメントシェーダー
Surfaceシェーダー
Surfaceシェーダーを使うとライティングやシャドウを考慮したシェーダーを簡単に書くことができます。
頂点シェーダー/フラグメントシェーダー
複雑なことをやりたい場合はこちらのシェーダー。
こちらはSurfaceシェーダーと比べてコードが複雑になりやすいです。
UnlitシェーダーやImageEffectシェーダーはこちらに含まれます。
両者の書き方の違い
筆者はこれらのシェーダーのどこが違うのかよくわからなかったので、書き方の違いを自分なりに軽くまとめてみました。
主な違い
具体的には以下のような違いがあります。 他にもあるかもしれません。
・コンパイルディレクティブの書き方の違い
・Passブロックの有無
・構造体データの書き方の違い
・vertexシェーダー関数の有無
・vertexシェーダー関数の書き方の違い
・フラグメントシェーダー関数の書き方の違い
・ライティングの記述方法の違い
コンパイルディレクティブの書き方の違い
Surfaceシェーダーの場合
以下のような書き方をします。
#pragma surface surf Standard fullforwardshadows vertex vert
#pragma surface surf Standard fullforwardshadows
#pragma vertex vert
Surfaceシェーダーでは、シェーダー関数指定時にライティングモデルを指定する必要があります。
サンプルではStandardがライティングモデルになっています。
参考: https://docs.unity3d.com/jp/540/Manual/SL-SurfaceShaders.html
フラグメントシェーダーの場合
以下のような書き方をします。
#pragma vertex vert
#pragma fragment frag
参考: https://docs.unity3d.com/jp/540/Manual/SL-ShaderPrograms.html
Passブロックの有無
Surfaceシェーダーの場合
・Passを書けない
フラグメントシェーダーの場合
・Passを書く必要がある
・複数のPassが記述可能
参考: https://docs.unity3d.com/jp/540/Manual/SL-Pass.html
構造体データの書き方の違い
Surfaceシェーダーの場合
以下のような書き方をします
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
};
参考: https://docs.unity3d.com/jp/540/Manual/SL-SurfaceShaders.html
フラグメントシェーダーの場合
以下のような書き方をします
struct v2f {
half3 worldRefl : TEXCOORD0;
float4 pos : SV_POSITION;
};
TEXCOORD0
のようなセマンティクスを書く必要があります。
参考: https://docs.unity3d.com/jp/540/Manual/SL-VertexFragmentShaderExamples.html
vertexシェーダー関数の有無
Surfaceシェーダーの場合
vertexシェーダー関数は書かなくてもいい
フラグメントシェーダーの場合
vertexシェーダー関数を書く必要がある
vertexシェーダー関数の書き方の違い
Surfaceシェーダーの場合
以下のような書き方をします
void vert (inout appdata_full v) {
v.vertex.xyz += v.normal * _Amount;
}
void myvert (inout appdata_full v, out Input data)
{
UNITY_INITIALIZE_OUTPUT(Input,data);
float4 hpos = UnityObjectToClipPos(v.vertex);
hpos.xy/=hpos.w;
data.fog = min (1, dot (hpos.xy, hpos.xy)*0.5);
}
計算結果を構造体データへ格納しているのが大きな特徴です。
参考:https://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html
フラグメントシェーダーの場合
以下のような書き方をします。
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
v2f vert (float4 vertex : POSITION, float3 normal : NORMAL)
{
v2f o;
o.pos = UnityObjectToClipPos(vertex);
o.worldPos = mul(_Object2World, vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(normal);
return o;
}
計算結果を構造体データとしてreturnしているのが大きな特徴です。
参考: https://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html
サーフェースシェーダー関数(フラグメントシェーダー関数)の書き方の違い
Surfaceシェーダーの場合
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
void surf (Input IN, inout SurfaceOutput o) {
clip (frac((IN.worldPos.y+IN.worldPos.z*0.1) * 5) - 0.5);
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
}
計算結果を構造体データの中へ格納しているのが特徴です。
参考: https://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html
フラグメントシェーダーの場合
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col *= i.diff;
return col;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed shadow = SHADOW_ATTENUATION(i);
fixed3 lighting = i.diff * shadow + i.ambient;
col.rgb *= lighting;
return col;
}
計算結果をカラー値としてreturnしているのが特徴です。
参考: https://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html
ライティングの記述方法の違い
Surfaceシェーダーの場合
以下のようにパラメータを指定するだけでライティングを記述することができます。
#pragma surface surf SimpleLambert
half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
c.a = s.Alpha;
return c;
}
参考: https://docs.unity3d.com/jp/540/Manual/SL-SurfaceShaderLightingExamples.html
フラグメントシェーダーの場合
ライティング処理を自分で書く必要があります。
参考: https://docs.unity3d.com/ja/540/Manual/SL-VertexFragmentShaderExamples.html
#その他
appdataについて
appdataの正式な名前は Application to Vertex Shader Structure らしいです。
v2fについて
v2fの正式な名前はVertex Shader to Fragment Shader Structureらしいです。
#さいごに
筆者はシェーダーに関しての知識が浅いので、間違っているところがあるかもしれません。
間違いを見つけた場合は教えていただけると嬉しいです。
参考URL
Unity のシェーダの基礎を勉強してみたのでやる気出してまとめてみた
http://tips.hecomi.com/entry/2014/03/16/233943
Shader Code - Unify Community Wiki
http://wiki.unity3d.com/index.php?title=Shader_Code#Application_to_Vertex_Shader_Structure_.28appdata.29
[Unity] Vertex/Fragment shaderで通常のライティングとシャドウを適用するサンプル
http://qiita.com/edo_m18/items/ee4b9018e860c11199b0