我正在与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);
}
你确定它不是一个数值精度问题吗?我不知道你正在使用哪种迭代算法,但它可能不会在出现数字错误时收敛。也许你需要使最低可接受的误差更高,或考虑使用另一种数字数据类型 – sinelaw
我同意sinelaw。在某些时候,您的算法必须说“足够接近”,并将值分配为等于目标值。 –
你能提供公式还是(伪)代码?没有更多细节,很难猜出出了什么问题。我能给你的唯一的事情就是2d空间中的旋转是可交换的,也许你在某处混淆了乘法的顺序? – 2011-09-26 06:21:33