3

我想实例化一个滑块约束,它允许一个物体在 A 点和 B 点之间滑动。为了实例化约束,我将两个物体分配给约束,在这种情况下,一个动态物体被约束到静态世界,想想滑动门. 第三个和第四个参数是变换,参考帧 A参考帧 B。为了创建和操作变换,该库支持四元数、矩阵和欧拉角。

默认滑块约束沿 x 轴滑动主体。我的问题是: 我如何设置这两个变换,以便身体 B 沿着由它自己的原点和空间中的一个附加点给出的轴滑动?

我天真地尝试过:

frameA.setOrigin(origin_of_point); //since the world itself has origin (0,0,0)
frameA.setRotation(Quaternion(directionToB, 0 rotation));

frameB.setOrigin(0,0,0); //axis goes through origin of object
frameB.setRotation(Quaternion(directionToPoint,0))

然而,四元数似乎并没有像我预期的那样工作。我对它们的数学知识不好,所以如果有人能告诉我为什么这不起作用,我将不胜感激。发生的情况是身体沿着与方向正交的轴滑动。当我在四元数构造函数中改变旋转部分时,主体围绕该滑动方向旋转。

编辑: 框架是子弹物理。这两个转换是滑块关节如何相对于每个身体的局部坐标系附加在每个身体上。

Edit2 我还可以通过正交基设置变换的旋转部分,但是我必须可靠地从单个向量构造正交基。我希望四元数能阻止这种情况。

Edit3 我在以下过程中取得了一些有限的成功:

btTransform trafoA, trafoB;
trafoA.setIdentity();
trafoB.setIdentity();

vec3 bodyorigin(entA->getTrafo().col_t);
vec3 thisorigin(trafo.col_t);
vec3 dir=bodyorigin-thisorigin;
dir.Normalize();

mat4x4 dg=dgGrammSchmidt(dir);
mat4x4 dg2=dgGrammSchmidt(-dir);

btMatrix3x3 m(
    dg.col_x.x, dg.col_y.x, dg.col_z.x,
    dg.col_x.y, dg.col_y.y, dg.col_z.y,
    dg.col_x.z, dg.col_y.z, dg.col_z.z);
btMatrix3x3 m2(
    dg2.col_x.x, dg2.col_y.x, dg2.col_z.x,
    dg2.col_x.y, dg2.col_y.y, dg2.col_z.y,
    dg2.col_x.z, dg2.col_y.z, dg2.col_z.z);


trafoA.setBasis(m);
trafoB.setBasis(m2);

trafoA.setOrigin(btVector3(trafo.col_t.x,trafo.col_t.y,trafo.col_t.z));
btSliderConstraint* sc=new btSliderConstraint(*game.worldBody, *entA->getBody(), trafoA, trafoB, true);

但是,GramSchmidt 总是翻转 trafoB 矩阵的某些轴,并且门出现颠倒或从右到左。我希望有一种更优雅的方式来解决这个问题。 Edit4 我找到了一个解决方案,但是如果顶部向量与滑动方向对齐,我不确定这是否会导致约束求解器出现奇点:

btTransform rbat = rba->getCenterOfMassTransform();
btVector3 up(rbat.getBasis()[0][0], rbat.getBasis()[1][0], rbat.getBasis()[2][0]);
btVector3 direction = (rbb->getWorldTransform().getOrigin() - btVector3(trafo.col_t.x, trafo.col_t.y, trafo.col_t.z)).normalize();

btScalar angle = acos(up.dot(direction));
btVector3 axis = up.cross(direction);
trafoA.setRotation(btQuaternion(axis, angle));
trafoB.setRotation(btQuaternion(axis, angle));
trafoA.setOrigin(btVector3(trafo.col_t.x,trafo.col_t.y,trafo.col_t.z));
4

3 回答 3

1

有没有可能你把这种方式弄得太复杂了?听起来像一个简单的参数转换 ( x = p*A+(1-p)*B) 就可以了。如果你的推拉门类比是准确的,那么整个旋转/方向的事情就是一个红鲱鱼。

另一方面,如果您试图限制两个方向之间的插值,则需要设置额外的限制,因为在一般情况下没有唯一的解决方案。

——马库斯

于 2009-03-03T20:12:06.010 回答
0

如果您能说出您正在使用什么框架或 API,或者复制并粘贴您正在调用的函数的文档,将会有所帮助。如果没有那种细节,我只能猜测:

背景:四元数表示结合比例的 3 维旋转。(通常您不希望管理比例的复杂性,因此您只使用表示旋转的单位四元数。)矩阵和欧拉角是表示旋转的两种替代方式。

参考系是一个位置加上一个旋转。想象一个物体放置在空间中的某个位置,然后旋转以面向特定方向。

所以 A 帧可能需要是对象的初始位置和旋转(当滑块在一端时),而 B 帧是对象的最终位置和旋转(当滑块在另一端时)。特别是,这两个旋转可能应该是相同的,因为您希望对象刚性滑动。

但正如我所说,这只是一个猜测。

更新:这是子弹物理吗?它似乎没有太多的文档方式,是吗?

于 2009-02-21T21:56:38.510 回答
0

也许您正在寻找slerp

Slerp 是球面线性插值的简写,由 Ken Shoemake 在四元数插值的上下文中引入,用于动画 3D 旋转。它是指在给定端点和介于 0 和 1 之间的插值参数的情况下,沿单位半径大圆弧进行等速运动。

归根结底,您仍然需要传统的旋转矩阵来旋转物体。

编辑:所以,我还在猜测,但我假设框架负责 slerping 并且您想要描述开始状态和结束状态的两个转换?

您可以将仿射变换堆叠在另一个之上。除非你必须反省。例如,假设滑动门在开始状态下放置在 (1, 1, 1) 朝东,您想将其向北滑动 (0, 1, 0)。门将在 (1, 1, 1) + (0, 1, 0) 结束。

对于开始状态,将门向东旋转。然后最重要的是,您应用另一个平移矩阵将门移动到 (1, 1, 1)。对于最终状态,再次将门向东旋转,然后通过再次应用平移矩阵将门移动到 (1, 1, 1)。接下来,应用平移矩阵 (0, 1, 0)。

于 2009-02-21T21:57:26.403 回答