準備運動も終わったので本丸のトゥーンシェード部のPass(Name "FORWARD")を見て行きます。今回は頂点シェーダー部
入出力セマンティクスと頂点シェーダー
struct VertexInput { float4 vertex : POSITION; float3 normal : NORMAL; float4 tangent : TANGENT; float2 texcoord0 : TEXCOORD0; }; struct VertexOutput { float4 pos : SV_POSITION; float2 uv0 : TEXCOORD0; float4 posWorld : TEXCOORD1; float3 normalDir : TEXCOORD2; float3 tangentDir : TEXCOORD3; float3 bitangentDir : TEXCOORD4; LIGHTING_COORDS(5,6) UNITY_FOG_COORDS(7) }; VertexOutput vert (VertexInput v) { VertexOutput o = (VertexOutput)0;
頂点シェーダーvertはVertexInput構造体を入力、VertexOutput構造体を出力としています。LIGHTING_COORDSマクロはTEXCOORD5/TEXCOORD6にライト周りのテクスチャとして設定し、UNITY_FOG_COORDSマクロはTEXCOORD7にフォグ周りのテクスチャを設定しています(これのマクロ展開についてはまた別の時にやります)。
o.uv0 = v.texcoord0; o.normalDir = UnityObjectToWorldNormal(v.normal);
uvはそのまま出力に渡しています。
出力normalDirは、頂点法線の「ワールド空間」の値になります。これ、覚えておいた方が良いかもです。
o.tangentDir = normalize( mul( unity_ObjectToWorld, float4( v.tangent.xyz, 0.0 ) ).xyz );
接線(タンジェント)ベクトルもワールド空間に変換して出力します。mulに渡す前に同次座標wを削除してるのはなんでなんだろ。wに値が入ってるのかな?(よくわかってない)
o.bitangentDir = normalize( cross(o.normalDir, o.tangentDir) * v.tangent.w);
crossはベクトルの外積を返す関数で、ここでは法線と接線から従法線(バイタンジェント)ベクトルを算出しています。さっきサクったwはここで使っているのですね。
※この辺のwの使い方実はいまいち把握できてないので今度ちゃんと調べます。
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
頂点座標自体もワールド空間の物を出力しておきます。
float3 lightColor = _LightColor0.rgb;
このライトのカラー値はマクロで使用しています。
o.pos = UnityObjectToClipPos(v.vertex );
最後に、頂点のクリップ空間座標を出力します。
UNITY_TRANSFER_FOG(o,o.pos); TRANSFER_VERTEX_TO_FRAGMENT(o) return o; }
組み込みマクロを2個実行して、構造体を返します。頂点シェーダーはここまで。
余談
そういえば、Unity2017.3から(なのか?)、"mul(UNITY_MATRIX_MVP,〜)"を含むシェーダーコードを書くと、該当部分が自動的に"UnityObjectToClipPos(〜)"に置換され、ファイルの先頭に以下の注釈が追記されるようになりました。
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
なにかしらの演算を省略する最適化があるのかな?(UnityObjectToClipPosの中身が更新されたのかはまだ見てない)。前者の方が直感的で分かりやすいと思っていたのですが、保存ができないので今後は後者を使っていきます。
2018/9/5追記
上記の現象について、下記に対応方法が記載されていました。
https://docs.unity3d.com/ja/current/Manual/SL-BuiltinMacros.html
自動アップグレードを無効にする UNITY_SHADER_NO_UPGRADE を使うと、Unity が自動的にシェーダーファイルをアップグレードするのを無効にすることができます。
UNITY_SHADER_NO_UPGRADEはどうやって使うのかがわからなかったのですが、ググったり自身で確認した限り、コメントで書いておく(!)のが正しいみたいです。マジか!?