Home > Back-end >  rotating bone with quaternion issue
rotating bone with quaternion issue

Time:05-28

I need to rotate bones of skeleton, i have already the quaterinion corresponding for each joints; and i am confused when it comes on rotating.

Skeleton to move is my opengl scene i need to move.

My problem is that i can't rotate the joint; Can anyone Help

Bellow is my code

//i evaluate each joint to get the translation and rotation.

 void Node::EvaluatePoi(std::vector<POI> pois, const Vector &par_pos,
                           const Quaternion &par_rot, Vector Node::*world_pos,std::vector<Arti> joints)
    {  Vector poi=this->PoiVec ;
    
            Quaternion rot;
            if (pois.empty()){
                this->*world_pos= this->rest_position ;//OFFSET
    
                rot= this-> rest_rotation ;//identity
    
            }else{
            if(this->name=="Hips")
            {
             this->*world_pos = eval_instant_positionPOI(poi);
         
               rot= this-> rest_rotation ;// do not rotate
            }else if(this->name=="LeftUpLeg")
            {
                this->*world_pos = this->rest_position;// set to OFFSET
              
                  rot= this-> rest_rotation ;// do not rotate
            }else if(this->name=="RightUpLeg")
            {
                this->*world_pos = this->rest_position;
                  rot= this-> rest_rotation ;
            }
    
            else
    
            {
             this->*world_pos= this->rest_position; 
     
                 rot= eval_instant_rotationPOI(joints);
            }
            }
    
            (this->*world_pos).rotate(rot);
            this->*world_pos  = par_pos;
           
            //rot = par_rot * rot;
            

            // draw joint's subhierarchy
            for (int i = 0; i < n_children; i  )
                child[i]->EvaluatePoi(pois, this->*world_pos, rot, world_pos,joints);
    }

//here i get the value of Quaternion for the joint corresponding

Quaternion Node::eval_instant_rotationPOI( std::vector<Arti> joints)
{

    Quaternion roto;//= new Quaternion();
    Quaternion sample;

 double t= 0.02;
 Vector v;
 Vector Euler(0,0,0);;


string x =this->name;
if(x== "Head"){
    Euler=GetEulers(joints,JOINT_HEAD);
}else if(x== "Neck"){
     Euler=GetEulers(joints,JOINT_NECK);
}
else if(x== "LeftUpArm"){
     Euler=GetEulers(joints,JOINT_LEFT_SHOULDER);
}
else if(x== "RightUpArm"){
     Euler=GetEulers(joints,JOINT_RIGHT_SHOULDER);
}
else if(x== "LeftLowArm"){
     Euler=GetEulers(joints,JOINT_LEFT_ELBOW);
}
else if(x== "LeftHand"){
     Euler=GetEulers(joints,JOINT_LEFT_HAND);
}
else if(x== "RightLowArm"){
     Euler=GetEulers(joints,JOINT_RIGHT_ELBOW);
}
else if(x== "RightHand"){
     Euler=GetEulers(joints,JOINT_RIGHT_HAND);
}
else if(x== "Hips"){
     Euler=GetEulers(joints,JOINT_TORSO);
}
else if(x== "LeftUpLeg"){
     Euler=GetEulers(joints,JOINT_LEFT_HIP);
}
else if(x== "RightUpLeg"){
     Euler=GetEulers(joints,JOINT_RIGHT_HIP);
}
else if(x== "LeftLowLeg"){
     Euler=GetEulers(joints,JOINT_LEFT_KNEE);
}
else if(x== "LeftFoot"){
     Euler=GetEulers(joints,JOINT_LEFT_FOOT);
}
else if(x== "RightLowLeg"){
     Euler=GetEulers(joints,JOINT_RIGHT_KNEE);
}
else if(x== "RightFoot"){
     Euler=GetEulers(joints,JOINT_RIGHT_FOOT);
}
   

Quaternion qx(x_vector, (Euler.x ));
Quaternion qy(y_vector, (Euler.y ));
Quaternion qz(z_vector, (Euler.z ));
  sample = qz  * qy * qx;
   
roto= slerp(qTemp, sample, t);
qTemp=roto;

 return roto ;
}

