Як я можу виправити об'єкти, що «вискакують» або тремтять у фізичному двигуні?


11

У мене є простий двигун фізики, який вирішує зіткнення, просто виправляючи положення тіл, що перекриваються (на даний момент просто кола), на відміну від простої зміни швидкості або застосування імпульсу. Швидкість змінюється лише після того, як впливи вже вирішені або під час інтеграції.

У мене виникла проблема, що на купи об’єктів верхні об’єкти чинять занадто великий тиск (це неявно, в алгоритмі немає моделювання тиску) на об’єкти в нижній частині кути, внаслідок чого їх проштовхують через підлоги, тощо.

Я хотів виправити це шляхом сортування об'єктів за їх y-координатою, тож зіткнення вирішуються знизу вгору. Але тепер, двигун демонструє дивну поведінку, що вискакує для об'єктів, які насправді повинні знаходитись у спокої (див. Gif)

введіть тут опис зображення

Не даючи вам лише вихідний код - що це може бути?


5
Загалом, це аналогічно ітераційному вирішенню лінійної системи рівнянь (або нелінійної системи, залежно від ваших обмежень / умов / тощо). У будь-якому випадку ви бачите ці артефакти, оскільки чисельно вони є правильною річчю: проміжні стани процесу конвергенції. Уникнути цього досить важко і може означати безліч неприємних хак (все одно, це відбувається в реальному житті на молекулярному рівні, і саме це у вас є, щоб найкраще нагадувати щось у реальному житті :)). Напевно, добре дослідити box2d, щоб побачити їх рішення для динаміки, заснованої на імпульсі.
теодрон

@TravisG як ти вирішив проблему? Я дивлюсь на подібну проблему, коли намагаюся реалізувати дуже простий двигун фізики.
сир

1
@cheeesus Минуло деякий час, коли я працював над цим, але я вважаю, що я просто використав більше ітерацій із меншими часовими кроками.
TravisG

Відповіді:


5

Я знайшов одне рішення, використовуючи коригування позиції, - це зробити кілька ітерацій і змінювати силу з кожною ітерацією.

doPhysics();

int num_iterations = 5;
for(int iteration=0; iteration<num_iterations; ++iteration)
{
    float strength = float(iteration+1)/num_iterations;
    correctPositions(strength);
}

Отже, перша ітерація має силу 1 / num_iterations, а остання має силу 1. Це робить мої імітації більш плавними та стабільними, ніж просто використання однакової кількості ітерацій із фіксованою силою.


2
Приємне рішення, але чому це працює?
Густаво Масель

5

Ваша проблема полягає в тому, що у вас немає стану спокою для ваших тіл. Будь-яка фізична система має кількість енергії, будь то кінетична, теплова тощо. Насправді твердий предмет деформується незначно і перетворює деяку кінетичну енергію в тепло, хоча це навряд чи можна виміряти. Варто також зазначити, що насправді не існує такого поняття, як цілком твердий предмет. Навіть щільні матеріали, як алмаз, містять простір між атомами, даючи структурі атома можливість гнутися та поглинати кінетичну енергію.

Щоб зробити це актуальним, тіла, що відпочивають, знаходяться в стані, коли єдиною діючою силою є «нормальна сила», тобто сила, яка не дозволяє тілам пропливати один через одного. Величина цієї нормальної сили пропорційна щільності предметів і тому, наскільки вони проникли один в одного.

Фізичні двигуни називають це значення "похилим".

Ось хитрість: обчисліть нахил та виправте положення тіл та застосуйте нормальну силу, виходячи з відносної швидкості обох тіл. під час оновлення самих тіл обчислюйте кінетичну енергію кожного тіла. Якщо вона нижче мінімальної величини, тоді укладайте тіло спати, поки на нього не буде застосована сила достатньої величини. (як правило, вдвічі мінімальне значення).


0

Чому б не додати до них "липку" поверхню і змусити їх поступово прилягати до положення спокою, і коли інший предмет вдарить по ній, він передає в неї деяку кількість енергії, що змусить її рухатися, але липка поверхня призведе до втрати частини цієї енергії та припинення в положенні відпочинку. gif схожий на те, що не має до нього тертя.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.