У меня есть 2 твердых тела (a
& b
) и 1 фиксированное ограничение сустава (с относительной трансформацией rela
).
Мои цели - достичь: -
Нет. 1. b.transform = a.transform * rela
Нет. 2. Центр масс (_5 _ + _ 6_) не меняется.
Нет. 3. (3-е правило Ньютона) Скорость всей системы (_7 _ + _ 8_) не меняется.
Нет. 4. (3-е правило Ньютона) Угловая скорость всей системы (_9 _ + _ 10_) не меняется.
Нет. 5. Перемещение / вращение обоих объектов для решения этой задачи должно быть минимизировано.
Я хочу применить импульс / крутящий момент к обоим телам, чтобы они постепенно соответствовали требованиям.
Это видео может показать то, что я хочу - (ссылка на YouTube).
Как определить значение импульса / крутящего момента для каждого тела?
Мне нужна приблизительная идея / алгоритм.
Это может быть текст описания без какого-либо кода.
Пример
Вот пример проблемы и ее правильное решение (то есть конечное состояние покоя): -
Кодекс (черновик)
Вот мой текущий фрагмент, на всякий случай: -
class Transform {
Vec3 pos;
Matrix33 basis;
};
Каждое твердое тело имеет следующие поля: -
class RigidBody {
float mass;
Matrix33 inertiaTensor;
Transform transform;
Vec3 velocity;
Vec3 angularVelocity;
};
Исправить ограничение соединения: -
class FixConstraint {
Transform rela;
RigidBody* a;
RigidBody* b;
};
Черновик моего плохого решения
Короче говоря, мне нужно изменить 12 переменных.
- положение
a
иb
(xyz - 6 переменных) - ориентация a и b (угол xyz - 6 переменных)
Затем я могу использовать «Мои цели» № 1 и 2 для создания некоторых уравнений.
Затем, в лучшем случае, я должен решить 12 линейных уравнений с 12 неизвестными переменными.
Я сомневаюсь, что это должно быть так сложно.
Мой предыдущий поиск в Интернете
Я просмотрел различные источники, но в основном они:
- просто войдите в решатель итераций.
- попробуйте диагонализовать матрицу + якобиан: понять может только специалист.
- "Почему бы вам не заглянуть в (вставьте здесь название Physic Engine) исходный код?" без понятных для новичков объяснений.
- покажите, как использовать (имя Physic Engine) для создания фиксированного ограничения соединения.
Вот некоторые из самых полезных: -
- Решатель Bullet Physics: https://github.com/svn2github/bullet/blob/master/tags/bullet-1.5f/BulletDynamics/ConstraintSolver/Point2PointConstraint.cpp
- "Стабильная, надежная и универсальная анимация динамики многотельных тел" http://image.diku.dk/kenny/download/erleben.05.thesis.pdf (см. главу 6)
- (отредактировано-добавлено) Алгоритм Фезерстоуна для тряпичной куклы: https://en.wikipedia.org/wiki/Featherstone%27s_algorithm (но он ориентирован на множество ограничений, а не на одно)
(отредактировал некоторые формулировки и правила, спасибо fafl и Нико Шертлер.)
(отредактировано-добавлено, через несколько дней)
Я считаю, что если я смогу взломать "Point2PointConstraint.cpp" (из Bullet Physics), я полностью пойму алгоритм и принцип.
Я также скопирую его сюда, на всякий случай.
Вот первая часть: -
SimdVector3 normal(0,0,0);
for (int i=0;i<3;i++)
{
normal[i] = 1;
new (&m_jac[i]) JacobianEntry(
m_rbA.getCenterOfMassTransform().getBasis().transpose(),
m_rbB.getCenterOfMassTransform().getBasis().transpose(),
m_rbA.getCenterOfMassTransform()*m_pivotInA - m_rbA.getCenterOfMassPosition(),
m_rbB.getCenterOfMassTransform()*m_pivotInB - m_rbB.getCenterOfMassPosition(),
normal,
m_rbA.getInvInertiaDiagLocal(),
m_rbA.getInvMass(),
m_rbB.getInvInertiaDiagLocal(),
m_rbB.getInvMass());
normal[i] = 0;
}
Вот вторая часть: -
SimdVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_pivotInA;
SimdVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_pivotInB;
SimdVector3 normal(0,0,0);
for (int i=0;i<3;i++)
{
normal[i] = 1;
SimdScalar jacDiagABInv = 1.f / m_jac[i].getDiagonal();
SimdVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
SimdVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
//this jacobian entry could be re-used for all iterations
SimdVector3 vel1 = m_rbA.getVelocityInLocalPoint(rel_pos1);
SimdVector3 vel2 = m_rbB.getVelocityInLocalPoint(rel_pos2);
SimdVector3 vel = vel1 - vel2;
SimdScalar rel_vel;
rel_vel = normal.dot(vel);
//positional error (zeroth order error)
SimdScalar depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
SimdScalar impulse = depth*m_setting.m_tau/timeStep * jacDiagABInv - m_setting.m_damping * rel_vel * jacDiagABInv;
SimdVector3 impulse_vector = normal * impulse;
m_rbA.applyImpulse(impulse_vector, pivotAInW - m_rbA.getCenterOfMassPosition());
m_rbB.applyImpulse(-impulse_vector, pivotBInW - m_rbB.getCenterOfMassPosition());
normal[i] = 0;
}
a
иb
). Однако это довольно сложно, поэтому телепортироваться не так уж и плохо. О вращении: еслиa
находится слева и движется вверх, аb
- справа и движется вниз, если они могут соединиться вместе, общий результат должен примерно вращаться как единое целое по часовой стрелке. (Я немного отредактировал вопрос, спасибо.) - person javaLover   schedule 03.04.2019a+b
. - person Spektre   schedule 11.04.2019a+b
объекта. Исходная точка - это центр масс объединенных объектов, а оси выровнены таким образом, чтобы объекты располагались на одной линии / оси (например, x) в каждом обновлении, применяя вращения и движение к этому реперу и вычисляя глобальное положение подобъектов на его основе. . поскольку их локальные координаты всегда будут одинаковыми ... так что это просто вопрос умножения на прямую или обратную матрицу (в зависимости от используемых обозначений) - person Spektre   schedule 11.04.2019absoluteTransformChild = absoluteTransformParent*relativeTransformOfThatChild
. (на всякий случай, если вы это объясняете); Хм, я до сих пор не верю, что трение связано с этим вопросом. Я согласен с тем, что трение заставляет вращающийся шар двигаться по полу. - person javaLover   schedule 11.04.2019