Shaderが書けないUnityエンジニアという事に危機感を感じてきたので、メモ書きしながら覚えていく事にする。
http://qiita.com/mitchydeath/items/bfde2b15c8ae4b928662
の続き
前回と同じく
http://tips.hecomi.com/entry/2014/03/16/233943
を参考にさせていただき、コードを実行しながら覚えていくことにする。
固定関数シェーダでは特に面白いことは出来ませんでしが、サーフェイスシェーダを使うと色々な表現が可能になります。
シェーダは通常はライティングとの相互作用やレンダリングパスなど複雑なコードを書く必要があります。
そこで Unity は、一段階抽象化されたコードを書くだけで、これをコンパイルして複雑なコードを自動生成してくれる仕組みとして、
サーフェイスシェーダを提供してくれています。サーフェイスシェーダは Cg/HLSL で記述します。
※上記の参考記事様から引用
へー!!面白そう。
とりあえずどんなものか診てみる。
サンプルコード1
Shader "Custom/5" {
Properties {
_MainColor("Color", Color) = (1,1,1)
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
float4 _MainColor;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = _MainColor.rgb;
}
ENDCG
}
Fallback "Diffuse"
}
当たり前だが、固定関数シェーダとはだいぶ見た目が違う。
Propertiesの書き方だけ共通なのかな。
参考記事様によると、「サーフェイスシェーダはCGPROGRAM 〜 ENDCG ブロック内に記述します」とのこと。
ふむふむ確かに、囲まれているところだけ固定関数シェーダとは記述方法が違う。
よりプログラムっぽくなっている。
その最初の行にある pragma 文は、サーフェイスシェーダをどのようにコンパイルするかを指示しています。
この指示は以下の形式で記述します。
#pragma surface surfaceFunction lightModel [optionalparams]
※参考記事より引用
ふむふむ。
・サーフェイスシェーダでは#pragma surfaceは固定?
・surfaceFunctionに関数名?(上のサンプルで言うとsurf)を入れる
・lightModelにはライティングモデルを指定する
・optionalparamsには透過させたいときは alpha、頂点の変形をしたい場合は vertex などの指定が行える
みたいな感じかな。
なるほど。「ライティングモデル」と「頂点の変形」以外は何となく分かる。
ライティングモデルについて
http://docs.unity3d.com/ja/current/Manual/SL-SurfaceShaderLightingExamples.html
ほー。なるほど。
確かに見た目の光沢とかが結構変わる。
ライティングモデルの中にもデフォルトで組み込まれているものやカスタムとして自作することもできるらしい。
頂点の変形について
http://docs.unity3d.com/ja/current/Manual/SL-SurfaceShaderExamples.html
頂点修飾子のある法線押し出しの項に例が書いてある
なるほど。頂点を動かすことで上記写真のように形を変えることができるらしい。
法線というのがまだどういうものかは分からないが、どんな事ができるかはなんとなくわかった。
ちなみにマテリアルに貼り付けた際の挙動としては、前回の記事のサンプルコード3と同じように見える。
Colorを変更することだけ可能である。
ではコードの中を詳しく見ていく。
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
float4 _MainColor;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = _MainColor.rgb;
}
ENDCG
Input構造体が定義されており、surf関数に渡される。
関数の中ではPropertiesの項で定義されている_MainColorのColorがSurfaceOutputのAlbedoプロパティに代入されている。
SurfaceOutputのAlbedoプロパティは反射の割合を示していて 0 にすると真っ黒になるらしい。
あと、Propertiesの項に定義しても「float4 _MainColor;」のようにCGPROGRAMの中で再定義しないと参照できないらしい。
ふむ。。なんとなく理解はできる。
あとはsurf関数はどうやって呼びだされているかが疑問である。
後から調べることにする。。。
あとはTagsについて
Tags ブロックでは「いつ」「どのように」レンダリングを行うかの指定を Key-Value の形式で与えます。
最初の例では RenderType を Opaque (不透明)に指定しています。透明な方は Transparent を指定しています。
※参考記事より引用
ふむ。挙動がよくわからないのでこの行をコメントアウトしてみる。
→変化がない
ValueをOpaqueからTransparentにしてみる。
→変化がない
んー。これも後から詳細を調べよう。。
サンプルコード2
Shader "Custom/6" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
サンプルコード1と違うのは
PropertiesにTextureが指定できることと、
Input構造体でfloat2 のuv_MainTexが渡ってくることくらいかな。
どんな意味を持つフィールドなのか。
テクスチャの UV 座標を参照するためには Input 内で対象の変数の頭に uv プレフィックスを付加した変数を宣言します
。これを Cg の組み込み関数の tex2D を使って、該当するテクスチャ座標の色を参照しています。
Cg の組み込み関数については、ドキュメントをご参照下さい。
※参考記事より引用
Cg Standard Library Documentation
Cgの「Cg Toolkit User's Manual」の日本語訳のPDFファイル - 強火で進め
ほーなるほど。どんな変数名をつけるかによってその変数の値が変わるわけか。
他にもそんな規約(?)があるのかな。
インスペクタではTextureの指定ができるようになっている。
んー。。。サーフェイスシェーダについて軽く調べたがまだまだ理解が足りてない。
次の記事ではサーフェイスシェーダをもう少しカスタムしてちょっとだけ凝ったことしてみたり、
今日調べきれなかった項目について調べたりする。