我正在制作一个有IK的程序,并且遇到了我最初认为是一个微不足道的问题,但后来遇到了解决问题。
背景:
一切都在3d空间。 我正在使用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 );
}
答案 0 :(得分:1)
当你在评论中写下应该在关节的局部坐标系中计算轴时,你是正确的:
我想知道这个问题是否正在发生,因为我正在进行计算以获得关节的世界空间中的轴和角度,然后将其应用于局部空间。
轴从世界框架到关节框架的旋转看起来像这样:
rot_axis = parent->GetWorldSpace().Inverse().get_Rotation() * rot_axis
可能还有其他问题需要调试,但这是我在您发布的代码中看到的唯一逻辑错误。