2011-09-26 33 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