跟随另一个旋转的物体

时间:2014-10-18 14:23:37

标签: c++ matrix rotation directx directx-11

我有三个对象:marshalsergeantsoldier。所有这些都是Human类型:

class Human{
public: //just to make question less complicated,
//let's assume all members are public
   DirectX::XMFLOAT3 position; //pivot point
   DirectX::XMFLOAT3 rotation;

   Human * follow;
   std::vector<Human *> followers;
   DirectX::XMFLOAT3 distanceToFollow;

   ...
   void render(){
      ...
      DirectX::XMMATRIX objectWorldMatrix = DirectX::XMMatrixIdentity();
      DirectX::XMMATRIX rotationMatrix = 
         DirectX::XMMatrixRotationX(rotation.x) * 
         DirectX::XMMatrixRotationY(rotation.y) * 
         DirectX::XMMatrixRotationZ(rotation.z)
      );
      ...
      DirectX::XMMATRIX translationMatrix = DirectX::XMMatrixTranslation(position.x, position.y, position.z);
      objectWorldMatrix =  scaleMatrix * rotationMatrix * translationMatrix;
      ...
   }

   void follow(Human * h){
       follow = h;
       h.followers.push_back(this);
       distanceToFollow = h.position - position;
   }
};

他们之间的关系看起来像这样:

soldier.follow(sergeant);
sergeant.follow(marshal);

我现在想要的是soldier跟随sergeantsergeant跟随marshal。因此,当例如 marshal移动时,每个人都会移动并保持彼此的距离(以及相对角度)(&#34;可视化&#34; 2D用于简化,但我正在使用3D模型):

enter image description here

对于职位变更,即可:

void Human::setPosition(XMFFLOAT3 newPosition){
    position = newPosition;
    for(auto &follower : followers){
        follower.setPosition(newPosition - follower.distanceToFollow);
        //keep the distance, soldier!
    }
}

但我无法弄清楚,如何为轮换做出同样的决定?

marshal轮换后,sergeant会更改其positionrotation

我很少失败。在我上一次尝试期间,当我将marshal轮换到[40, 0, 0],然后[0, 30, 0],然后[-40, 0, 0][0, -30, 0]sergeant到位时就不同了在所有这些旋转之前(marshal支持放置它,并且旋转[0, 0, 0] - 相对距离已被打破)。也许是因为计算的顺序。

无论如何,我不想提出解决问题的错误方法,所以只会问你:如何编写 Human::setRotation(XMFFLOAT3 newRotation) 方法?< /强>

注意:现在没有插值/动画(从一个州到另一个州),所以我猜四元数不是必需的。


我的尝试

起初我不想发布它。这是因为我认为它包含了一些错误,我不想向你提出这些错误(我觉得与正确的解决方案比较比找错误的错误更容易)。但是如果你想检查我的错误代码:

Human::setRotation(XMFFLOAT3 newRotation){
    XMFFLOAT3 oldRotation = rotation;
    rotation = newRotation;
    for(auto &follower : followers){
        follower.rotateAround(newRotation - oldRotation, rotationDiffrenceToFollowTarget, position);
        //keep the relative angle, soldier!
    }
}

Human::rotateAround(XMFFLOAT3 radians, XMFFLOAT3 origin){
    DirectX::XMMATRIX rotX = DirectX::XMMatrixRotationX(radians.x);
    DirectX::XMMATRIX rotY = DirectX::XMMatrixRotationY(radians.y);
    DirectX::XMMATRIX rotZ = DirectX::XMMatrixRotationZ(radians.z);

    DirectX::XMMATRIX worldM = rotX * rotY * rotZ;

    DirectX::XMFLOAT3 positionTemp = DirectX::XMFLOAT3(
        position.x - origin.x, position.y - origin.y, position.z - origin.z);
    DirectX::XMVECTOR pos = XMLoadFloat3(&positionTemp);
    pos = XMVector3Transform(pos, worldM);
    XMStoreFloat3(&positionTemp, pos);

    positionTemp.x = positionTemp.x + origin.x;
    positionTemp.y = positionTemp.y + origin.y;
    positionTemp.z = positionTemp.z + origin.z;

    setPosition(positionTemp); //so followers will get noticed
    rotation += radians;
}

rotationDiffrenceToFollowTarget计算为:

Human::void follow(Human * h){
    follow = h;
    h.followers.push_back(this);
    distanceToFollow = h.position - position;
    rotationDiffrenceToFollowTarget = h.rotation - rotation;
}

1 个答案:

答案 0 :(得分:1)

你不能减去一组三个旋转角度并且期待感觉,因为3D旋转不会通勤,这几乎会破坏你的方法。您的三个角度区域对任何东西都没有多大用处 - 它是您想要存储的一体化矩阵。

这样做的方法是将领导者的每个单独的运动表达为单个矩阵,并将该矩阵恰好应用于追随者。对于翻译,这个矩阵只是一个翻译,对于旋转,它是领导者到原点的翻译,然后是简单的旋转,反映导致它的UI动作,然后是反向翻译。当我说&#34;其次是&#34;我的意思是&#34;预乘&#34;。

如果该UI动作应该是以角色为中心的,即如果向左转是感觉相同,那么在应用更改并重新应用之前,您还必须展开当前轮换。之后,翻译仍然是最外层的。如果没有这种跟随领导者的特征,可以归结为简单地将当前矩阵乘以变化,但对于跟随者,你将应用领导者当前矩阵的逆,然后改变,然后是旧的当前矩阵。

这不适用于您的多阶段关注事项,所以您必须表达这一点,因为这两位关注者都是直接关注一位领导者。

另一个选择是找到一个矩阵,将领导者的整个状态转换为跟随者,并且当领导者在你周围移动时,通过该矩阵将他的状态转换为跟随者的状态。通过&#34;州&#34;我的意思是位置和方向表示为单个矩阵。你怎么在第一时间找到那个矩阵?如果它被称为M而L和F是两个状态,那么L.M = F所以M = Inv(L).F。

那是否足够具体? ; - )