帮助我进行刚体物理/变换
我想实例化一个滑块约束,它允许主体在 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))
但是,四元数似乎并不像我期望。 我对它们的数学知识不好,所以如果有人能告诉我为什么这不起作用,我将不胜感激。 发生的情况是物体沿着与该方向正交的轴滑动。 当我改变四元数构造函数中的旋转部分时,主体将围绕该滑动方向旋转。
编辑: 该框架是子弹物理。 这两个变换是滑块关节相对于每个主体的局部坐标系连接到每个主体的方式。
编辑2 我还可以通过正交基设置变换的旋转部分,但随后我必须从单个向量可靠地构造正交基。 我希望四元数能够防止这种情况发生。
编辑3 我在以下过程中取得了一些有限的成功:
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 矩阵的某些轴,并且门出现颠倒或从右到左。 我希望有一种更优雅的方式来解决这个问题。 编辑4 我找到了一个解决方案,但我不确定如果顶部向量与滑动方向对齐,这是否会导致约束求解器出现奇点:
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));
I want to instance a slider constraint, that allows a body to slide between point A and point B.
To instance the constraint, I assign the two bodies to constrain, in this case, one dynamic body constrained to the static world, think sliding door.
The third and fourth parameters are transformations, reference Frame A and reference Frame B.
To create and manipulate Transformations, the library supports Quaternions, Matrices and Euler angles.
The default slider constraint slides the body along the x-axis.
My question is:
How do I set up the two transformations, so that Body B slides along an axis given by its own origin and an additional point in space?
Naively I tried:
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))
However, Quaternions don't seem to work as I expected. My mathematical knowledge of them is not good, so if someone could fill me in on why this doesn't work, I'd be grateful.
What happens is that the body slides along an axis orthogonal to the direction. When I vary the rotational part in the Quaternion constructor, the body is rotated around that sliding direction.
Edit:
The framework is bullet physics.
The two transformations are how the slider joint is attached at each body in respect to each body's local coordinate system.
Edit2
I could also set the transformations' rotational parts through a orthogonal basis, but then I'd have to reliably construct a orthogonal basis from a single vector. I hoped quaternions would prevent this.
Edit3
I'm having some limited success with the following procedure:
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);
However, the GramSchmidt always flips some axes of the trafoB matrix and the door appears upside down or right to left.
I was hoping for a more elegant way to solve this.
Edit4
I found a solution, but I'm not sure whether this will cause a singularity in the constraint solver if the top vector aligns with the sliding direction:
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));
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
有没有可能你把这种方式搞得太复杂了? 听起来一个简单的参数翻译(
x = p*A+(1-p)*B
)就可以做到。 如果你的滑动门类比是准确的,那么整个旋转/方向的事情就是一个转移注意力的事情。另一方面,如果您尝试限制两个方向之间的插值,则需要设置额外的限制,因为一般情况下没有唯一的解决方案。
——马库斯Q
Is it possible you're making this way too complicated? It sounds like a simple parametric translation (
x = p*A+(1-p)*B
) would do it. The whole rotation / orientation thing is a red herring if your sliding-door analogy is accurate.If, on the other hand, you're trying to constrain to an interpolation between two orientations, you'll need to set additional limits 'cause there is no unique solution in the general case.
-- MarkusQ
如果您能说出您正在使用的框架或 API,或者复制并粘贴您正在调用的函数的文档,将会有所帮助。 如果没有这种细节,我只能猜测:
背景:四元数表示与比例相结合的 3 维旋转。 (通常您不希望管理比例变得复杂,因此您使用仅表示旋转的单位四元数。)矩阵和欧拉角是表示旋转的两种替代方法。
参考系是一个位置加上一个旋转。 想象一个物体放置在空间中的某个位置,然后旋转以面向特定方向。
因此,A 帧可能需要是对象的初始位置和旋转(当滑块位于一端时),而 B 帧可能需要是对象的最终位置和旋转(当滑块位于另一端时)。 特别是,两个旋转可能应该相同,因为您希望对象刚性地滑动。
但正如我所说,这只是一个猜测。
更新:这是子弹物理学吗? 它似乎没有太多文档,不是吗?
It would help if you could say what framework or API you're using, or copy and paste the documentation for the function you're calling. Without that kind of detail I can only guess:
Background: a quaternion represents a 3-dimensional rotation combined with a scale. (Usually you don't want the complications involved in managing the scale, so you work with unit quaternions representing rotations only.) Matrices and Euler angles are two alternative ways of representing rotations.
A frame of reference is a position plus a rotation. Think of an object placed at a position in space and then rotated to face in a particular direction.
So frame A probably needs to be the initial position and rotation of the object (when the slider is at one end), and frame B the final position and rotation of the object (when the slider is at the other end). In particular, the two rotations probably ought to be the same, since you want the object to slide rigidly.
But as I say, this is just a guess.
Update: is this Bullet Physics? It doesn't seem to have much in the way of documentation, does it?
也许您正在寻找slerp?
最终,您仍然需要传统的旋转矩阵来旋转物体。
编辑:所以,我仍然在猜测,但我假设框架负责 slerping,并且您想要描述开始状态和结束状态的两个转换?
您可以将仿射变换堆叠在其他变换之上。 除非你必须向后思考。 例如,假设滑动门在开始状态时被放置在朝东 (1, 1, 1) 处,并且您希望将其向北滑动 (0, 1, 0)。 门最终位于 (1, 1, 1) + (0, 1, 0)。
对于开始状态,将门向东旋转。 然后在此基础上应用另一个平移矩阵将门移动到 (1, 1, 1)。 对于最终状态,再次将门向东旋转,然后再次应用平移矩阵将门移动到 (1, 1, 1)。 接下来,应用平移矩阵 (0, 1, 0)。
Perhaps you are looking for slerp?
At the end of the day, you still need the traditional rotational matrix to get things rotated.
Edit: So, I am still guessing, but I assume that the framework takes care of the slerping and you want the two transformations which describes begin state and the end state?
You can stack affine transformations on top of the other. Except you have to think backwards. For example, let's say the sliding door is placed at (1, 1, 1) facing east at the begin state and you want to slide it towards north by (0, 1, 0). The door would end up at (1, 1, 1) + (0, 1, 0).
For begin state, rotate the door towards east. Then on top of that you apply another translation matrix to move the door to (1, 1, 1). For end state, again, you rotate the door towards east, then you move the door to (1, 1, 1) by applying the translation matrix again. Next, you apply the translation matrix (0, 1, 0).