Анимация с начальной скоростью - PullRequest
9 голосов
/ 01 апреля 2010

Я пытался решить эту проблему уже несколько дней, но я, должно быть, что-то упустил.

Известные переменные:
vi = Начальная скорость
t = Продолжительность анимации
d = Расстояние.
конечная скорость всегда должна быть равна нулю

Функция, которую я пытаюсь создать: D (0 ... t) = текущее расстояние для данного времени

Используя эту информацию, я хочу иметь возможность создавать плавную кривую анимации с переменной скоростью (замедление / замедление).

Анимация должна быть в состоянии ослабить начальную скорость.

Время анимации должно составлять ровно t секунд, а время прохождения - ровно d единиц.

Кривая должна наклоняться к средней скорости с ускорением, возникающим в начале и в конечных частях кривой.

Я открыт для дополнительных переменных конфигурации.

Лучшее, что я смог придумать, это то, что не учитывает начальную скорость. Я надеюсь, что кто-то умнее может помочь мне. ;)

Спасибо!

p.s. Я работаю с вариантом ECMAScript

Ответы [ 5 ]

5 голосов
/ 03 апреля 2010

Вот другое решение, где нет никакого интервала времени, где скорость постоянна. Вместо этого скорость как функция времени является полиномом второго порядка, а ускорение линейно по времени (положительное в начале и отрицательное в конце). Может быть, вы можете попробовать это.

Позвольте мне немного переименовать ваши переменные. Пусть

  • T = конечное время = продолжительность анимации
  • V = начальная скорость (> 0)
  • D = общее расстояние (> 0)

Мы ищем гладкую функцию v (t) (скорость как функция времени) такую, что:

  • v (0) = V
  • v (T) = 0
  • интеграл от 0 до T от v (t) dt равен D

С помощью (вогнутого) полинома второго порядка мы можем удовлетворить все три ограничения. Следовательно, пусть

v (t): = at ^ 2 + bt + c

и давайте решим для a, b, c. Первое ограничение v (0) = V дает сразу c = V. Второе ограничение гласит:

aT ^ 2 + bT + V = 0

С другой стороны, интеграл от v (t) равен d (t) = 1/3 при ^ 3 + 1/2 bt ^ 2 + Vt (это расстояние, пройденное до момента t), поэтому третье ограничение гласит

d (T) = 1/3 a T ^ 3 + 1/2 b T ^ 2 + VT = D

Последние два уравнения кажутся грязными, но они представляют собой просто два линейных уравнения с двумя неизвестными a, b, и они должны быть легко решаемыми. Если я сделал мои вычисления правильно, конечный результат будет

a = 3 В / Т ^ 2 - 6D / T ^ 3, b = 6 В / Т ^ 2 - 4 В / Т

Если вы подставите a, b, c в выражение d (t), вы получите пройденное расстояние как функцию времени.

1 голос
/ 01 апреля 2010

Я считаю, что вы хотите решить вашу проблему в 3 части.

Во-первых, вам нужно найти минимальную скорость, необходимую для преодоления расстояния во времени T.

Это было бы довольно просто (Д / т) = V (мин)

Предполагается мгновенное ускорение от v (начальное) до v (мин) и снова замедление в течение периода времени 0 с в начале и в конце.

так, например, скажем, ваш v (i) равен 5px / s. Вы хотите движение 100px в течение 10 секунд.

v (мин) = 100px / 10s = 10px / s

Во-вторых, вы хотите плавное ускорение от v (начальный) до v (мин). это займет некоторый период времени t (акк). Предполагая, что ускорение и замедление будут равны, тогда вы можете просто рассчитать для одного из них, а затем умножить на 2. Мы можем вызвать функцию, которая описывает расстояние, пройденное во время ускорения D (ускорение).

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

так что ваше уравнение для общего пройденного расстояния будет D (всего) = D (ускорение) + D (v (макс.))

Когда вы знаете, что D (accel) рассчитан на 2 с, вы можете вычислить

D (ускорение) = (V (ini) + V (max)) / 2) * (2 секунды)

и

D (v (max)) = V (max) * 8 с

Решая для V (max) мы получаем

100px = D (ускорение) + D (v (макс.))

100 пикселей = (5 пикселей / с + VMax) / 2 * (2 с)) + VMax * 8 с

100px = 5px + (Vmax * 1с) + Vmax * 8с

95px = 9Vmax * s

VMax = 95px / 9s

VMax = 10,556 пикселей / с

Теперь вы можете вернуться и заменить окно ускорения 1 с формулой, определяющей окно ускорения как% от общего периода времени или что-то другое.

Также обратите внимание, что в целях анимации вам придется разбивать 10,556 пикселей / с на пиксельные движения на кадр и учитывать время соответственно.

0 голосов
/ 27 апреля 2016

Решение Федерико хорошее, но я обнаружил, что ускорение линейного ускорения слишком резкое, и я закончил тем, что продвинулся вперед с решением с двумя параболами, где ускорение постоянное, сначала в одном направлении, а затем другой, пока объект не заканчивается в 1 со скоростью 0. (Я пытался решить его с переменными начала и конца, но это было слишком сложно. Вместо этого моя реализация просто масштабирует входы и выходы, прежде чем передать их через функцию.)

