Очередные сложности со столкновениями тел. Краткое содержание предыдущих серий:
Сначала мы столкновения реализовывали упругими силами, расталкивающими тела. Недостатки -- силы должны быть большими, чтобы не допускать глубокого проникновения тел друг в друга, а это приводит к жесткости задачи и довольно большим погрешностям интегрирования. Как правило, даже в не очень сложных задачах энергия флуктуировала на уровне 10-5 что довольно много.
Потом мы реализовали идеальные столкновения. Столкновение 2-х идеальных (недеформируемых) твердых тел даже с учетом вращения можно аналитически точно рассчитать используя только законы сохранения энергии/импульса/момента импульса. На выходе -- идеальный биллиард практически без артефактов -- точность соблюдения законов сохранения достигала 15 знаков после запятой -- фактически, точность машинной арифметики.
Схема отлично работала пока мы не начали ее тестировать в гравитационных полях. Оказывается, если "положить" неупругий шарик на "пол" --плоскость (в поле тяжести), то он начинает (медленно но неуклонно) в нее просачиваться. Причина простая -- на каждом шаге интегрирования шарик приобретает небольшую скорость вертикально вниз, и чуть-чуть смещается тоже вниз. Т.е. к концу шага он оказывается чуть внутри плоскости. Движок collision detection фиксирует взаимопроникновение, движок столкновений отрабатывает физику столкновения, и "отражает" скорость шарика -- теперь он летит вверх. Если столкновение абсолютно упругое, этой скорости точь-в-точь хватает, чтобы к концу следующего шага оказаться там же, где он был в начале предыдущего -- у поверхности пола -- и все начнется с начала. Т.е. шарик будет просто колебаться с периодом 2*dt. Но если столкновение неупругое, то после отражения у шарика будет меньшая скорость, и он потеряет ее в гравитационном поле раньше, чем "выскочит" из взаимопроникновения с плоскостью. И следующий шаг (микропадение-отражение-микроподскок) начнет уже с точки чуть-чуть под поверхностью. Это чуть-чуть будет каждый раз увеличиваться, постепенно шарик будет просачиваться в пол.
Решение было довольно очевидным -- нужно делать коррекцию положения (position correction -- штука, хорошо известная в игровых движках, хоть там и несколько другая физика). Т.е. вместе с модификацией импульсов/моментов тел в ходе столкновения нужно "откатить время" назад, ровно чтобы оказаться в моменте, где объекты еще только-только соприкоснулись. Строго говоря, откатить, конечно, нужно всю систему, но для упрощения жизни мы начали откатывать только пару сталкивающихся тел. Тела перестали проваливаться.
Вместо этого они начали разгоняться. Причина, опять же, легко понятна. Выталкивая шарик к поверхности пола, мы, фактически, совершаем работу против сил гравитации, которые его толкали вниз -- т.е. чуть-чуть увеличиваем энергию системы. Если в системе мала диссипация, эти маленькие работы начинают накапливаться, и система идет в разнос. Починили это завязав коррекцию положения на коэффициент упругости отражения. Казалось бы, настало счастье.
И вот, очередной раунд. Создаем стакан (стенки+пол), поле тяжести, +20 шариков, столкновения неупругие. Через несколько секунд шарики скапливаются на дне стакана. И начинают довольно быстро просачиваться друг в друга и в пол.
Почему? Кратные столкновения. Наше приближение -- при коррекции положения откатывать надо всю систему, но мы откатываем только текущую пару тел -- работает удовлетворительно только если в системе достаточно "свободно", если столкновения только парные, если отматывая время для одной пары тел и убирая их взаимопроникновение мы, тем самым, не создаем взаимопроникновение другой пары тел. В случае стакана с шариками на дне это не так. Каждый шарик в контакте с 2-3-4 другими, а то еще и с полом или стенками. Получается, что для данного шарика коррекция положения будет суперпозицией коррекций для всех его столкновений с соседями. По факту, более-менее правильно пройдет только последняя коррекция, остальные превратятся черт знает во что. Вот это "черт знает" и видно на экране :)
Что будет следующей итерацией пока не знаю. Надо думать. Честно рассчитывать кратные столкновения нереально -- во-первых, только из законов сохранения более чем парное столкновение не рассчитать, во-вторых под это дело придется сильно корежить движок collision detection, в третьих сам алгоритм position correction для этого случая неочевиден.
В раздумьях
Комментариев нет:
Отправить комментарий