Unity
Shader

unity_ObjectToWorldからスケール成分を取り出したい

unity_ObjectToWorldからスケール成分を取り出したい


参考にしました というかそのまま持ってきました

The Matrix and Quaternions FAQ
OpenGLプログラミングメモ 行列:合成行列から拡大縮小成分を抜き出す



Unity5.5からunity_Scaleの中身がfloat(1,1,1,1)になりました。
通常、それはそれで問題ありませんけど、それでもスケールの数値を所得したい!
ということで、unity_ObjectToWorldに含まれているはずのスケール成分を抜き出してみました

変換行列の中身は大体こんな感じ

unityScale =
\begin{bmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & 1 & 0\\
0 & 0 & 0 & 1
\end{bmatrix}
\begin{matrix}
XScale成分(1,0,0),平行移動成分X\\
YScale成分(0,1,0),平行移動成分Y\\
ZScale成分(0,0,1),平行移動成分Z\\
0,0,0,1\\
\end{matrix}

さて参考にしたサイトのままですが、
変換行列の平行移動成分を除いて、各列3要素の
ベクトルの大きさを計算するとスケール成分が取り出せます。

\begin{vmatrix}
A
\end{vmatrix} = \sqrt{A{x}^2+A{y}^2+A{z}^2
}

これをScriptにするとこんな感じになります。

float sX = sqrt(unity_ObjectToWorld[0].x * unity_ObjectToWorld[0].x + unity_ObjectToWorld[0].y * unity_ObjectToWorld[0].y + unity_ObjectToWorld[0].z * unity_ObjectToWorld[0].z);
float sY = sqrt(unity_ObjectToWorld[1].x * unity_ObjectToWorld[1].x + unity_ObjectToWorld[1].y * unity_ObjectToWorld[1].y + unity_ObjectToWorld[1].z * unity_ObjectToWorld[1].z);
float sZ = sqrt(unity_ObjectToWorld[2].x * unity_ObjectToWorld[2].x + unity_ObjectToWorld[2].y * unity_ObjectToWorld[2].y + unity_ObjectToWorld[2].z * unity_ObjectToWorld[2].z);

検証用Shaderコードです。

Shader "Unlit/ScaleSample"
{
    Properties{ }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float mX = sqrt(unity_ObjectToWorld[0].x * unity_ObjectToWorld[0].x + unity_ObjectToWorld[0].y * unity_ObjectToWorld[0].y + unity_ObjectToWorld[0].z * unity_ObjectToWorld[0].z);
                float mY = sqrt(unity_ObjectToWorld[1].x * unity_ObjectToWorld[1].x + unity_ObjectToWorld[1].y * unity_ObjectToWorld[1].y + unity_ObjectToWorld[1].z * unity_ObjectToWorld[1].z);
                float mZ = sqrt(unity_ObjectToWorld[2].x * unity_ObjectToWorld[2].x + unity_ObjectToWorld[2].y * unity_ObjectToWorld[2].y + unity_ObjectToWorld[2].z * unity_ObjectToWorld[2].z);
                float3 matrixDat = float3(mX, mY, mZ);
                return float4(matrixDat, 1);
            }
            ENDCG
        }
    }
}

ということで実行結果です。 スケールを弄ると、色が変化しているのがわかりますね。
sample.png


以下メモ

平行移動行列
T =
\begin{bmatrix}
1 & 0 & 0 & X \\
0 & 1 & 0 & Y \\
0 & 0 & 1 & Z \\
0 & 0 & 0 & 1
\end{bmatrix}

スケール行列
S =
\begin{bmatrix}
x & 0 & 0 & 0 \\
0 & y & 0 & 0 \\
0 & 0 & z & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
回転行列
Rx =
\begin{bmatrix}
1 & 0 & 0 & 0\\
0 & cos\theta & -sin\theta & 0\\
0 & sin\theta & cos\theta & 0\\
0 & 0 & 0 & 1
\end{bmatrix}
Ry =
\begin{bmatrix}
cos\theta & 0 & sin\theta & 0 \\
0 & 1 & 0 & 0\\
-sin\theta & 0 & cos\theta & 0\\
0 & 0 & 0 & 1
\end{bmatrix}
Rz =
\begin{bmatrix}
cos\theta & -sin\theta & 0 & 0\\
sin\theta & cos\theta & 0 & 0\\
0 & 0 & 1 & 0\\
0 & 0 & 0 & 1
\end{bmatrix}

回転行列3軸

M = X・Y・Zと計算するとして展開するとこうなる

M =
\begin{bmatrix}
(cos\theta{y} * cos\theta{z}) & (-cos\theta{y} * -sin\theta{z}) & (-sin\theta{y}) & 0\\
(sin\theta{x} * sin\theta{y} * cos\theta{z} + cos\theta{x} * sin\theta{z}) & (-sin\theta{x} * sin\theta{y} * sin\theta{z} + cos\theta{x} * cos\theta{z}) & (-sin\theta{x} * cos\theta{y}) & 0\\
(-sin\theta{x} * sin\theta{y} * cos\theta{z} + sin\theta{x} * sin\theta{z}) & (cos\theta{x} * sin\theta{y} * sin\theta{z} + sin\theta{x} * cos\theta{z}) & (cos\theta{x} * cos\theta{y}) & 0\\
0 & 0 & 0 & 1
\end{bmatrix}