Математика была старшеклассницей, но я рассмотрю ее ради полноты.

учитывая v, начальную скорость, мы имеем две параболы, левую и правую

  • ly = m (t - ax) ^ 2 + ay, где t - ввод времени, в диапазоне от 0 до 1, а ax, ay и m - это константы, которые нам нужно найти, учитывая v.
  • ry = -m (t - 1) ^ 2 + 1

Обратите внимание, что они оба принимают m за крутизну, потому что они ускоряются с одинаковой скоростью. ry использует -m, потому что он ускоряется в другом направлении.

У нас есть ряд ограничений, которые нужно решить для

  • ly (0) = 0, значение равно 0 при t = 0
  • ly '(0) = v, дифференциал уравнения (скорость) равен v (заданная начальная скорость) при t = 0
  • ly (h) = ry (h), две параболы соединяются в некоторой заданной точке на полпути (которая на самом деле не находится на полпути, если v = 0)
  • ly '(h) = ry' (h), скорость в этой точке на полпути одинакова, внезапных рывков нет

С этого момента я прошел через несколько подходов, но, в конце концов, казалось, что единственным способом было решить для m в терминах v. Мы приходим к формуле mm + m (v - 2) - ( ст) / 4. Применяя квадратную формулу, получаем m = ((2 - v) ± sqrt (2vv - 4v + 4)) / 2 Это означает, что либо

m = ((2 - v) + sqrt (2v * v - 4v + 4)) / 2

или

m = ((2 - v) - sqrt (2v * v - 4v + 4)) / 2

И мы находим, что можем решить, что это, посмотрев на начальную скорость,

let sqrt_part = Math.sqrt(2*sq(initial_velocity) - 4*initial_velocity + 4)
let m = (2 - initial_velocity + (initial_velocity < 2 ? sqrt_part : -sqrt_part))/2

оттуда остальные переменные (ax, ay и h) довольно легко определить.

Здесь реализована формула ржавчины https://gist.github.com/makoConstruct/df173c3a4e0854b535869fdc2acdeeb1

Синтаксис Rust довольно обычный, поэтому у вас не будет особых проблем с переводом этого в JS. Не стесняйтесь размещать свой порт в комментариях.

0 голосов
/ 01 апреля 2010

abustin, так как вам не нравится 3-сегментное решение, вы можете попробовать кривые Безье , чтобы решить эту проблему.Кривая Безье может быть использована для интерполяции времени и расстояния, поэтому вы можете определить несколько контрольных точек вблизи концов вашего движения для генерации ускорения, где средний «сегмент» будет определен так, что скорость будет близка к постоянной.Использование сплайнов также возможно.

0 голосов
/ 01 апреля 2010

Использование постоянных ускорений:

Определения:

Vi - Initial velocity
Va - Average velocity
Vo - Ending velocity
D  - Total distance to be traveled
T  - Total time for travel
t1 - Acceleration time from beginning to Va
t2 - Acceleration time from Va to Vo

Уравнение, которое нужно решить:

(Vi+Va)/2*t1 + Va*(T-t2-t1) + (Va+Vo)/2*t2 = D

Вы должны решить, сколько времени занимает начальное ускорение (t1) и окончательное ускорение (t2), и тогда у вас остается только одно неизвестное -> Va, которое можно легко решить.

РЕДАКТИРОВАТЬ : найти расстояние как функцию времени:

Ну, теперь, когда вы знаете скорости, легко вычислить пройденное расстояние:

D(t) = Vi*t + 0.5*t^2*(Va-Vi)/t1                {0<t<t1}
D(t) = Va*(t-t1) + D1                           {t1<t<t3}
D(t) = Va*(t-t3)+0.5*(t-t3)^2*(Vo-Va)/t2 + D2   {t3<t<T}

где t3 = (T-t2), D1 и D2 - расстояние, пройденное в конце первого и второго сегментов, которое можно найти по соответствующим функциям:

D1 = 0.5*(Va+Vi)*t1
D2 = D1 + Va*(t3-t1)

РЕДАКТИРОВАТЬ 2 : Решение для Va:

(Vi+Va)/2*t1 + Va*(T-t2-t1) + (Va+Vo)/2*t2 = D

Помните, что t1 и t2 - это параметры задачи, которые вы выбираете. Вы сами решаете, какую часть движения объект ускоряет и замедляет. Допустим, t1 = t2 = 0,1 * T. Замена тогда дает:

(Vi+Va)/2*(0.1T) + Va*(T-(0.1T)-(0.1T)) + (Va+Vo)/2*(0.1T) = D
Va*(0.1T/2 + T-0.1T-0.1T + 0.1T/2) + Vi*(0.1T)/2 + Vo*(0.1T)/2 = D
Va*(0.9T) + Vi*(0.05T) + Vo*(0.05T) = D
Va*(0.9T) = D - Vi*(0.05T) + Vo*(0.05T)
Va = (D - (Vi + Vo)*(0.05T)) / (0.9T)

Понял?

...