2011-09-26 77 views
1

我正在與IK一起開發一個程序,並遇到了我最初認爲的問題,這是一個微不足道的問題,但自那時起就無法解決問題。向量旋轉問題

背景:

一切都在3d空間中。 我使用三維矢量和四元數來表示變換。

我有一個肢體,我們會打電話給V1。 我想旋轉到V2。

我得到了V1和V2之間的角度。 然後V1的旋轉軸與V2交叉。

然後從軸和角度製作一個四元數。

然後我採取四肢目前的方向,並乘以軸角四元數。

這我相信是我期望的肢體局部空間。

該肢體附着於一系列其他鏈接。爲了獲得世界空間,我將根據父母本地空間與孩子的本地空間結合起來,直到達到根。

如果我旋轉的矢量包含在X和Y平面內,或者肢體所連接的身體沒有被修改,這似乎工作得很好。如果有任何修改,例如旋轉根節點,那麼在第一次迭代時,矢量將非常接近所需的矢量。在那之後,儘管它將開始在所有地方旋轉,從未達到目標。

我已經通過所有的數學線逐行,它似乎都是正確的。我不確定是否有某些我不知道的或者僅僅是過度看的東西。我的邏輯聲音是?或者我不知道什麼?任何幫助是極大的讚賞!

Quaternion::Quaternion(const Vector& axis, const float angle) 
{ 
float sin_half_angle = sinf(angle/2); 

v.set_x(axis.get_x() * sin_half_angle); 
v.set_y(axis.get_y() * sin_half_angle); 
v.set_z(axis.get_z() * sin_half_angle); 

w = cosf(angle/2); 
} 

Quaternion Quaternion::operator* (const Quaternion& quat) const 
{ 

Quaternion result; 

Vector v1(this->v); 
Vector v2(quat.v ); 

float s1 = this->w; 
float s2 = quat.w; 

result.w = s1 * s2 - v1.Dot(v2); 
result.v = v2 * s1 + v1 * s2 + v1.Cross(v2); 

result.Normalize(); 

return result; 
} 

Vector Quaternion::operator* (const Vector& vec) const 
{ 

Quaternion quat_vec(vec.get_x(), vec.get_y(), vec.get_z(), 0.0f); 
Quaternion rotation(*this); 

Quaternion rotated_vec = rotation * (quat_vec * rotation.Conjugate()); 

return rotated_vec.v; 
} 

Quaternion Quaternion::Conjugate() 
{ 
    Quaternion result(*this); 
    result.v = result.v * -1.0f; 
    return result; 
} 

Transform Transform::operator*(const Transform tran) 
{ 
return Transform(mOrient * transform.getOrient(), mTrans + (mOrient * tran.getTrans()); 
} 

Transform Joint::GetWorldSpace() 
{  
Transform world = local_space; 

Joint* par = GetParent(); 

while (par) 
{ 
    world = par->GetLocalSpace() * world; 
    par = par->GetParent(); 
} 

return world; 
} 

void RotLimb() 
{ 
Vector end_effector_worldspace_pos = end_effector->GetWorldSpace().get_Translation(); 
Vector parent_worldspace_pos  = parent->GetWorldSpace().get_Translation(); 

Vector parent_To_end_effector  = (end_effector_worldspace_pos - parent_worldspace_pos).Normalize(); 
Vector parent_To_goal    = (goal_pos     - parent_worldspace_pos).Normalize(); 

float dot = parent_To_end_effector.Dot(parent_To_goal); 

Vector rot_axis(0.0f,0.0f,1.0f); 
float angle = 0.0f; 

if (1.0f - fabs(dot) > EPSILON) 
{ 
    //angle = parent_To_end_effector.Angle(parent_To_goal);    
    rot_axis = parent_To_end_effector.Cross(parent_To_goal).Normalize(); 

    parent->RotateJoint(rot_axis, acos(dot)); 
} 
} 

void Joint::Rotate(const Vector& axis, const float rotation) 
{ 
    mLocalSpace = mlocalSpace * Quaternion(axis, rotation); 
} 
+2

你確定它不是一個數值精度問題嗎?我不知道你正在使用哪種迭代算法,但它可能不會在出現數字錯誤時收斂。也許你需要使最低可接受的誤差更高,或考慮使用另一種數字數據類型 – sinelaw

+0

我同意sinelaw。在某些時候,您的算法必須說「足夠接近」,並將值分配爲等於目標值。 –

+1

你能提供公式還是(僞)代碼?沒有更多細節,很難猜出出了什麼問題。我能給你的唯一的事情就是2d空間中的旋轉是可交換的,也許你在某處混淆了乘法的順序? – 2011-09-26 06:21:33

回答

1

當你在一個評論,該軸應在關節局部座標系來計算寫你是正確的:如果這個問題正在發生,因爲我我想知道

進行計算以獲得關節的世界空間中的軸和角度,然後將其應用於本地空間。

來自全球框架的聯合框架軸的旋轉將是這個樣子:

rot_axis = parent->GetWorldSpace().Inverse().get_Rotation() * rot_axis 

也有其他的問題進行調試,但它是唯一合乎邏輯的錯誤,我可以看到您發佈的代碼。

+0

在寫完評論後,我回到家並測試了這個問題。果然,這就是問題所在,我只是簡單地添加了代碼將軸轉換爲關節的局部空間......一切都很完美。有趣的事情,我們有時忽略...我忘了這個職位,直到現在看到這個答案。這是我所做的事。我感謝您花時間回覆。 – user964426