Я хочу создать ограничение ползунка, которое позволяет телу скользить между точкой 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))
Однако кватернионы, похоже, не работают так, как я ожидал. Мои математические знания о них не очень хороши, поэтому, если кто-то сможет объяснить мне, почему это не работает, я буду благодарен.
Что происходит, так это то, что тело скользит вдоль оси, ортогональной направлению. Когда я изменяю вращательную часть в конструкторе Quaternion, тело вращается вокруг этого направления скольжения.
Edit:
Основой является физика пули.
Эти два преобразования показывают, как соединение ползунка прикрепляется к каждому телу по отношению к локальной системе координат каждого тела.
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));