/*here i multiply the joint and its parent to get the Euler Angle ; is it necessary to convert to Euler Angle?/

 Vector Node::GetEulers(std::vector<Arti> joints, const int idx) {
           // Get the quaternion of its parent.
           Quaternion q_parent;
            Quaternion q_current;
           if (idx == JOINT_TORSO) {
               q_parent.identity();
           }
           /////
    
           {
               q_parent = Quaternion(joints[parent_joint_map[idx]].quat.x,
                                      joints[parent_joint_map[idx]].quat.y,
                                      joints[parent_joint_map[idx]].quat.z,
                                      joints[parent_joint_map[idx]].quat.w);
           }
    
           // Get the quaternion of the joint.
            q_current =  Quaternion(joints[idx].quat.x, joints[idx].quat.y,
                                   joints[idx].quat.z, joints[idx].quat.w);
    
           // Calculate the relative quaternion.
          Quaternion q_delta = quat_left_multiply(q_current , quat_inverse(q_parent));
    
             Vector angle = euler_from_quat(q_delta);
           // cout<<this->name<<" "<<angle<<"   ";
    
           return angle;
       }

    Quaternion quat_left_multiply(Quaternion l, Quaternion r) {
               Quaternion q = {r.w * l.x   r.x * l.w   r.y * l.z - r.z * l.y,
                   r.w * l.y   r.y * l.w   r.z * l.x - r.x * l.z,
                   r.w * l.z   r.z * l.w   r.x * l.y - r.y * l.x,
                   r.w * l.w - r.x * l.x - r.y * l.y - r.z * l.z};
               return q;
           }

Vector& Vector::rotate(const Quaternion& q)
{
    Quaternion p(x, y, z, 0.0f);
    Quaternion qc(q);
    qc.conjugate();
    Quaternion pp(q * p * qc);

    x = pp.x;
    y = pp.y;
    z = pp.z;

    return *this;
}

CodePudding user response:

Rotating a quaternion is actually multiplying a quaternion by another. Given the quaternion qA representing the current rotation of an object and qB the quaternion representing the amount of rotation to apply (to add) to this object, the resulting new rotation of this object is computed as follow (pseudocode):

qA = qA * qB;

Alternatively, you can apply (add) this rotation in what is called "object" or "local" transformation space by swapping operands:

qA = qB * qA

Each joint should hold (usualy as class member) a quaternion representing its current rotation in local space. This is probably what you already done. If you want to apply a rotation to that joint, then you simply need multiply the joint quaternion, by another quaternion representing the amount of rotation to apply. A quaterion rotation method can be like this (pseudocode):

Joint::Rotate(const quaterion& amount, bool local) 
{
   if(local) {
     this->rotation = amount * this->rotation;
   } else {
     this->rotation = this->rotation * amount;
   }

   this->rotation.normalize();
}

That is all you need for the rotation part, nothing else. After that, you will need to convert the joint quaternion to a rotation matrix, so to be combined with the other joint transformations (translation, scale, whatever). Here is one implementation of the quaternion to rotation matrix conversion (pseudocode):

Matrix3 QuaternionToMatrix(const quaternion& q) 
{
    float x2 = q.x   q.x;
    float y2 = q.y   q.y;
    float z2 = q.z   q.z;
    float xx = q.x * x2;
    float xy = q.x * y2;
    float xz = q.x * z2;
    float yy = q.y * y2;
    float yz = q.y * z2;
    float zz = q.z * z2;
    float wx = q.w * x2;
    float wy = q.w * y2;
    float wz = q.w * z2;

    Matrix3 m; //< 3x3 matrix

    m[0] = (1.0f - (yy   zz));
    m[1] = (xy - wz);
    m[2] = (xz   wy);
    m[3] = (xy   wz);
    m[4] = (1.0f - (xx   zz));
    m[5] = (yz - wx);
    m[6] = (xz - wy);
    m[7] = (yz   wx);
    m[8] = (1.0f - (xx   yy));

    return m;
}

What you may finally need is to input rotation using Euler angles instead of quaternion values. Indeed, Euler angles are easier to handle and understand when it come to apply a rotation in a human point of view. In this case, you'll need to convert the input Euler angles to a quaternion. Here is one possible implementation of Euler angle to quaternion conversion:

Quaternion EulerToQuaternion(float x, float y, float z) 
{
    float sx = sinf(x * -0.5f);
    float cx = cosf(x * -0.5f);
    float sy = sinf(y * -0.5f);
    float cy = cosf(y * -0.5f);
    float sz = sinf(z * -0.5f);
    float cz = cosf(z * -0.5f);

    Quaternion q;

    q.x = sx * cy * cz   cx * sy * sz;
    q.y = cx * sy * cz - sx * cy * sz;
    q.z = cx * cy * sz   sx * sy * cz;
    q.w = cx * cy * cz - sx * sy * sz;

    return q;
}
  • Related