ムラサメ研究ブログ

主にゲームやプログラミングのログ

UNITYシェーダー研究 UNITシェーダを読む

今回のソース

https://github.com/YukiMiyatake/UnityLesson/tree/Shader_2

前回のあらすじ

Surfaceシェーダを新規で作る 中野シスターズに適用
Surfaceシェーダの解説

たいした内容じゃなくてすみません

でも 初歩からやりたいの

UNITシェーダを適用する

本格的なシェーダーを作るには UNITシェーダは欠かせないので Surfaceシェーダと同じように作る
今度は名前を Unit/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
        }
    }
}

今度は明らかに、レンダリング結果が変わった

f:id:murasame-labo:20170911092726p:plain

シェーダーの中身

今回は前回と違い、テクスチャしかパラメーターがありません!

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しても変化しない)