我有三个对象:marshal
,sergeant
,soldier
。所有这些都是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
跟随sergeant
和sergeant
跟随marshal
。因此,当例如 marshal
移动时,每个人都会移动并保持彼此的距离(以及相对角度)(&#34;可视化&#34; 2D用于简化,但我正在使用3D模型):
对于职位变更,即可:
void Human::setPosition(XMFFLOAT3 newPosition){
position = newPosition;
for(auto &follower : followers){
follower.setPosition(newPosition - follower.distanceToFollow);
//keep the distance, soldier!
}
}
但我无法弄清楚,如何为轮换做出同样的决定?
marshal
轮换后,sergeant
会更改其position
和rotation
。
我很少失败。在我上一次尝试期间,当我将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;
}
答案 0 :(得分:1)
你不能减去一组三个旋转角度并且期待感觉,因为3D旋转不会通勤,这几乎会破坏你的方法。您的三个角度区域对任何东西都没有多大用处 - 它是您想要存储的一体化矩阵。
这样做的方法是将领导者的每个单独的运动表达为单个矩阵,并将该矩阵恰好应用于追随者。对于翻译,这个矩阵只是一个翻译,对于旋转,它是领导者到原点的翻译,然后是简单的旋转,反映导致它的UI动作,然后是反向翻译。当我说&#34;其次是&#34;我的意思是&#34;预乘&#34;。
如果该UI动作应该是以角色为中心的,即如果向左转是感觉相同,那么在应用更改并重新应用之前,您还必须展开当前轮换。之后,翻译仍然是最外层的。如果没有这种跟随领导者的特征,可以归结为简单地将当前矩阵乘以变化,但对于跟随者,你将应用领导者当前矩阵的逆,然后改变,然后是旧的当前矩阵。
这不适用于您的多阶段关注事项,所以您必须表达这一点,因为这两位关注者都是直接关注一位领导者。
另一个选择是找到一个矩阵,将领导者的整个状态转换为跟随者,并且当领导者在你周围移动时,通过该矩阵将他的状态转换为跟随者的状态。通过&#34;州&#34;我的意思是位置和方向表示为单个矩阵。你怎么在第一时间找到那个矩阵?如果它被称为M而L和F是两个状态,那么L.M = F所以M = Inv(L).F。
那是否足够具体? ; - )