2020年12月10日木曜日

UnityObjectToViewPos関数は右手系用?

ややこしいUnityの座標系の確認方法」シリーズ.UnityObjectToViewPos関数は右手系用なのか左手系用なのか? マニュアルやブログの解説で読んでもピンとこないのでどういうことなのか? これも実験で確かめてみる. この図のとおり,カメラとオブジェクトを配置.

この状況ならオブジェクト座標(右図)でキューブの中央は\([0, 0, 0, 1]^T\)で,その点はカメラ座標(左図)でみると\([0, 10, 0, 1]^T\)になる. この変換はオブジェクト座標を\([x_o, y_o, z_o, w_o]^T\),カメラ座標を\([x_c, y_c, z_c, w_c]^T\)とすると次式で表すことができる. どちらの座標系も左手系であることは図を見ると明らか.

\begin{equation} \left[ \begin{array}{c} x_c\\ y_c\\ z_c\\ w_c \end{array} \right] = \left[ \begin{array}{cccc} 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ -1 & 0 & 0 & 10 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{c} x_o\\ y_o\\ z_o\\ w_o \end{array} \right] \end{equation}

UnityObjectToViewPos関数がこの演算を単にやってるとすると, 次のプログラムのxyz_oの値を色々変えたときにどうなるのか? xyz_oかxyz_cのどちらか,もしくは両方が右手系扱い(\(z\)軸だけ符号反転)なのだとしたら,どうなるのか? 予想してみた.結果は最後.

fixed4 frag (v2f i) : SV_Target
{
    float3 xyz_o = float3(1, 0, 0);
    float3 xyz_c = UnityObjectToViewPos(xyz_o);

    return float4(xyz_c, 1);
}
\[ \def\rd#1{{\color{red} 赤}&}%なぜか&がいる \def\gn#1{{\color{green} 緑}&}%なぜか&がいる \def\br#1{{\color{blue} 青}&}%なぜか&がいる \]

左手系→左手系

\begin{equation} \left[ \begin{array}{c} x_c\\ y_c\\ z_c\\ w_c \end{array} \right] = \left[ \begin{array}{cccc} 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ -1 & 0 & 0 & 10 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{c} x_o\\ y_o\\ z_o\\ w_o \end{array} \right] \end{equation} \[ \begin{array}{crrr} \hline \hline x_o & 1 & 0 & 0& -1& 0& 0\\ y_o & 0 & 1 & 0& 0& -1& 0\\ z_o & 0 & 0 & 1& 0& 0& -1\\ \hline x_c & 0 & 0 & 1& 0& 0& -1\\ y_c & 0 & 1 & 0& 0& -1& 0\\ z_c & 9 & 0 & 0& 11& 0& 0\\ \hline 色 & \br& \gn& \rd& \br& 黒& 黒\\ \end{array} \]

右手系→右手系

\begin{equation} \left[ \begin{array}{c} x_c\\ y_c\\ z_c\\ w_c \end{array} \right] = \left[ \begin{array}{cccc} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{cccc} 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ -1 & 0 & 0 & 10 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{cccc} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{c} x_o\\ y_o\\ z_o\\ w_o \end{array} \right] \end{equation} \begin{equation} = \left[ \begin{array}{cccc} 0 & 0 & -1 & 0 \\ 0 & 1 & 0 & 0 \\ 1 & 0 & 0 & -10 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{c} x_o\\ y_o\\ z_o\\ w_o \end{array} \right] \end{equation} \[ \begin{array}{crrr} \hline \hline x_o & 1 & 0 & 0& -1& 0& 0\\ y_o & 0 & 1 & 0& 0& -1& 0\\ z_o & 0 & 0 & 1& 0& 0& -1\\ \hline x_c & 0 & 0 & -1& 0& 0& 1\\ y_c & 0 & 1 & 0& 0& -1& 0\\ z_c & -9 & 0 & 0& -11& 0& 0\\ \hline 色 & 黒& \gn& 黒& 黒& 黒& \rd \\ \end{array} \]

右手系→左手系

\begin{equation} \left[ \begin{array}{c} x_c\\ y_c\\ z_c\\ w_c \end{array} \right] = \left[ \begin{array}{cccc} 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ -1 & 0 & 0 & 10 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{cccc} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{c} x_o\\ y_o\\ z_o\\ w_o \end{array} \right] \end{equation} \begin{equation} = \left[ \begin{array}{cccc} 0 & 0 & -1 & 0 \\ 0 & 1 & 0 & 0 \\ -1 & 0 & 0 & -10 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{c} x_o\\ y_o\\ z_o\\ w_o \end{array} \right] \end{equation} \[ \begin{array}{crrr} \hline \hline x_o & 1 & 0 & 0& -1& 0& 0\\ y_o & 0 & 1 & 0& 0& -1& 0\\ z_o & 0 & 0 & 1& 0& 0& -1\\ \hline x_c & 0 & 0 & -1& 0& 0& -1\\ y_c & 0 & 1 & 0& 0& -1& 0\\ z_c & -11& 0 & 0& -11& 0& 0\\ \hline 色 & 黒& \gn& 黒& 黒& 黒& 黒\\ \end{array} \]

左手系→右手系

\begin{equation} \left[ \begin{array}{c} x_c\\ y_c\\ z_c\\ w_c \end{array} \right] = \left[ \begin{array}{cccc} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{cccc} 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ -1 & 0 & 0 & 10 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{c} x_o\\ y_o\\ z_o\\ w_o \end{array} \right] \end{equation} \begin{equation} = \left[ \begin{array}{cccc} 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 1 & 0 & 0 & -10 \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \left[ \begin{array}{c} x_o\\ y_o\\ z_o\\ w_o \end{array} \right] \end{equation} \[ \begin{array}{crrr} \hline \hline x_o & 1 & 0 & 0& -1& 0& 0\\ y_o & 0 & 1 & 0& 0& -1& 0\\ z_o & 0 & 0 & 1& 0& 0& -1\\ \hline x_c & 0 & 0 & 1& 0& 0& -1\\ y_c & 0 & 1 & 0& 0& -1& 0\\ z_c & -9 & 0 & 0& -10& 0& 0\\ \hline 色 & 黒& \gn& \rd& 黒& 黒& 黒\\ \end{array} \]

結果

結果は「左手系→右手系」と完全に一致した. これが分かった後,その他色々な値を入れてみたけど,やっぱりこれで正しい. つまり

UnityObjectToViewPos関数は引数はUnityと同じ左手系の座標をとるけど,出力は右手系のカメラとして計算している.

つまりめちゃくちゃややこしい.少なくともシェーダ内のこの関数はなぜかカメラ座標系だけ右手系になるみたい. 加えて,同じ右手系でもx軸が右,y軸が下,z軸が前の右手系1と,x軸が右,y軸が上,z軸が後の右手系2では結果は違う. その時は,右手系1から右手系2への変換を考えて更に変換すればいい.