É possível aproximar uma solução para esse problema para a maioria das trajetórias paramétricas. A idéia é a seguinte: se você aplicar zoom suficientemente profundo em uma curva, não poderá distinguir a curva da tangente nesse ponto.
Ao fazer essa suposição, não há necessidade de precompor nada mais do que dois vetores (três para curvas de Bezier cúbicas etc. ).
Portanto, para uma curva , calculamos seu vetor tangente no ponto . A norma desse vetor é e, portanto, a distância percorrida por uma duração pode ser aproximada como . Segue-se que uma distância é percorrida por uma duração .M(t)dMdtt∥dMdT∥Δt∥dMdT∥ΔtLL÷∥dMdT∥
Aplicação: curva quadrática de Bezier
Se os pontos de controle da curva de Bezier são , e , a trajetória pode ser expressa como:ABC
M( T )= ( 1 - t )2A + 2 t ( 1 - t ) B + t2C= t2( A - 2 B + C) + t ( - 2 A + 2 B ) + A
Portanto, a derivada é:
dMdt= t ( 2 A - 4 B + 2 C) + ( - 2 A + 2 B )
Você só precisa armazenar vetores e algum lugar. Então, para um dado , se você quiser avançar um comprimento , faça:v⃗ 1= 2 A - 4 B + 2 Cv⃗ 2= - 2 A + 2 Bteu
t = t + Ll e n gt h ( t ⋅ v⃗ 1+ v⃗ 2)
Curvas cúbicas de Bezier
O mesmo raciocínio se aplica a uma curva com quatro pontos de controle , , e :UMABCD
M( T )= ( 1 - t )3A + 3 t ( 1 - t )2B + 3 t2( 1 - t ) C+ t3D= t3( - A + 3 B - 3 C+ D ) + t2( 3 A - 6 B + 3 C) + t ( - 3 A + 3 B ) + A
A derivada é:
dMdt= t2( - 3 A + 9 B - 9 C+ 3 D ) + t ( 6 A - 12 B + 6 C) + ( - 3 A + 3 B )
Pré-calculamos os três vetores:
v⃗ 1v⃗ 2v⃗ 3= - 3 A + 9 B - 9 C+ 3 D= 6 A - 12 B + 6 C= - 3 A + 3 B
e a fórmula final é:
t = t + Ll e n gt h ( t2⋅ v⃗ 1+ t ⋅ v⃗ 2+ v⃗ 3)
Problemas de precisão
Se você estiver executando em uma taxa de quadros razoável, (que deve ser calculado de acordo com a duração do quadro) será suficientemente pequeno para que a aproximação funcione.eu
No entanto, você pode enfrentar imprecisões em casos extremos. Se for muito grande, você poderá fazer o cálculo por partes, por exemplo, usando 10 partes:eu
for (int i = 0; i < 10; i++)
t = t + (L / 10) / length(t * v1 + v2);
L
é suficientemente pequena, essa aproximação é realmente sempre mais precisa do que a resposta abaixo, sim. Ele também usa menos memória (porque usa a derivada em vez de armazenar todos os valores de pontos). QuandoL
começar a crescer, você pode usar a técnica que sugiro no final.Você precisa reparamaterizar a curva. A maneira mais fácil de fazer isso é calcular os comprimentos do arco de vários segmentos da curva e usá-los para descobrir de onde você deve amostrar. Por exemplo, talvez em t = 0,5 (no meio do caminho), você deve passar s = 0,7 para a curva para obter a posição "no meio do caminho". Você precisa armazenar uma lista de comprimentos de arco de vários segmentos de curva para fazer isso.
Provavelmente existem maneiras melhores, mas aqui está um código C # muito simples que escrevi para fazer isso no meu jogo. Deve ser fácil portar para o Objetivo C:
Edit: Vale a pena notar que isso não fornecerá o comprimento exato do arco, pois é impossível obter o comprimento do arco de uma curva cúbica. Tudo o que isso faz é estimar o comprimento dos vários segmentos. Dependendo do comprimento da curva, pode ser necessário aumentar a resolução para impedir que ela mude de velocidade quando atingir um novo segmento. Eu costumo usar ~ 100, com o qual nunca tive problemas.
fonte
Uma solução muito leve é aproximar a velocidade em vez de aproximar a curva. Na verdade, essa abordagem é independente da função da curva e permite que você use qualquer curva exata em vez de usar derivadas ou aproximações.
Aqui está o código para o C # Unity 3D:
Embora a solução seja independente da função de curva, eu queria anotá-la aqui, pois também estava procurando como obter velocidade constante em uma curva de Bezier e, em seguida, forneço essa solução. Considerando a popularidade da função, isso pode ser útil aqui.
fonte
Eu não sei nada sobre cocos2, mas uma curva de bezier é um tipo de equação paramétrica, portanto, você poderá obter seus valores xey em termos de tempo.
fonte