views:

723

answers:

3

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

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?

Gareth Rees
the framework is bullet physics.
heeen
A: 

Perhaps you are looking for slerp?

Slerp is shorthand for spherical linear interpolation, introduced by Ken Shoemake in the context of quaternion interpolation for the purpose of animating 3D rotation. It refers to constant speed motion along a unit radius great circle arc, given the ends and an interpolation parameter between 0 and 1.

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

eed3si9n
there's no interpolation/animation involved. I need two static transformations that link two bodies with a straight line.
heeen
sorry, still wrong. Think of it this way: you have two things you want to attach sliding on a rod. the transformations specify how you attach the sliding holster to each body: at the edge of the body, or right through the center, top to bottom or front to back.
heeen
+1  A: 

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

MarkusQ
The orientation part is necessary, because if you imagine a room with two doors, one at the east wall, and one at the north wall, not only do they slide in different directions, they also are differently oriented.See my comments below for more details.
heeen