【UnityShader】ロドリゲスの回転公式 【1】#81
前回の成果
回転行列を理解した
今回やること
前回の回転行列をもっと簡単に解きます。
事前準備
Scene上にCubeを配置します。
Cubeに今回制作したマテリアルをアタッチします。
自分は回転を見やすくするためにUnityのデフォルトのDafault-Checker-GrayをTextureにアタッチしています。
ソースコード
Shader "Unlit/RodriguesRotation" { Properties { _MainTex ("Texture", 2D) = "white" {} _Axis ("Axis", Vector) = (0, 0, 0, 0) _Theta ("Theta", float) = 0 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; fixed4 _Axis; float _Theta; fixed3 rotate(fixed3 pos, fixed3 axis, float theta) { fixed3 axisN = normalize(axis); if (length(axisN) < 0.001) { return pos; } half radTheta = radians(theta); fixed sinTheta = sin(radTheta); fixed cosTheta = cos(radTheta); fixed a = 1.0 - cosTheta; fixed3x3 m = fixed3x3 ( axisN.x * axisN.x * a + cosTheta, axisN.y * axisN.x * a + axisN.z * sinTheta, axisN.z * axisN.x * a - axisN.y * sinTheta, axisN.x * axisN.y * a - axisN.z * sinTheta, axisN.y * axisN.y * a + cosTheta, axisN.z * axisN.y * a + axisN.x * sinTheta, axisN.x * axisN.z * a + axisN.y * sinTheta, axisN.y * axisN.z * a - axisN.x * sinTheta, axisN.z * axisN.z * a + cosTheta ); return mul(m, pos); } v2f vert (appdata v) { v2f o; v.vertex.xyz = rotate(v.vertex.xyz, _Axis.xyz, _Theta); o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); return col; } ENDCG } } }
前回の回転行列とShaderの中身は大きく変わっていません。
変化させているのは、回転用の関数であるrotateになります。
回転行列の比較
前回のものも今回のものも、結果としてはオブジェクトを回転させるものです。
前回の回転関数
float4 rotate3D(float4 pos) { float radX = radians(_ThetaX); float radY = radians(_ThetaY); float radZ = radians(_ThetaZ); float sinX = sin(radX); float cosX = cos(radX); float4x4 rotX = float4x4( float4(1, 0, 0, 0), float4(0, cosX, sinX, 0), float4(0, -sinX, cosX, 0), float4(0, 0, 0, 1) ); float sinY = sin(radY); float cosY = cos(radY); float4x4 rotY = float4x4( float4(cosY, 0, -sinY, 0), float4(0, 1, 0, 0), float4(sinY, 0, cosY, 0), float4(0, 0, 0, 1) ); float sinZ = sin(radZ); float cosZ = cos(radZ); float4x4 rotZ = float4x4( float4(cosZ, sinZ, 0, 0), float4(-sinZ, cosZ, 0, 0), float4(0, 0, 1, 0), float4(0, 0, 0, 1) ); pos = mul(pos, rotX); pos = mul(pos, rotY); pos = mul(pos, rotZ); return pos; }
今回の回転関数
fixed3 rotate(fixed3 pos, fixed3 axis, float theta) { fixed3 axisN = normalize(axis); if (length(axisN) < 0.001) { return pos; } half radTheta = radians(theta); fixed sinTheta = sin(radTheta); fixed cosTheta = cos(radTheta); fixed a = 1.0 - cosTheta; fixed3x3 m = fixed3x3 ( axisN.x * axisN.x * a + cosTheta, axisN.y * axisN.x * a + axisN.z * sinTheta, axisN.z * axisN.x * a - axisN.y * sinTheta, axisN.x * axisN.y * a - axisN.z * sinTheta, axisN.y * axisN.y * a + cosTheta, axisN.z * axisN.y * a + axisN.x * sinTheta, axisN.x * axisN.z * a + axisN.y * sinTheta, axisN.y * axisN.z * a - axisN.x * sinTheta, axisN.z * axisN.z * a + cosTheta ); return mul(m, pos); }
比較してみると、前回の回転行列は各軸に対して毎回行列の計算をしており少し冗長に感じます。
それに比べ、今回のものは1回で行列の計算を済ませています。
ロドリゲスの回転公式
今回のShaderでは、ロドリゲスの回転公式と言われるものを使用しています。
説明は以下になります。
ベクトル空間において、与えられた回転軸に対して回転を行うための効率的なアルゴリズムを指す。
そして、式は以下になります。
位置ベクトルを角だけ回転させる回転行列をとする。
そうすると、回転後の位置ベクトルは
となる。
直交座標系において、回転軸方向の単位ベクトルをとする。
ロドリゲスのの回転公式の表現行列:より引用
この式をソースコードに起こしたものが今回の回転回数となります。
なぜこの式で求めることが出来るのかを自分なりに理解したので、解説していきます。
ロドリゲスの回転公式のベクトル表現
式が長いので混乱しやすいですが、今回求めたいものは
になります。
は以下の式で求めることができます。
まずはを求める式をひとつずつ理解していきます。
を求める
まずはを分解します。
ベクトルは垂直成分と平行成分の和に置き換えることができます。
ですので、以下の式で表すことができます。
を求める
平行成分であるを置き換えます。
単位ベクトルと内積を取ると、単位ベクトルの方向の値が取れる性質があります。
原理までは割愛しますが、詳しくはこちらの画像と画像のサイト様が分かりやすかったです。
単位ベクトルと内積
この性質を利用すると、は以下で表すことができます。
を求める
垂直成分のについても置き換えます。
まず、をベクトルの引き算を用いて2つのベクトルに分解します。
ベクトルの引き算
ベクトルの足し算・引き算:より引用
すると、以下のように表すことができます。
は、は平行成分で求めたとおりと置き換えることができます。
ですので、最終的には以下で表すことができます。
を求める
の平行成分であると垂直成分であるに垂直なベクトルである、を求めます。
はとの外積から求めることが出来るので、
となります。
そして、はで表せると垂直成分を求める時に出したので以下となります。
とは同じ向きですので、外積を求めると0になります。
ですので、最終的に以下となります。
を求める
の垂直成分であるを求めます。
点,,,は同じ円周上の点ですので、2次元の回転が計算に利用できます。
そして、は、はに置き換えられるので以下となります。
を求める
いよいよ最後です。
は以下で表すことができます。
そして、とは以下で表せます。
ですので、求めたかったは以下で表せます。
以上でロドリゲスの回転公式のベクトル表現の解説は終わります。
しかし、これを行列で表現する必要があります。
今回は以上となります。
ここまでご視聴ありがとうございました。