私はIKを使ってプログラムに取り組んでいて、最初は些細な問題だと思っていたものに出くわしましたが、それ以来、それを解決するのに苦労しました。
バックグラウンド:
すべてが3D空間にあります。変換を表すために3Dベクトルとクォータニオンを使用しています。
V1と呼ぶ手足があります。V2に回転させたい。
V1とV2の間の角度を取得していました。次に、V1による回転軸がV2と交差します。
次に、軸と角度からクォータニオンを作成します。
次に、手足の現在の方向を取得し、軸角度クォータニオンを掛けます。
これが私の手足に必要なローカルスペースだと思います。
この手足は、他の一連のリンクに接続されています。ワールドスペースを取得するために、ルートに到達するまで、親のローカルスペースと子のローカルスペースを組み合わせてルートまでトラバースします。
これは、回転しているベクトルがX平面とY平面内に含まれている場合、または手足が接続されているボディが変更されていない場合に、うまく機能しているようです。ルートノードの回転など、何かが変更されている場合、最初の反復で、ベクトルは目的のベクトルに非常に近く回転します。その後、それはあちこちで回転し始め、ゴールに到達することはありません。
私はすべての数学を1行ずつ調べましたが、すべて正しいようです。わからないことがあるのか、見過ぎているのかわかりません。私の論理的な音ですか?それとも私は何かに気づいていませんか?どんな助けでも大歓迎です!
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 );
}