申し訳ありませんが、これは少しネクロであることは知っていますが、これは将来の読者にとって役立つかもしれないと思います.
私が完全に間違っていない限り、丸め誤差を考慮して正規化するときに角度を保持しない方が実際には望ましいです (特にゲームで四元数を使用して回転を表す場合)。理由を説明しましょう:
回転を表すはずの 2 つのクォータニオンがあり (以降、それらをQ1
と呼びQ2
ます)、丸め誤差のために単位ではなく、それらを乗算したいとします (結果を呼び出します)。Q3
. これも単位四元数にしたい)。t1
が変数であり、 のすべてのコンポーネントと乗算されると、単位四元数Q1
にQ1
なります (つまり、t1
は のユークリッド長で除算されQ1
ますが、実際にはここでは関係ありません。はt2
に対して同じことを行いQ2
ます。正規化後のクォータニオン (つまりQ3 = (t1*Q1)(t2*Q2)
) 次の結果が得られます。
Q3.w = t1*Q1.w*t2*Q2.w - t1*Q1.x*t2*Q2.x - t1*Q1.y*t2*Q2.y - t1*Q1.z*t2*Q2.z
Q3.x = t1*Q1.w*t2*Q2.x + t1*Q1.x*t2*Q2.w + t1*Q1.y*t2*Q2.z - t1*Q1.z*t2*Q2.y
Q3.y = t1*Q1.w*t2*Q2.y - t1*Q1.x*t2*Q2.z + t1*Q1.y*t2*Q2.w + t1*Q1.z*t2*Q2.x
Q3.z = t1*Q1.w*t2*Q2.z + t1*Q1.x*t2*Q2.y - t1*Q1.y*t2*Q2.x + t1*Q1.z*t2*Q2.w
これは次のように書き換えることができます
Q3.w = (t1*t2)*(Q1.w*Q2.w - Q1.x*Q2.x - Q1.y*Q2.y - Q1.z*Q2.z)
Q3.x = (t1*t2)*(Q1.w*Q2.x + Q1.x*Q2.w + Q1.y*Q2.z - Q1.z*Q2.y)
Q3.y = (t1*t2)*(Q1.w*Q2.y - Q1.x*Q2.z + Q1.y*Q2.w + Q1.z*Q2.x)
Q3.z = (t1*t2)*(Q1.w*Q2.z + Q1.x*Q2.y - Q1.y*Q2.x + Q1.z*Q2.w)
つまり、Q3=(t1*Q1)(t2*Q2)=(t1*t2)(Q1*Q2)
. ご覧のとおり、乗算後にこの方法で正規化すると、両方の入力を乗算前に正規化した場合と同じ四元数になります。これは、クォータニオンが単位からどれだけずれても同じ結果が得られるため、すべての計算の後ではなく、ベクトル/メッシュ/ポイントに回転を適用する直前に正規化するだけでよいことを意味します。
ここで、同じ計算を見てみましょうが、クォータニオン単位を作成する角度を維持する方法を使用します (t
変数は、非実数 (別名 xyz) 部分のみを乗算したときにクォータニオン単位を作成します)。
Q3.w = Q1.w*Q2.w - t1*Q1.x*t2*Q2.x - t1*Q1.y*t2*Q2.y - t1*Q1.z*t2*Q2.z
Q3.x = Q1.w*Q2.x + t1*Q1.x*Q2.w + t1*Q1.y*t2*Q2.z - t1*Q1.z*t2*Q2.y
Q3.y = Q1.w*Q2.y - t1*Q1.x*t2*Q2.z + t1*Q1.y*Q2.w + t1*Q1.z*t2*Q2.x
Q3.z = Q1.w*Q2.z + t1*Q1.x*t2*Q2.y - t1*Q1.y*t2*Q2.x + t1*Q1.z*Q2.w
の非実数成分がQ3
共通因子を持たなくなったことに注意してください。これは、この方法で事後操作を正規化すると、正規化してこの方法で事前操作を行ったQ3
場合に得られるものとは異なる四元数になる可能性があることを意味します。Q2
Q1
クォータニオンの正規化は安価な操作ではないため、特に多数の回転を合成する場合は、あまり頻繁に使用する必要がないため、ゲームのようなものには角度を保存しない方法を使用することをお勧めします。同じことが他のクォータニオン操作にも当てはまるかどうかはわかりませんが、おそらくクォータニオンをたくさん乗算することになると考えると、少なくとも私の意見では、角度を保存しない方法を使用することが望ましいです。