知識0からのUnityShader勉強

知識0からのUnityShader勉強

UnityのShaderをメインとして、0から学んでいくブログです。

【UnityShader】Shaderのローカル座標 #15

前回の成果

soramamenatan.hatenablog.com

リングを移動させることができた。

今回やること

f:id:soramamenatan:20190730124056p:plain

前回行なった、一番最初のただの円を描画するだけのものです。
これを修正していこうと思います。

何を修正するの?

ただの円なので修正する箇所はないように思えます。

問題点はこの部分です。

distance(fixed3(0, 0, 0), IN.worldPos);

このソースコードは、原点とPlaneのワールド座標で比較してしまっているので、Positionを動かしてしまうと

f:id:soramamenatan:20190730124405p:plain

このように円がズレてしまいます。
今回はそのズレを修正していきたいと思います。

ソースコード

Shader "Custom/moveRingFix" {
    Properties {
        _Color ("Color" , Color) = (1, 1 , 1 , 1)
    }
    SubShader {
        Tags { "RenderType" = "Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard
        #pragma target 3.0

        struct Input {
            float3 worldPos;
        };

        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o) {
            float3 localPos = IN.worldPos -  mul(unity_ObjectToWorld, float4(0, 0, 0, 
 1)).xyz;
            float dist = distance(fixed3(0, 0, 0), localPos);
            float radius = 2.0f;
            if (radius < dist ) {
                o.Albedo = _Color;
            } else {
                o.Albedo = fixed4(1, 1, 1, 1);
            }
        }
        ENDCG
    }
    FallBack "Diffuse"
}
 float dist = distance(fixed3(0, 0, 0), IN.worldPos);

この部分を

float3 localPos = IN.worldPos -  mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz;
 float dist = distance(fixed3(0, 0, 0), localPos);

このように修正しました。

不明な点は

  • unity_ObjectToWorld
  • mul
  • なぜワールド座標から引いているのか

この3点なので、説明していきます。

unity_ObjectToWorld

現在のモデルの行列のことです。

他の行列変換についても紹介します。

名称 用途
UNITY_MATRIX_MVP 現在のモデル×ビュー×プロジェクション行列
UINTY_MATRIX_MV 現在のモデル×ビュー行列
UNITY__MATRIX_V 現在のビュー行列
UNITY_MATRIX_P 現在のプロジェクション行列
UNITY_MATRIX_VP 現在のビュー×プロジェクション行列
UNITY_MATRIX_T_MV モデル×ビュー行列の変換
UNITY_MATRIX_IT_MV モデル×ビュー行列の逆変換
unity_ObjectToWorld 現在のモデル行列
unity_WorldToObject 現在のワールド行列の逆変換

mul

行列の乗算になります。

// 今回の場合
// xに行列
// yにベクトル
mul(x, y)

なぜワールド座標から引いているのか

これが今回の本題になります。
色々怪しい箇所があると思うので、何かあったらご指摘よろしくお願いします。

結論から先に言うと、Planeのワールド座標をローカル座標に変えるためです。

ローカル座標は、

子のワールド座標 - 親のワールド座標

で求めることができます。

では、なぜローカル座標が

IN.worldPos -  mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz

この式で求められるかを説明していこうと思います。

ローカル座標の求め方

Unityは、列オーダーとなっています。

f:id:soramamenatan:20190813160616p:plain

Unityの行列の扱いとベクトルのオーダー周りについてまとめておく - e.blog:より引用

なので、ベクトルは縦ベクトル(列ベクトル)となり、

{\displaystyle 
    \begin{pmatrix}
      x \\
      y \\
      z \\
      1
    \end{pmatrix}
}

で表すことができます。

今回はfloat4(0, 0, 0, 1)ですので、

{\displaystyle 
    \begin{pmatrix}
      0 \\
      0 \\
      0 \\
      1
    \end{pmatrix}
}

となります。

次に行列です。
列オーダーの場合には、MVP行列ではなくPVM行列となります。
MVPとはモデル・ビュー・プロジェクションの略で、説明は省かさせていただきます。

light11.hatenadiary.com

MVP行列ですと、

{\displaystyle 
    \begin{pmatrix}
      1 & 0 & 0 & 0 \\
      0 & 1 & 0 & 0 \\
      0 & 0 & 1 & 0\\
     Tx & Ty & Tz & 1
    \end{pmatrix}
}

※TはPositionです
になるのですが、今回はPVM行列ですので

{\displaystyle 
    \begin{pmatrix}
      1 & 0 & 0 & Tx \\
      0 & 1 & 0 & Ty \\
      0 & 0 & 1 & Tz \\
     0 & 0 & 0 & 1
    \end{pmatrix}
}

となります。

この2つのことから、

{\displaystyle 
    \begin{pmatrix}
      1 & 0 & 0 & Tx \\
      0 & 1 & 0 & Ty \\
      0 & 0 & 1 & Tz \\
     0 & 0 & 0 & 1
    \end{pmatrix}

    \begin{pmatrix}
      0  \\
      0 \\
      0 \\
     1
    \end{pmatrix}
}

と置き換えることができます。

この行列の積は、

{\displaystyle 
    \begin{pmatrix}
      a_{11} & a_{12} & a_{13} & a_{14} \\
      a_{21} & a_{22} & a_{23} & a_{24} \\
      a_{31} & a_{32} & a_{33} & a_{34} \\
     a_{41} & a_{42} & a_{43} & a_{44}
    \end{pmatrix}

    \begin{pmatrix}
      b_1  \\
      b_2 \\
      b_3 \\
     b_4
    \end{pmatrix}

=

    \begin{pmatrix}
      a_{11} b_1 + a_{12} b_2 + a_{13} b_3 + a_{14} b_4 \\
      a_{21} b_1 + a_{22} b_2 + a_{23} b_3 + a_{24} b_4 \\
      a_{31} b_1 + a_{32} b_2 + a_{33} b_3 + a_{34} b_4 \\
     a_{41} b_1 + a_{42} b_2 + a_{43} b_3 + a_{44} b_4
    \end{pmatrix}
}

なので、

{\displaystyle 
    \begin{pmatrix}
      Tx \\
      Ty \\
      Tz \\
     1
    \end{pmatrix}
}

となります。
このベクトルからxyz成分を取れば、親のワールド座標を取ることができ、ローカル座標を求めることができます。

参考サイト様集

ローカル座標の求め方

answers.unity.com

行列の考え方

learnopengl.com

Unityにおけるベクトルのオーダー

edom18.hateblo.jp

結果

f:id:soramamenatan:20190813173851p:plain

Positionを移動させても、円がズレなくなりました。

今回は以上となります。
次回はノイズを制作していきます。