Рассчитать импульс / крутящий момент для обоих тел в трехмерном фиксированном соединении - PullRequest
6 голосов
/ 03 апреля 2019

У меня есть 2 твердых тела (a & b) и 1 фиксированное ограничение соединения (с относительным преобразованием rela).

Моими целями являются: -

Нет.1. b.transform = a.transform * rela
Нет.2. Центр масс (a + b) не изменяется.
Нет.3. (3-е правило Ньютона) Скорость всей системы (a + b) не изменяется.
Нет.4. (3-е правило Ньютона) Угловая скорость всей системы (a + b) не изменяется.
Нет.5. Перемещение / вращение обоих объектов для его решения должно быть минимизировано.

Я хочу применить импульс / крутящий момент к обоим телам, чтобы они постепенно соответствовали требованию.
В этом видео можно изобразить то, что я хочу - ( ссылка на YouTube ).

Как определить значение импульса / крутящего момента, которое применяется к каждому телу?
Мне нужна грубая идея / алгоритм.
Это может быть текст описания без кода.

Пример

Вот примерная проблема и ее правильное решение (т.е. состояние окончательного покоя): -

enter image description here

Код (черновик)

Вот мой текущий фрагмент, на всякий случай: -

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) для создания фиксированного ограничения соединения.

Вот некоторые из наиболееполезные из них: -

(отредактировал некоторые формулировки и правила, спасибо 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;
}

1 Ответ

2 голосов
/ 14 апреля 2019

Как следует из названия, ограничение - это ограничение, налагаемое на движение двух тел. Следовательно, чтобы успешно смоделировать ограничение, необходимо полностью понять, какие ограничения накладывает это ограничение на два тела, и представить эти ограничения в виде уравнения импульса или силы. Решатели на основе импульсов используются над решателями на основе силы почти все время, поскольку уравнения первого порядка (скорости) (и соответствующие числа) легче вычислить и иметь дело с уравнениями второго порядка (ускорения). Таким образом, мы будем рассматривать импульсы моделирования для общих 1-D ограничений (n-D ограничения могут быть представлены как одно или несколько 1-D ограничений).

Моделирование ограничения первого порядка (скорости) одномерного ограничения

Первый шаг в моделировании ограничения с импульсами представляет ограничение (я) в виде уравнений первого порядка (скорость / импульс). Рассматриваемое фиксированное ограничение (далее просто упоминаемое как «ограничение») имеет простое позиционное (нулевой порядок) ограничение: линейные и угловые положения в пространстве ограничений должны оставаться одинаковыми (как определено относительным преобразованием rela). Мы можем преобразовать это в ограничение первого порядка, используя тот факт, что для того, чтобы сделать относительное положение двух тел постоянным, их относительная скорость должна быть равна нулю. Таким образом, ограничение может быть интерпретировано как обеспечение того, что относительные линейные и угловые скорости двух тел в пространстве ограничений равны нулю.

Теперь ограничение можно смоделировать как импульс, который необходимо применить к системе, чтобы относительная скорость стала равной нулю. Если v1 и v2 - начальная и конечная относительные скорости системы, m - масса системы, а j - импульс, приложенный для удовлетворения ограничения, тогда

v2 = v1 + j/m    (1)
v2 = 0           (2)

Первое уравнение выполняется для любого ограничения (это второй закон Ньютона), но второе уравнение (далее именуемое уравнением ограничения) выполняется только для данного ограничения.

Моделирование ограничения нулевого порядка (положения) 1-D ограничения

Наша модель теперь гарантирует, что относительная позиция остается постоянной (ограничение первого порядка), но мы все еще не установили ограничение нулевого порядка, то есть относительная позиция B относительно A должна быть такой, которая определяется относительное преобразование rela. Если x1 является «ошибкой» в позиции системы ограничений, то это может быть «введено» в импульс, используя термин Баумгарте beta * x1/h, где h - шаг по времени, а beta - параметр, обычно между 0 и 1. Вы можете считать beta долей ошибки позиционирования, которую решатель должен разрешать в каждом кадре.

Наше уравнение ограничения теперь становится

