如何从头到尾创建旋转?

时间:2013-08-13 15:18:11

标签: math linear-algebra directx-11

我正在用c ++(弹簧物理学)进行绳索物理模拟。我成功地实施了基本的绳索运动,它由几个“骨头”组成(只是一些具有位置,重量等的颗粒[质量])。计算每个粒子的位置时,我将它们分配给蒙皮网格骨架的相应骨骼。 我想要的是计算一个粒子的旋转,使它旋转到它的子粒子(圆是骨头[粒子的位置],黑点是尾巴,它应该连接到它的孩子的头部,等......): the problem visualized 我查了一些帖子,然后来到这里:Finding quaternion representing the rotation from one vector to another并试图实现我项目的接受答案,所以我得到了这个:

XMVECTOR q;
XMVECTOR a = XMVector3Cross(head,tail);
XMVECTOR lh=XMVector3Length(head),lt=XMVector3Length(tail),dot=XMVector3Dot(head,tail);

q.m128_f32[0] = a.m128_f32[0]; //assigning the x coordinate
q.m128_f32[1] = a.m128_f32[1]; //assigning the y coordinate
q.m128_f32[2] = a.m128_f32[2]; //assigning the z coordinate
q.m128_f32[3] = sqrt(pow(lh.m128_f32[0],2)*pow(lt.m128_f32[0],2)) + dot.m128_f32[0]; //assigning the w coordinate
return XMQuaternionNormalize(q);

不幸的是,由于某种原因它没有对我有用,所以尝试了另一个也失败了:

XMVECTOR Head = XMVector3Normalize( head );
XMVECTOR Tail = XMVector3Normalize( tail );

float angle = acos(XMVector3Dot(Head,Tail).m128_f32[0]); //acos(dot(Head,Tail))
XMVECTOR axis = XMVector3Normalize(XMVector3Cross(Head,Tail));

XMVECTOR q = XMQuaternionRotationAxis(axis,angle);

如果有人会给我发一个替代解决方案,我会非常感激,并为糟糕的油漆技巧感到抱歉。

1 个答案:

答案 0 :(得分:1)

不要直接使用XMVECTOR的成员......出于这个原因,XMStore / XMLoad函数就在那里。最底层的解决方案如下:

XMVECTOR Head = XMVectorNormalize(head);
XMVECTOR Tail = XMVectorNormalize(tail);

float angle = 0.0f;
XMStoreFloat(&angle,XMVector3AngleBetweenVectors(Head,Tail));
XMVECTOR axis = XMVectorCross(Head,Tail);

return XMQuaternionAxisAngle(axis,angle);

通过这种方式,您可以避免直接访问XMVECTOR,这可能有助于解决问题。

您还应该使用第一个解决方案,但同样应该使用XMStore / XMLoad函数而不是直接访问。

XMFLOAT3 a;
XMStoreFloat3(&a,XMVector3Cross(head,tail));
float lh2, lt2, dot;
XMStoreFloat(&lh2,XMVector3Dot(head,head)); //this calculates the length squared.
XMStoreFloat(&lt2,XMVector3Dot(tail,tail)); //same as above
XMStoreFloat(&dot,XMVector3Dot(head,tail));

XMFLOAT4 q;
q.x = a.x; //assigning the x coordinate
q.y = a.y; //assigning the y coordinate
q.z = a.z; //assigning the z coordinate
q.w = sqrt(lh2*lt2) + dot; //assigning the w coordinate
return XMQuaternionNormalize(XMLoadFloat4(&q));

更新:

如果仔细使用上述解决方案,它们将起作用,但通常情况下,它们会产生最终以原点为中心的结果。这是因为参考的变化。要产生所需的行为,您需要执行以下操作(假设点由结构/类Point表示):

XMMATRIX CalculateTransform(Point p)
{
    XMVECTOR pos=XMLoadFloat3(&p.GetPosition());
    //Get your new rotation quaternion using the methods above
    XMMATRIX r=XMMatrixRotationQuaternion(CalculateRotation(p.GetHead(),p.GetTail()));
    XMMATRIX t=XMMatrixTranslationFromVector(pos);
    if(p.HasParent())
        return CalculateTransform(p.GetParent())*r*t;
    else
        return r*t;
}

这将组成层次结构中每个先前骨骼的运动,以形成传递给函数的点的最终变换矩阵。

上述解决方案适用于小型模型(< 10-20骨骼左右),但对于更大的模型,您还需要memoization algorithm来加速计算,如递归现在,它将多次计算根骨的变换矩阵。