オブジェクトのScale値を取得する関数はありますが(「ObjectScale」ノード)、オブジェクトのRotation値を取得する関数はなかったので、自作してみました。

結果動画
今回自作したMF_ObjectRotationのノードの返り値である float3(x=Roll, y=Pitch, z=Yaw) を、「DebugFloat3Values」ノードで可視化してみます。

↓のGIF動画のように、TransformのRotationに入力した値(= Cubeにかけた回転値)と同じ値が、オブジェクト表面に表示されています。
No |
GIF |
1 |
 |
2 |
 |
全体図
こちらが今回自作したMF_ObjectRotationノードの全体図です。

コアの部分はCustomノードで、HLSLで書いています。
解説
最初に、オブジェクトにかかっているTransformから、カスタム座標系を算出します。

カスタム座標系からオイラー角を算出する式を構築
次に、カスタム座標系からオイラー角(Roll, Pitch, Yaw)を算出する式を構築します。
ここが今回の本丸部分になります。
まず、回転行列Rの各要素を次のように表すとします。
R=m00m10m20m01m11m21m02m12m22
また、各軸が[Forward,Right,Up]のカスタム座標系は、行列の形では次のように表せます。
R=Forward.xForward.yForward.zRight.xRight.yRight.zUp.xUp.yUp.z
Roll,Pitch,Yawそれぞれの回転行列は次のようになります。
RRoll=1000cosθRollsinθRoll0−sinθRollcosθRoll
RPitch=cosθPitch0−sinθPitch010sinθPitch0cosθPitch
RYaw=cosθYawsinθYaw0−sinθYawcosθYaw0001
オイラー角では回転順が最終結果に影響します。
UnrealEngineではRoll,Pitch,Yawの順で回転がかけられますが、これは
Yaw→Pitch→Roll
のように左からかけるので、合成後の回転行列は
RYawRPitchRRoll
で求まります。
RYaw,Pitch,Roll=cosθPitchcosθYawcosθPitchsinθYaw−sinθPitchsinθRollsinθPitchcosθYaw−cosθRollsinθYawsinθRollsinθPitchsinθYaw+cosθRollcosθYawsinθRollcosθPitchcosθRollsinθPitchcosθYaw+sinθRollsinθYawcosθRollsinθPitchsinθYaw−sinθRollcosθYawcosθRollcosθPitch
上記より、
m20=Forward.z=−sinθPitch
★θPitch=arcsin(−Forward.z)
となり、まずPitchが求まります。
続いて、RollとUpを求めますが、cosθPitch=0 のときと、cosθPitch=0 のときで場合分けします。
まず、cosθPitch=0 のとき
m21=Right.z=sinθRollcosθPitchsinθRoll=cosθPitchRight.z
m22=Up.z=cosθRollcosθPitchcosθRoll=cosθPitchUp.z
より、
cosθRollsinθRoll=tanθRoll=Up.zRight.z
★θRoll=arctan(Up.zRight.z)
で、Rollが求まります。
また、
m10=Forward.y=cosθPitchsinθYawsinθYaw=cosθPitchForward.y
m00=Forward.x=cosθPitchcosθYawcosθYaw=cosθPitchForward.x
より、
cosθYawsinθYaw=tanθYaw=Forward.xForward.y
★θYaw=arctan(Forward.xForward.y)
で、Yawが求まります。
次に、cosθPitch=0 のとき
このときはジンバルロックが発生してForward軸とUp軸の回転が同軸での回転となります。
ここで、θRoll=0 と仮定(すなわち、sinθRoll=0、cosθRoll=1)すると、回転行列は、
RYaw,Pitch,Roll=00−sinθPitch−sinθYawcosθYaw0sinθPitchcosθYawsinθPitchsinθYaw0
となります。
ここから、
tanθYaw=cosθYawsinθYaw=−m11m01=−Right.yRight.x
★θYaw=arctan(−Right.yRight.x)
で、Yawが求まります。
以上より、
θRoll={arctan(Up.zRight.z)0(cosθPitch=0)(cosθPitch=0)θPitch=arcsin(−Forward.z)θYaw={arctan(Forward.xForward.y)arctan(−Right.yRight.x)(cosθPitch=0)(cosθPitch=0)
CustomノードでHLSLの記述
上記までで求めたカスタム座標系とオイラー角算出の式を使って、オイラー角を返すCustomノードとしてHLSLコードを起こします。

Customノードの引数は、カスタム座標系のForwardベクトル、Rightベクトル、Upベクトルの3つです。
それら引数のベクトルをもとに、まずPitchから求めます。
RollとYawを求めるときには、ジンバルロックを考慮して、if (cos(pitchRad) != 0.0f)
で場合分けします。
最終的には、float3(x=roll, y=pitch, z=yaw)
として値を返しています。
参考ページ
回転行列⇔オイラー角の相互変換について、こちらのページを大いに参考にさせていただきました。
https://qiita.com/aa_debdeb/items/3d02e28fb9ebfa357eaf
Discussion