v2 + beta*x1/h = 0

Примечание: Если решатель использует полу-неявное интегрирование, то x1 является исходной позиционной ошибкой, но если решатель использует неявное интегрирование, ошибка на самом деле x2 = x1 + v2*h.

Демпфирование / смягчение ограничения

Как вы указали, искомое ограничение является мягким (или демпфированным), поскольку вы хотите, чтобы движение происходило постепенно. Для экспоненциального демпфирования ограничения мы моделируем дифференциальное уравнение экспоненциального затухания и добавляем значение, пропорциональное j (которое пропорционально производной скорости dv = v2 - v1, поскольку шаг по времени становится бесконечно малым).

Наше уравнение ограничения теперь становится

v2 + beta * x1/h + gamma * j = 0

Где gamma >= 0 - другой параметр (также называемый коэффициентом демпфирования). Если gamma = 0, ограничение будет незатухающим или жестким.

Исключение v2 из двух уравнений и решение полученного уравнения для j дает нам

j = -(v1 + beta * x1/h) * (1/(gamma + 1/m))
                         | equivalent mass |

Механизм расчета применяет этот импульс и его отрицательное значение в направлении оси (обычно называемой normal ) ограничения.

Адаптация и использование общего 1-D мягкого ограничения

Этот общий 1-D импульс мягкого ограничения может быть перенаправлен для создания множества различных соединений, таких как фиксированные соединения, пружинные соединения и так далее. Для фиксированного соединения мы хотим, чтобы ограничение ограничивало положение B, а вращение в пространстве A было бы положением и поворотом относительного преобразования. Таким образом, в пространстве А x1 = B.position - rela.origin и v1 = relative velocity of A and B along x1. Однако, поскольку мы хотим ограничить положение в 3-х измерениях (т. Е. x1 - это трехмерный вектор, а не скаляр), мы можем решить 1-D ограничение для каждой из трех осей в отдельности. Затем этот процесс может быть повторен для угловых положений и скоростей с использованием того же ограничения. Тот же процесс можно использовать для получения импульса для любого одномерного ограничения.

Применение ограничения

После вычисления импульс j должен быть приложен к обоим телам в противоположных направлениях, чтобы суммарный импульс в системе ограничений был равен нулю. Когда положительный, этот импульс предназначен для отталкивания двух тел, а когда отрицательный - для их объединения. Следовательно, если нормальное ограничение указывает от тела A к телу B (в соответствии с соглашением), -j * normal применяется к телу A и +j * normal применяется к телу B.

1-D ограничение может быть расширено до n-D при необходимости. Некоторые ограничения, такие как ограничение пружины / расстояния, расположены вдоль линии и, следовательно, по своей природе являются одномерными ограничениями в n мерном пространстве и не требуют нескольких итераций решения для разных осей.

Вы также можете изменить уравнение ограничения, чтобы учесть накопленные импульсы при демпфировании для стабильности, если ваш решатель использует теплые запуски. Член демпфирования становится gamma * (j + j0), где j0 - накопленный импульс, который подается во время теплого старта.

Различия с решателями ограничений Bullet 1.5

Следует отметить, что искомое фиксированное ограничение на самом деле составляет Generic6DofConstraint (со всеми 6 степенями свободы), а не Point2PointConstraint (это шар и гнездо) сустав) в пуле 1.5. Вы можете посмотреть на его реализацию для справки. Решатели ограничений Bullet 1.5 используют немного другое (и немного более волнистое) уравнение с демпфированными импульсами (где они умножают относительную скорость на коэффициент демпфирования, но не добавляют ее к обратной величине эквивалентной массы), что немного ослабляет ограничение Больше. Выбор зависит от того, какой вы хотите выбрать, но я считаю, что тот, который здесь используется, более оправдан, а также гораздо проще адаптировать его к другим естественным мягким ограничениям (например, параметризация ограничения в терминах частоты пружины и коэффициента демпфирования для имитации демпфирующая пружина).

Вы также можете взглянуть на, надеюсь, самоочевидный код демпфирующей пружины (мягкое ограничение расстояния) solver в моем механизме 2D-физики.

...