0

我正在用 C++(弹簧物理)进行绳索物理模拟。我成功地实现了基本的绳索运动,它由几个“骨骼”(它们只是一些具有位置、重量等的粒子 [质量])组成。计算每个粒子的位置后,我将它们分别分配给蒙皮网格骨架的相应骨骼。我想要的是计算一个粒子的旋转,以便它旋转到它的子粒子(圆是骨头的头部[粒子的位置],黑点是尾巴,它应该连接到它的孩子的头部,并且依此类推...): 问题形象化 我查找了一些线程并得出了结论:Finding quaternion代表从一个向量到另一个向量的旋转,并尝试实现我的项目接受的答案,所以我得到了这个:

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);

如果有人能给我一个替代解决方案,我将非常感激,并为糟糕的绘画技巧感到抱歉。

4

1 回答 1

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));

更新:

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

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 块左右的骨骼),但对于更大的模型,您还需要一个记忆算法来加快计算速度,因为现在的递归将计算根骨骼的变换矩阵多次。

于 2013-08-13T16:01:22.167 回答