Я пишу симулятор частиц в C ++.
Я перемещаю частицы, добавляя их скорость в их положение на каждом временном шаге.
Значение временного шага — это процент от текущего кадра. Таким образом, шаг по времени полного кадра равен 1, шаг по времени половины кадра равен .5, шаг по времени четверть кадра равен .25 и т. Д. Общее количество шагов моделирования равно frameCount / timeStep … поэтому, чем меньше шаг по времени, тем больше общее число шаги смоделированы.
Сохранение базовых движений во временных шагах одинаково очень просто. Уравнение:
position = position + velocity * timeStep; //10 full frames later, end position is always the same
Тем не менее, это становится слишком сложным для моего текущего понимания математики, когда я пытаюсь изменить скорость со временем тоже. Например, если я сделаю это:
velocity = velocity * .95f;
position = position + velocity * timeStep; //10 full frames later, end position dependent on time step
Результаты на разных временных шагах больше не совпадают. Я знаю, что это потому, что если я увеличиваю общее количество шагов, рассчитанное путем уменьшения шага по времени, я также уменьшаю скорость еще во много раз, что окажет большое влияние на конечное положение частицы.
Как я могу изменить скорость с течением времени таким образом, чтобы получить одинаковые результаты на разных временных шагах?
Скорость — это изменение положения с течением времени. Вы правильно рассчитали это в своем уравнении.
position = position + velocity * timeStep;
Ускорение — это изменение скорости с течением времени. Таким образом, вы просто используете то же уравнение, но соответственно изменяете переменные. То есть изменить положение на скорость, а скорость на ускорение. Шаг по времени остается неизменным.
velocity = velocity + acceleration * timeStep;
Если вы хотите симулировать трение, то вы умножаете скорость на некоторое постоянное значение трения и временной шаг и вычитаете это из ускорения. Но это значение следует использовать только для кадра, а не сохранять в фактическом значении ускорения.
float temp_accel = acceleration - friction * velocity * timeStep;
Затем измените свою скорость в соответствии с temp_accel.
velocity = velocity + temp_accel * timeStep;
Если ваше ускорение равно нулю, вы можете вычесть это из уравнения:
float temp_accel = -friction * velocity * timeStep;
Принятый ответ хорош, но я хочу подчеркнуть, что вы никогда не сможете быть полностью не зависит от размера шага симуляции.
Уравнения движения (которые дают нам положение и скорость в некоторый момент времени) являются интегралами. Симуляции приближают интеграцию, делая суммы по маленьким шагам. Но поскольку эти шаги конечны, а не бесконечно малы, всегда есть ошибка. Чем меньше вы можете сделать шаги, тем больше вы можете уменьшить ошибку.
Для видеоигр и анимации пользовательского интерфейса временные шаги порядка частоты кадров, скажем, 10-100 шагов в секунду, обычно достаточны для того, чтобы ошибка оставалась достаточно маленькой, чтобы она не оказала негативного влияния на внешний вид анимации или играбельность игра.
Но если вы выполняете одно и то же моделирование с частотой 10 и 100 шагов в секунду, вы можете получить разные результаты, потому что последнее является лучшим приближением, чем первое.
Сокращение шагов также увеличивает объем вычислений. Иногда вам не хватает мощности, чтобы использовать шаги, достаточно малые, чтобы удержать ошибку в разумных пределах. Для этих обстоятельств существуют численные интеграторы, которые дают лучшие приближения, чем повторяющиеся суммы. Вероятно, самый известный числовой интегратор Рунге-Кутта (РК4). Если вы обнаружите, что вы должны установить свой timeStep
непрактично маленький, попробуйте использовать RK4.