有幾件事情可能正在發生。你沒有提到重新規範化該四元數。如果你不這樣做,肯定會發生壞事。您也不會說在將三角形四元數組件添加到原始四元數之前,它們已經通過了dt
的時間量。如果角速度是以弧度/秒爲單位的,但你只是向前走幾分之一秒,那麼你會走得太遠。然而,即便如此,由於您正在經歷一段時間,試圖假裝它無限小,奇怪的事情將會發生,特別是如果您的時間步或角速度很大。
物理引擎ODE提供了從角速度更新物體旋轉的選項,就好像它正在採取無限小步驟或使用有限大小的步驟進行更新。有限步驟更精確,但涉及一些觸發。功能等等有點慢。可以看到相關的ODE源代碼here, lines 300-321,代碼查找delta-quaternion here, line 310。
float wMag = sqrt(wx*wx + wy*wy + wz*wz);
float theta = 0.5f*wMag*dt;
q[0] = cos(theta); // Scalar component
float s = sinc(theta)*0.5f*dt;
q[1] = wx * s;
q[2] = wy * s;
q[3] = wz * s;
其中sinc(x)
是:
if (fabs(x) < 1.0e-4) return (1.0) - x*x*(0.166666666666666666667);
else return sin(x)/x;
這可以讓你避免除以零的問題,仍然是非常精確的。
然後,將四元數q
預乘到現有的身體方向的四元數表示上。然後,重新正常化。
編輯 - 當這個公式來源於:
考慮初始四元數q0
和最終四元q1
與角速度w
旋轉爲dt
量的時間之後產生的。我們在這裏所做的就是將角速度矢量改變成四元數,然後用四元數旋轉第一個方向。四元數和角速度都是軸角表示的變化。 正文圍繞單位軸[x,y,z]
圍繞theta
的標準方向旋轉將具有以下四元數的方向表示:q0 = [cos(theta/2) sin(theta/2)x sin(theta/2)y sin(theta/2)z]
。 身體是旋轉theta/s
圍繞單位軸[x,y,z]
將有角速度w=[theta*x theta*y theta*z]
。因此,爲了決定在dt
秒內將發生多少旋轉,我們首先提取角速度的大小:theta/s = sqrt(w[0]^2 + w[1]^2 + w[2]^2)
。然後我們找到實際的角度乘以dt
(爲方便起見,同時除以2,將其轉換爲四元數)。由於我們需要對軸線[x y z]
進行歸一化,因此我們也除以theta
。這就是sinc(theta)
部分的來源。 (因爲theta
有一個額外的0.5*dt
從它的規模,我們乘以返回)。當x
很小時,sinc(x)
函數只是使用函數的泰勒級數近似,因爲它在數值上是穩定的,而且更準確。使用這個方便的功能的能力是爲什麼我們不僅僅是除以實際量值wMag
。旋轉速度不快的物體將具有非常小的角速度。由於我們預計這很常見,我們需要一個穩定的解決方案。我們最終得到的是一個四元數,表示旋轉的單步時間步dt
。
你說你沒有得到預期的結果。什麼似乎出錯? – JCooper 2012-01-13 20:51:55
我正在使用模型進行跟蹤,並且它不穩定 – 2012-01-16 07:46:21
「w」向量是否已經乘以「delta time」?只有「增量時間」很小時,該等式才能正常工作。 – minorlogic 2014-05-21 08:48:39