Pull to refresh

Comments 38

Также данный алгоритм можно использовать для другого фундаментального взаимодействия

Какой этот алгоритм? 2 закон Ньютона? Или редуцированный вариант численного метода интегрирования Эйлера? Так то их можно использовать практически везде, разве что пока у вас скорости не близкие к световым. Ну и разумеется если нужна большая точность, то Эйлера лучше заменить на что-то типа Дорвана-Принса.

Что касается статьи — зря вы выбрали dt = 1. Первая причина — ваша одна секунда равняется 0.02 с реальных, а, как следствие — все коэффициенты придется пересчитывать. Вторая — если будет просяд fps — все поедет. Нужно рассчитывать dt динамически.

Ну и setTimeout — используйте window.requestAnimationFrame.

А так статья интересная, но (только не в обиду) для гуманитариев. Второй закон Ньютона и интегрирование Эйлером — прям совсем база.
UFO just landed and posted this here
dt должен быть фиксированным. Если между двумя кадрами прошло время dt*2 то надо просчитать физику на 2 шага.
и привет, «телепорты» и проскакивания насквозь.

А собственно, кому должен? Всё зависит от постановки задачи.
В еве онлайн вот не побрезговали замедлением времени при увеличении количества участников.
Да что вы утрируете то?
В js (да везде в общем то) dt должен быть динамичным, покуда requestAnimationFrame не стабильный (я уж молчу про setInterval) — то будет все заторможенно, то наоборот. Но если «промах» по времени был слишком большой (больше некого epsilon) — ставим dt равным этому порогу. Да, будет тормоз, но решит кучу других проблем.
Не совсем так. dt должен быть фиксированным. Если между двумя вызовами requestAnimationFrame прошло времени n*dt, то нужно обсчитать физику в n шагов.
Телепорты и проскальзывания насквозь получаются как раз из-за динамического dt. Если 2 объекта движутся навстречу друг другу, а dt сильно большой, то они пролетят сквозь друг друга. Но если большой dt разделить на интервалы поменьше, то коллизия будет зарегистрирована. Кроме того динамический dt не позволяет добиться одинакового поведения при одинаковых исходных условиях, что сильно затрудняет тестирование.
Если 2 объекта движутся навстречу друг другу, а dt сильно большой, то они пролетят сквозь друг друга.


Так и я про это же.
Но я не согласен, что из-за динамического. Если интервал большой, то статичность не поможет.

Но если большой dt разделить на интервалы поменьше

Так эти интервалы опять же и будут dt для физического движка.

И я это тоже имел в виду — считать надо эти субинтервалы, а не «между двумя кадрами».
Второй закон Ньютона и интегрирование Эйлером — прям совсем база.
Тогда, когда был придуман этот алгоритм я даже производных ещё не знал, а метод Эйлера только на 2 курсе универа нам преподнесли.
Ну и setTimeout — используйте window.requestAnimationFrame.
Спасибо за совет, следующих статьях буду использовать именно этот метод
Нужно рассчитывать dt динамически.

В результате получим невоспроизводимость -> боль при отладке.
Ещё вспоминается Dune II, где можно было влиять на успех боя переключая скорость игры.
Мне с постоянным dt сразу вспоминается GTA II, который без патча на современной системе работает с fps ~500 и одно нажатие клавиши отправляет вас в дорогу со скоростью звука.
Кстати, управлять величиной FPS можно не только с помощью изменения dt. Если расчёт закончился раньше времени (для большого dt), то можно просто дать процессору отдохнуть.
Ну и разумеется если нужна большая точность, то Эйлера лучше заменить на что-то типа Дорвана-Принса.

