Подтвердить что ты не робот

Math: Ease In, ease Извлечение смещения с использованием кривой Эрмита с временным ограничением

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

double Interpolate(
    double timeToAccel, double timeCruising, double timeToDecel,
    double finalPosition,
    double currentTime)
{
    //...
}

Может кто-то указать мне на часть кода, которая это делает? Я не знаю, как интегрировать кривую Эрмита, поэтому не знаю, сколько я буду двигаться в ускоряющей части или в замедляющей части, и в свою очередь я не могу понять, какая будет скорость в линейной часть.

Спасибо.

Некоторая ссылка, чтобы проиллюстрировать мой вопрос.

Edit:

  • начальная и конечная скорости равны нулю, а текущее время также является частью параметров в методе, я обновил подпись.
  • В принципе идея состоит в том, чтобы представить движение с постоянной скоростью на расстоянии d, что дает общую продолжительность. Затем мы добавляем фазы ускорения и замедления, сохраняя при этом одну и ту же продолжительность, поэтому у нас есть неизвестная новая скорость круиза для определения (потому что мы меньше двигаемся в фазах Эрмита, чем в линейных фазах, которые они заменили). Возможно, количество перемещений, потерянных в фазах Эрмита, по сравнению с линейным движением одной и той же продолжительности - это соотношение между верхней и нижней областью кривых, просто идея от эксперта.

Изменить: Roman и Bob10 предоставили полные рабочие решения. Я реализовал код от Романа. Спасибо вам, ребята! Я ценю вашу прекрасную поддержку и ваши подробные решения, вы сохранили мне долгие поиски и испытания.

4b9b3361

Ответ 1

Сначала сделаем кубическую гермитовую сплайн-функцию:

/*
  t  - in interval <0..1>
  p0 - Start position
  p1 - End position
  m0 - Start tangent
  m1 - End tangent
*/
double CubicHermite(double t, double p0, double p1, double m0, double m1) {
   t2 = t*t;
   t3 = t2*t;
   return (2*t3 - 3*t2 + 1)*p0 + (t3-2*t2+t)*m0 + (-2*t3+3*t2)*p1 + (t3-t2)*m1;
}

Теперь ваша задача - рассчитать p0, p1, m0 и m1 для разделов как для облегчения, так и для облегчения. Добавим несколько переменных, чтобы сделать математику немного легче написать:

double Interpolate(
    double timeToAccel, double timeCruising, double timeToDecel,
    double finalPosition,
    double currentTime) {

    double t1 = timeToAccel;
    double t2 = timeCruising;
    double t3 = timeToDecel;
    double x = finalPosition;
    double t = currentTime;

Нам нужно указать, где должен находиться объект, когда он перестает ускоряться и начинает замедляться. Вы можете указать их, но, тем не менее, вы все равно произведите плавное движение, однако нам нужно несколько "естественное" решение.

Предположим, что крейсерская скорость v. Во время сверления объект перемещается на расстояние x2 = v * t2. Теперь, когда объект ускоряется от 0 до скорости v, он перемещается на расстояние x1 = v * t1 / 2. То же самое для замедления x3 = v * t3 / 2. Все вместе:

x1 + x2 + x3 = x

v * t1/2 + v * t2 + v * t3/2 = x

Из этого мы можем рассчитать нашу скорость и расстояния:

    double v = x / (t1/2 + t2 + t3/2);
    double x1 = v * t1 / 2;
    double x2 = v * t2;
    double x3 = v * t3 / 2;

И теперь, когда мы все знаем, мы просто кормим его в наш кубический гермитовый сплайн-интерполятор

    if(t <= t1) {
       // Acceleration
       return CubicHermite(t/t1, 0, x1, 0, v*t1);
    } else if(t <= t1+t2) {
       // Cruising
       return x1 + x2 * (t-t1) / t2;
    } else {
       // Deceleration
       return CubicHermite((t-t1-t2)/t3, x1+x2, x, v*t3, 0);
    }
}

Я тестировал это в Excel, здесь эквивалентный код VBA для воспроизведения. Для граничных условий есть некоторые деления на ноль, я оставляю это исправление как упражнение для читателя


Public Function CubicHermite(t As Double, p0 As Double, p1 As Double, _
m0 As Double, m1 As Double) As Double
   t2 = t * t
   t3 = t2 * t
   CubicHermite = (2 * t3 - 3 * t2 + 1) * p0 + _
(t3 - 2 * t2 + t) * m0 + (-2 * t3 + 3 * t2) * p1 + (t3 - t2) * m1
End Function

Public Function Interpolate(t1 As Double, t2 As Double, t3 As Double, _
x As Double, t As Double) As Double
    Dim x1 As Double, x2 As Double, x3 As Double

    v = x / (t1 / 2 + t2 + t3 / 2)
    x1 = v * t1 / 2
    x2 = v * t2
    x3 = v * t3 / 2

    If (t <= t1) Then
       Interpolate = CubicHermite(t / t1, 0, x1, 0, v*t1)
    ElseIf t <= t1 + t2 Then
       Interpolate = x1 + x2 * (t - t1) / t2
    Else
       Interpolate = CubicHermite((t-t1-t2)/t3, x1+x2, x, v*t3, 0)
    End If
End Function

Ответ 2

Это простое использование с обычным постоянным ускорением. Тогда возникает вопрос, какую скорость (v) вам нужно ускорить, чтобы завершить поездку в нужное время, и это скажет вам ускорение, необходимое для достижения этой скорости.

Если общее время t_t и время ускорения t_a, то вы пройдете расстояние как две ускоряющие и замедляющие части и часть постоянной скорости:

x = 2*(a*t_a*t_a/2) + v*(t_t-2*t_a)

Это можно решить для ускорения, подбирая в v = a * t_a, чтобы найти

a = x/(t_a*(t_t - t_a))

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

from pylab import *

t_a, t_t, D = 3., 10., 1.  # input values

a = D/(t_a*(t_t - t_a))
segments = (t_a, a), (t_t-2*t_a, 0.), (t_a, -a)  # durations and accelerations for each segment

t0, x0, v0 = 0.0, 0.0, 0.0  #initial values for the segment
tdata, xdata = [], []
for t_segment, a in segments: # loop over the three segments
    times = arange(0, t_segment, .01)
    x = x0 + v0*times + .5*a*times*times
    xdata.append(x)
    tdata.append(times+t0)
    x0 = x[-1] # the last x calculated in the segment above
    v0 += a*t_segment
    t0 += t_segment

plot(tdata[0], xdata[0], 'r', tdata[1], xdata[1], 'r', tdata[2], xdata[2], 'r')
xlabel("time")
ylabel("position")
show()

alt text http://i26.tinypic.com/34sqzpi.png