Veja também esta resposta .
Existem duas maneiras comuns de usar Lerp
:
1. Mistura linear entre um começo e um fim
progress = Mathf.Clamp01(progress + speedPerTick);
current = Mathf.Lerp(start, end, progress);
Esta é a versão com a qual você provavelmente está mais familiarizado.
2. Facilidade exponencial em direção a um alvo
current = Mathf.Lerp(current, target, sharpnessPerTick);
Observe que nesta versão o current
valor aparece como saída e como entrada. Ele desloca a start
variável, por isso estamos sempre começando de onde quer que nos mudemos na última atualização. É isso que fornece essa versão da Lerp
memória de um quadro para o outro. A partir deste ponto inicial em movimento, movemos então uma fração da distância em direção à target
ditada por um sharpness
parâmetro.
Esse parâmetro não é mais uma "velocidade", porque nos aproximamos do alvo de maneira semelhante ao zeno . Se sharpnessPerTick
fosse 0.5
, na primeira atualização nos moveríamos a meio caminho do nosso objetivo. Na próxima atualização, moveríamos metade da distância restante (portanto, um quarto da nossa distância inicial). Então, no próximo, nos moveríamos pela metade novamente ...
Isso proporciona uma "facilidade exponencial", onde o movimento é rápido quando está longe do alvo e diminui gradualmente à medida que se aproxima assintoticamente (embora com números de precisão infinita nunca o alcance em um número finito de atualizações - para nossos propósitos, fica perto o suficiente). É ótimo para perseguir um valor-alvo móvel ou suavizar uma entrada barulhenta usando uma " média móvel exponencial ", geralmente usando um sharpnessPerTick
parâmetro muito pequeno como 0.1
ou menor.
Mas você está certo, há um erro na resposta votada que você vincula. Não está corrigindo deltaTime
o caminho certo. Este é um erro muito comum ao usar esse estilo de Lerp
.
O primeiro estilo de Lerp
é linear, para que possamos ajustar linearmente a velocidade multiplicando por deltaTime
:
progress = Mathf.Clamp01(progress + speedPerSecond * Time.deltaTime);
// or progress = Mathf.Clamp01(progress + Time.deltaTime / durationSeconds);
current = Mathf.Lerp(start, end, progress);
Mas nossa flexibilização exponencial é não linear , portanto, apenas a multiplicação de nosso sharpness
parâmetro por deltaTime
não dará a correção correta do tempo. Isso aparecerá como uma trepidação no movimento, se a taxa de quadros flutuar, ou uma alteração na nitidez da flexibilização, se você passar de 30 para 60 de forma consistente.
Em vez disso, precisamos aplicar uma correção exponencial para nossa facilidade exponencial:
blend = 1f - Mathf.Pow(1f - sharpness, Time.deltaTime * referenceFramerate);
current = Mathf.Lerp(current, target, blend);
Aqui referenceFramerate
está apenas uma constante 30
para manter as unidades sharpness
da mesma forma que estávamos usando antes de corrigir o tempo.
Há um outro erro discutível nesse código, que está usando Slerp
- a interpolação linear esférica é útil quando queremos uma taxa de rotação exatamente consistente por todo o movimento. Mas se usarmos uma facilidade exponencial não linear de qualquer maneira, Lerp
forneceremos um resultado quase indistinguível e é mais barato. ;) Os quaternions lerp são muito melhores que as matrizes, por isso geralmente é uma substituição segura.