Smoothstep Integral

smoothstepintegral

Intro


При выполнении анимации без сохранения состояния мы каким-то образом должны описывать конечное положение и ориентацию объектов в сцене как функция времени, а не как результат процесса моделирования. Это означает, что понятия скорости и ускорения не даются явно для вычисляемой позиции, но они скорее неявны и являются следствием функции положения, которую мы разрабатываем. И поэтому иногда бывает немного сложно разработать функцию положения, которая производит желаемую скорость.



Влево, некорректная анимация. Верно, правильная анимация.

Одним из таких случаев является создание плавного перехода от стационарной ситуации к движению с постоянной скоростью. Мы знаем, что функция smoothstep () , также известная иногда как EaseInOut () , это удобный способ плавной интерполяции значений или перехода между состояниями. Поэтому естественно представить, что для создания такой анимации может потребоваться задействовать smoothstep (). Однако нужно быть осторожным и соблюдать правильное количество, что может быть неочевидно для некоторых людей. Итак, давайте посмотрим:

Неправильный способ сделать это


Один из подходов к разработке нашей функции анимации состоит в том, чтобы заметить, что мы хотим плавно интерполировать между двумя скоростями – от нулевой скорости в начале нашей анимации до постоянной скорости. Без потери общности, предположим, что мы хотим развивать скорость до 1 единицы в секунду, и что мы хотим, чтобы этот переход между стационарным и постоянным состояниями скорости длился T секунд. В основном

плавный шаг скорости поплавка (0.0, T, t);

И это здорово пока собственно. Проблема в том, как определить положение нашего объекта на основе этой скорости. Можно наивно попытаться умножить скорость на время, чтобы получить позицию, например:

float position (float t, in float T) {return smoothstep (0.0, T, t) t; }

Это, однако, не работает – при использовании в нашей сцене объект, который мы хотим привести в движение, кажется, быстро ускоряется, а затем очень резко и неестественно замедлиться перед установкой на постоянной скорости. На видео в верхней части статьи, слева, вы можете увидеть, как крылья бабочки, которую мы пытаемся привести в движение, кажется, замедляются, прежде чем начать нормально хлопать. Конечно, это не похоже на плавный шаг, и наша интуиция явно подвела нас здесь. Построение графика фактической функции position () с течением времени на самом деле показывает, что что-то действительно пошло не так, и что действительно наклон нашей кривой положения временно стал больше, чем градусов, или 1, что было нашей целевой скоростью:

Правильное решение


Итак, в чем была ошибка, почему мы не получили плавную анимацию. Проблема в том, что мы предположили, что положение – это скорость, умноженная на время, и это работает только для постоянных скоростей. В общем, положение – это интеграл скорости. Итак, чтобы получить нашу функцию положения, нам нужно интегрировать smoothstep. К счастью, поскольку smoothstep – это простая кубическая функция, интегрировать ее очень просто:

Это всего лишь одно деление (если T не известно заранее) и несколько умножений и сложений, и переводится в код напрямую как

float position (float t, in float T) {if (t> = T ) возврат t – 0,5 т; поплавок f = t / T; вернуть f f f (Tt 0.5); }

График этой функции, теперь выделенный синим цветом на рисунке ниже, показывает действительно красивый переход, где наклон плавно переходит от нуля к единице, не выходя за пределы:

И действительно, когда мы используем его для анимации крыльев бабочки, отображается в правой половине видео на В верхней части статьи анимация плавная и просто идеальная.

У вас есть работающий пример бабочки с неправильной и с правильной функцией положения в Shadertoy: https://www.shadertoy.com/view/sdBSWc . Кроме того, я использую эту функцию достаточно часто, чтобы добавить ее в свою коллекцию Полезные маленькие функции . И, наконец, я создаю 1-минутную сводку видео этой статьи.