Если физический движок предназначен для какой-то игры, то нужна не точность, а быстродействие. Так что лучше вместо Дормана — Принса взять метод Верле, который позволяет получать координаты прямо из ускорений без вычисления скоростей.
А где просчет столкновений? К сожалению, ничего интересного. Лучше бы потратили время на изучение Box2D, например.
Просчёт столкновений в следующей статье будет
Меня вот, кстати, всегда немного удивляло почему просчёт столкновений относят к физическому движку. Как по мне, этим должен заниматься отдельный менеджер, а движок должен заниматься расчёт изменений физических (а не габаритных, геометрических) свойств объектов на основе данных о взаимной расположении объектов в пространстве.
Что такое «отдельный менеджер»? Что подразумевается под физическими изменениями? Почему габаритные — не физические? Без подколки, просто привык считать, что ф. движок просчитывает все, что связано и с положением в пространстве, и изменением положения, размерами — все, что связано с законами механики и пр. Задачка вида «было у нас 2 шара, они столкнулись и где нам их рисовать через 3 секунды после столкновения?» — вполне себе для ф. движка.
Да, согласен, не корректно сформулировал. Габаритные свойства тоже можно в чём-то отнести к физическим. Я имел в виду то, что часто не нужен просчёт взаимодействия негабаритных свойств объектов (расчёт сил, ускорений, и.т.д), но нужно только искать пересечение между габаритами объектов, между объектами и лучами, и.т.д. Для механизма решения задач поиска взаимоотношения геометрических форм в пространстве есть название: spatial database (пространственные базы данных). В физических движках поиск пересечений почти всегда включают в механизм расчёта физической реакции на эти пересечения. Именно это меня всегда удивляло. Всегда казалось, что это разные области ответственности и что из-за этого, во-первых, приходится тащить за собой данные о физических свойствах объектов когда тебе не нужны связанные с ними расчёты, а во-вторых отпадает возможность для разработчиков физических движков использовать готовые библиотеки для работы с пространственными базами данных, а на себя брать задачу создания более качественной реализации физической симуляции (ну, или наоборот — создавать более качественные пространственные базы данных и присоединять к ним механизмы физический симуляции).
Попробуйте посмотреть в сторону потенциала Леннарда-Джонса (насколько я догадываюсь, Вы «вручную» собираетесь контролировать сближение объектов?).
Буду искать объекты, которые пересекаются и объединять их в центре масс (неупругое столкновение) или раздвигать их и давать скорость по закону сохранения импульса (упругое).
А что делает этот код физическим движком? Функция Step()?
Прочил определение и отстал. Привык считать, что движок — это компонент для других программ (библиотека или фреймворк).
Отсутствие dt в коде реализации численной схемы — большая ошибка, особенно для программы, претендующей на учебник для новичков. И лучше его задать честной константой dt=0.025, как Вы указали вначале статьи.
Рано или поздно, он понадобится.
Забавно как-то гравитация работает (столкновений, как я понимаю в этой версии нет). Если в демке натыкать мышкой несколько точек рядом, они медленно притягиваются друг другу по спирали, а затем запуливают друг друга в разные стороны с какой-то невменяемой скоростью.
Немного правил константы, и Вы попали в момент, когда движение было слишком медленным. Сейчас всё работает
Да, так лучше, но гравитация продолжает выглядеть странной.
Издержки пошагового вычисления: в определённый момент расстояние между объектами становится очень маленьким и сила стремится к бесконечности, поэтому они ускоряются до невероятной скорости. На следующий такт эти объекты слишком удаляются друг от друга и не могут затормозить из-за большого расстояния
Эта строка частично решает данную проблему:
if(r < 0.1) r = 0.1; // избегаем деления на очень маленькое число

Можно также ввести искусственное ограничение скорости или уменьшить интервал.
Спасибо. Весьма исчерпывающее объяснение. Будет интересно посмотреть реализацию вашего движка с обработкой коллизий, но присоединюсь к KvanTTT. Для практических целей, лучше использовать какой нибудь из уже существующих движков. Тот же Box2D, например.
Я тоже делал N-body simulation, долго возился с величиной r, пока не понял, что это жуткий костыль. Как сделать правильную физическую симуляцию макрообъектов? Задать им размер? Принудительно заставить соблюдаться закон сохранения импульса?
Я бы задал размер и после столкновения пересчитал скорости по закону сохранения импульса. В своём конечном варианте я задал плотность константой и высчитывал радиус исходя из массы.
При большом количестве частиц количество вычислений методом «в лоб» будет расти квадратично, что не очень хорошо. Ведь на движение каждой частицы наибольшее влияние оказывают её ближайшие соседи. Если не нужна сверхвысокая точность (а задача многих тел точно не решается даже численно), можно ограничиться только ими.
Попробуйте реализовать модель с меньшей алгоритмической сложностью. В качестве отправной точки рекомендую, например, event driven collision model. Она в общих чертах рассмотрена в книге «Алгоритмы» Седжвика и его же курсе «Algorithms I» на Курсере.
И вот на горизонте замаячил fast multipole method, про который, между прочим, было бы *действительно* интересно почитать.
Забудем на время то, что в (1) сила — скаляр, а в (2) сила — вектор. И во 2 случае будем считать силу и ускорение скалярами.

Что-что? Может стоит лучше сказать, что в (1) речь идет о проекции силы на конкретное направление (на направление вдоль линии, соединяющей центры тел)? Это очень и очень существенное обстоятельство, если эта статья призвана кого-то и чему-то научить. :)

И да: посмотрите в сторону метода Рунге-Кутты.
У вас в движке большая проблема с просчетом близких орбит. Не работает банальный закон сохранения энергии — если два тела почти стоят, то в демке, да и с такой дискретной математикой, у них будут очень большие ускорения на близких расстояниях. Как результат — если просто поставить два тела, то они медленно будут сближаться, а потом разлетятся на сильно большей скорости чем им дала энергия падения.
Общим, я даже не знаю где эту модель можно применить. Нужно существенно доработать.
Sign up to leave a comment.

Articles