我想实例化一个滑块约束,它允许一个物体在 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));