Плавное увеличение/уменьшение числа

Нужна помощь математиков, ибо я, как говорится, не бум-бум

Покадрово рисую гифку на 180 кадров, в гифке колесо, которое по задумке изначально крутится быстро, и по итогу плавно останавливается, но я не понимаю, как сделать плавное замедление

Накидал минимальный-упрощённый пример того, как это происходит сейчас. Делаю какое-то подобие ускорения вращения, а по завершению цикла беру выходные картинки из папки и переворачиваю список, но остановка сейчас слишком резкая

int totalFrames = 180;
float lastAngle = 0;

for (int frame = 0; frame < totalFrames; frame++) {
    Image img = Image.FromFile(...);
    Image main = new Bitmap(img.Width, img.Height);

    float angle = 0;
    if (frame > 15)
        angle = (lastAngle + frame / 5f) % 360; << вот тут нужна плавность

    lastAngle = angle;

    using (Graphics g = Graphics.FromImage(main)) {
        g.DrawImage(RotateImage(img, angle), new Rectangle(0, 0, img.Width, img.Height));
        main.Save($"out/{frame}.jpg", ImageFormat.Jpeg);
    }
}

Ответы (1 шт):

Автор решения: Andrei Khotko

Плавное торможение достигается за счет уменьшения скорости вращения колеса (или угловой скорости). Скорость вращения колеса (в формулах и коде буду применять обозначение vAngular) - это угол, на который поворачивается колесо за единицу времени. В вашем случае - это поворот на x градусов за 1 кадр.

Эту скорость vAngular необходимо плавно уменьшать со значения vAngularStart до значения vAngularEnd = 0 за определенный промежуток времени. Чтобы уменьшать скорость в цикле - необходимо найти некоторую vDelta - изменение скорости вращения за 1 кадр. Она вычисляется по формуле:

vDelta = (vAgularEnd - vAngularStart) / deltaT

где deltaT - время торможения.

Поскольку скорость в вашем случае уменьшается, то vDelta будет отрицательная.

Применяя все выше сказанное к вашему коду, получаем следующее:

int totalFrames = 180;
int frameStartBraking = 15; // Фрейм, с которого начинаем торможение
float deltaT = totalFrames - frameStartBraking;

float vAngularStart = 30; // Скорость вращения колеса при начале торможения.
float vAngularCurrent = vAngularStart; // Считаем, что до торможения скорость колеса вращения не изменялась
float vAgularEnd = 0; // Конечная скорость вращения колеса
float vDelta = (vAgularEnd - vAngularStart) / (totalFrames - frameStartBraking);

float angle = 0;
for (int frame = 0; frame < totalFrames; frame++) {

    //...
    
    if (frame > frameStartBraking) {
        vAngularCurrent += deltaV;
    }
    
    angle += vAngularCurrent;

    //...
}

Регулируется плавность торможения за счет изменения величин vAngularStart и deltaT.

Единственный нюанс: этот расчет не гарантирует того, что в последнем фрейме ваше колесо будет повернуто на angle = 0.

→ Ссылка