No meu entender, uma função Lerp interpola entre dois valores ( a
e b
) usando um terceiro valor ( t
) entre 0
e 1
. Em t = 0
, o valor a é retornado, em t = 1
, o valor b
é retornado. Em 0,5, o valor entre a
e b
é retornado.
(A figura a seguir é uma etapa suave, geralmente uma interpolação cúbica)
Estive navegando nos fóruns e, nesta resposta , encontrei a seguinte linha de código:transform.rotation = Quaternion.Slerp(transform.rotation, _lookRotation, Time.deltaTime);
Pensei comigo mesmo: "que idiota, ele não tem idéia", mas como tinha mais de 40 votos positivos, tentei e, com certeza, funcionou!
float t = Time.deltaTime;
transform.rotation = Quaternion.Slerp(transform.rotation, toRotation, t);
Debug.Log(t);
Eu tenho valores aleatórios entre 0.01
e 0.02
para t
. A função não deve interpolar adequadamente? Por que esses valores são empilhados? O que há no lerp que eu não entendo?
fonte
Respostas:
Veja também esta resposta .
Existem duas maneiras comuns de usar
Lerp
:1. Mistura linear entre um começo e um fim
Esta é a versão com a qual você provavelmente está mais familiarizado.
2. Facilidade exponencial em direção a um alvo
Observe que nesta versão o
current
valor aparece como saída e como entrada. Ele desloca astart
variável, por isso estamos sempre começando de onde quer que nos mudemos na última atualização. É isso que fornece essa versão daLerp
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 umsharpness
parâmetro.Esse parâmetro não é mais uma "velocidade", porque nos aproximamos do alvo de maneira semelhante ao zeno . Se
sharpnessPerTick
fosse0.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 como0.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 deLerp
.O primeiro estilo de
Lerp
é linear, para que possamos ajustar linearmente a velocidade multiplicando pordeltaTime
:Mas nossa flexibilização exponencial é não linear , portanto, apenas a multiplicação de nosso
sharpness
parâmetro pordeltaTime
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:
Aqui
referenceFramerate
está apenas uma constante30
para manter as unidadessharpness
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.fonte
Eu acho que o conceito principal que falta seria neste cenário A não é fixo. A é atualizado a cada etapa, no entanto, ao longo da interpolação que Time.deltaTime é.
Portanto, com A se aproximando de B a cada etapa, o espaço total da interpolação muda a cada chamada Lerp / Slerp. Sem fazer as contas reais, eu suspeitaria que o efeito não é o mesmo que o gráfico Smoothstep, mas é uma maneira barata de aproximar uma desaceleração quando A se aproxima de B.
Além disso, isso é frequentemente usado porque B também pode não ser estático. Caso típico pode ser uma câmera seguindo um jogador. Você deseja evitar instabilidade, fazendo a câmera pular para um local ou rotação.
fonte
Você está certo, o método
Quaternion Slerp(Quaternion a, Quaternion b, float t)
interpola entrea
eb
pela quantidadet
. Mas observe o primeiro valor, não é o valor inicial.Aqui, o primeiro valor dado ao método é a rotação atual do objeto
transform.rotation
. Portanto, para cada quadro, ele interpola entre a rotação atual e a rotação alvo_lookRotation
pela quantidadeTime.deltaTime
.É por isso que produz uma rotação suave.
fonte