Насколько я понимаю, функция Lerp интерполирует между двумя значениями ( a
и b
), используя третье значение ( t
) между 0
и 1
. At t = 0
, значение a возвращается, at t = 1
, значение b
возвращается. На 0,5 значение на полпути между a
и b
возвращается.
(Следующая картинка - плавный шаг, обычно кубическая интерполяция)
Я просматривал форумы и в этом ответе нашел следующую строку кода:transform.rotation = Quaternion.Slerp(transform.rotation, _lookRotation, Time.deltaTime);
Я подумал про себя: «Что за дурак, он понятия не имеет», но поскольку у него было более 40 голосов, я попробовал и, конечно же, это сработало!
float t = Time.deltaTime;
transform.rotation = Quaternion.Slerp(transform.rotation, toRotation, t);
Debug.Log(t);
Я получил случайные значения между 0.01
и 0.02
для t
. Разве функция не должна интерполировать соответственно? Почему эти значения складываются? Что такого в lerp, что я не понимаю?
источник
Ответы:
Смотрите также этот ответ .
Есть два распространенных способа использования
Lerp
:1. Линейное смешивание между началом и концом
Это версия, с которой вы, вероятно, больше всего знакомы.
2. Экспоненциальная легкость по отношению к цели
Обратите внимание, что в этой версии
current
значение отображается как выход и вход. Она смещаетstart
переменную, поэтому мы всегда начинаем с того места, куда переместились при последнем обновлении. Это то, что дает этой версииLerp
памяти от одного кадра к другому. Из этой движущейся начальной точки мы затем перемещаем часть расстояния в направлении,target
определяемомsharpness
параметром.Этот параметр больше не является «скоростью», потому что мы приближаемся к цели в стиле Zeno . Если бы
sharpnessPerTick
были0.5
, то при первом обновлении мы бы пошли на полпути к нашей цели. Затем в следующем обновлении мы переместим половину оставшегося расстояния (то есть четверть нашего начального расстояния). Тогда на следующем мы двинулись бы снова наполовину ...Это дает «экспоненциальное замедление», когда движение происходит быстро, когда оно далеко от цели, и постепенно замедляется по мере асимптотического приближения (хотя с числами бесконечной точности оно никогда не достигнет его в любом конечном количестве обновлений - для наших целей это подбирается достаточно близко). Это отлично подходит для погони за движущимся целевым значением или для сглаживания шумового ввода с использованием « экспоненциального скользящего среднего », обычно с использованием очень маленького
sharpnessPerTick
параметра, например0.1
или меньше.Но вы правы, есть ошибка в ответе, на который вы ответили. Это не
deltaTime
правильно для правильного пути. Это очень распространенная ошибка при использовании этого стиляLerp
.Первый стиль
Lerp
линейный, поэтому мы можем линейно регулировать скорость, умножая наdeltaTime
:Но наше экспоненциальное ослабление нелинейно , поэтому умножение нашего
sharpness
параметра наdeltaTime
не даст правильной коррекции времени. Это будет проявляться как дрожь в движении, если наша частота кадров колеблется, или изменение резкости ослабления, если вы последовательно переходите от 30 до 60.Вместо этого нам нужно применить экспоненциальную коррекцию для нашей экспоненциальной простоты:
Вот
referenceFramerate
только константа, как30
сохранить единицы дляsharpness
того же, что мы использовали, прежде чем исправлять на время.В этом коде есть еще одна спорная ошибка
Slerp
- сферическая линейная интерполяция полезна, когда мы хотим точно одинаковую скорость вращения на протяжении всего движения. Но если мы все равно будем использовать нелинейную экспоненциальную простоту,Lerp
это даст почти неразличимый результат и будет дешевле. ;) Кватернионы выглядят гораздо лучше, чем матрицы, поэтому обычно это безопасная замена.источник
Я думаю, что основная концепция отсутствует в этом сценарии А не является фиксированной. A обновляется с каждым шагом, насколько бы ни была интерполяция Time.deltaTime.
Таким образом, когда A становится ближе к B с каждым шагом, общее пространство интерполяции меняется с каждым вызовом Lerp / Slerp. Не занимаясь реальной математикой, я подозреваю, что эффект не такой же, как ваш график Smoothstep, но это дешевый способ приблизить замедление, когда A приближается к B.
Кроме того, это часто используется, потому что B также не может быть статическим. Типичным случаем может быть камера, следующая за игроком. Вы хотите избежать рывков, заставив камеру перейти на локацию или вращение.
источник
Вы правы, метод
Quaternion Slerp(Quaternion a, Quaternion b, float t)
интерполирует междуa
иb
по суммеt
. Но следите за первым значением, это не начальное значение.Здесь первое значение, данное методу, является текущим вращением объекта
transform.rotation
. Таким образом, для каждого кадра он интерполирует между текущим и целевым вращением_lookRotation
по величинеTime.deltaTime
.Вот почему он производит плавное вращение.
источник