Проблема вращения вектора - PullRequest
1 голос
/ 26 сентября 2011

Я работаю над программой с IK и столкнулся с тем, что, на первый взгляд, было тривиальной проблемой, но с тех пор у меня возникли проблемы с ее решением.

Справочная информация:

Все в трехмерном пространстве. Я использую трехмерные векторы и кватернионы для представления преобразований.

У меня есть конечность, которую мы будем называть 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 );
}

1 Ответ

1 голос
/ 27 сентября 2011

Вы правы, когда пишете в комментарии, что ось должна быть вычислена в локальной системе координат соединения:

Мне интересно, возникает ли эта проблема, потому что я делаю вычисления, чтобы получить ось и угол в мировом пространстве для соединения, но затем применяю его к локальному пространству.

Вращение оси от мировой рамы к соединительной раме будет выглядеть примерно так:

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

Могут быть и другие проблемы для отладки, но это единственная логическая ошибка, которую я вижу в опубликованном вами коде.

...