UNITYシェーダー研究 UNITシェーダを読む
今回のソース
https://github.com/YukiMiyatake/UnityLesson/tree/Shader_2
前回のあらすじ
Surfaceシェーダを新規で作る
中野シスターズに適用
Surfaceシェーダの解説
たいした内容じゃなくてすみません
でも 初歩からやりたいの
UNITシェーダを適用する
本格的なシェーダーを作るには UNITシェーダは欠かせないので Surfaceシェーダと同じように作る
今度は名前を Unlit/yUnit にする
Shader "Unlit/yUnit" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; 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; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } } }
今度は明らかに、レンダリング結果が変わった
シェーダーの中身
今回は前回と違い、テクスチャしかパラメーターがありません!
Pass
Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog
UNITシェーダでは 複数のPassを持つことができる
輪郭線とか影とか
今回は1個
pragmaは 前回はSurfaceでサーフェースシェーダを指定したが、今回は vertex、fragmentと2つのシェーダを指定している
もちろん、それらの後に続くのは エントリポイントである
今回はfogが有効になっている
変数宣言等
#include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST;
UnityCG.cginc をincludeしているが、色々と便利なマクロや関数等が入ったヘッダなので使う
構造体は今回2個
頂点毎の入力(attribute)の appdata
フラグメントシェーダに渡す Varyingの v2f
そして シェーダーの引数 uniformの _MainTex
シェーダー中身
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; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col; }
頂点シェーダ
UnityObjectToClipPosの定義を見てみよう
// Tranforms position from object to homogenous space inline float4 UnityObjectToClipPos(in float3 pos) { // More efficient than computing M*VP matrix product return mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(pos, 1.0))); } inline float4 UnityObjectToClipPos(float4 pos) // overload for float4; avoids "implicit truncation" warning for existing shaders { return UnityObjectToClipPos(pos.xyz); }
オブジェクトのローカル座標からビューポート座標に変換している
TRANSFORM_TEX
// Transforms 2D UV by scale/bias property #define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
なんと、トークンマクロで
TRANSFORM_TEX(v.uv, MainTex); は
v.uv.xy * MainTex_ST.xy + MainTex_ST.zw
になる。
MainTex_ST.xyにTiling、zwにOffsetの値が入ってくるようだ
UNITY_TRANSFER_FOG
// SM3.0 and PC/console: calculate fog distance per-vertex, and fog factor per-pixel #define UNITY_TRANSFER_FOG(o,outpos) o.fogCoord.x = (outpos).z
ビューポート座標系でのZ座標をFOGのパラメータに入れている。距離によるFOG。ここは さらっと読み飛ばしてもいい
結論からいうと、ローカル座標をビューポート座標に変換し、テクスチャのUVを補正して、Zフォグのパラメータを渡しているだけのようだ
フラグメントシェーダ
// sample the texture fixed4 col = tex2D(_MainTex, i.uv); // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col;
非常にシンプルで、テクスチャマッピングして、FOGを適用しているだけのようだ
ライトの計算も何も入っていない(実際DirectionalライトをON/OFFしても変化しない)