Es posible aproximar una solución a este problema para la mayoría de las trayectorias paramétricas. La idea es la siguiente: si hace un zoom lo suficientemente profundo en una curva, no puede distinguir la curva en sí de su tangente en ese punto.
Al hacer esta suposición, no es necesario calcular previamente nada más que dos vectores (tres para curvas de Bezier cúbicas, etc. ).
Entonces, para una curva calculamos su vector tangente en el punto . La norma de este vector es y, por lo tanto, la distancia recorrida durante una duración puede aproximarse como . Se deduce que se recorre una distancia durante un tiempo .METRO( t )reMETROrett∥ dMETROreT∥Δ t∥ dMETROreT∥ Δ tLL ÷ ∥ dMETROreT∥
Aplicación: curva de Bezier cuadrática
Si los puntos de control de la curva de Bezier son , y , la trayectoria se puede expresar como:UNAsido
METRO( t )= ( 1 - t )2A + 2 t ( 1 - t ) B + t2do= t2( A - 2 B + C) + t ( - 2 A + 2 B ) + A
Entonces la derivada es:
reMETROret= t ( 2 A - 4 B + 2 C) + ( - 2 A + 2 B )
Solo necesita almacenar los vectores y alguna parte. Luego, para una determinada , si desea avanzar una longitud , debe:v⃗ 1=2A−4B+2Cv⃗ 2= - 2 A + 2BtL
t = t + Ll e n gt h ( t ⋅ v⃗ 1+ v⃗ 2)
Curvas de Bezier cúbico
El mismo razonamiento se aplica a una curva con cuatro puntos de control , , y :UNAsidore
METRO( t )= ( 1 - t )3A + 3 t ( 1 - t )2B + 3 t2( 1 - t ) C+ t3re= t3( - A + 3 B - 3 C+ D ) + t2( 3 A - 6 B + 3 C) + t ( - 3 A + 3 B ) + A
La derivada es:
reMETROret= t2( - 3 A + 9 B - 9 C+3D)+t(6A−12B+6C)+(−3A+3B)
Calculamos previamente los tres vectores:
v⃗ 1v⃗ 2v⃗ 3=−3A+9B−9C+3D=6A−12B+6C=−3A+3B
y la fórmula final es:
t=t+Llength(t2⋅v⃗ 1+t⋅v⃗ 2+v⃗ 3)
Problemas de precisión
Si está ejecutando a una velocidad de cuadro razonable, (que debe calcularse de acuerdo con la duración del cuadro) será lo suficientemente pequeño para que la aproximación funcione.L
Sin embargo, puede experimentar imprecisiones en casos extremos. Si es demasiado grande, puede hacer el cálculo por partes, por ejemplo, utilizando 10 partes:L
for (int i = 0; i < 10; i++)
t = t + (L / 10) / length(t * v1 + v2);
L
es suficientemente pequeño, esta aproximación siempre es más precisa que la respuesta a continuación, sí. También usa menos memoria (porque usa la derivada en lugar de almacenar todos los valores de puntos). CuandoL
comience a crecer, puede usar la técnica que sugiero al final.Necesita volver a dibujar la curva. La forma más fácil de hacer esto es calcular las longitudes de arco de varios segmentos de la curva y usarlas para determinar de dónde debe tomar muestras. Por ejemplo, tal vez en t = 0.5 (a mitad de camino), debe pasar s = 0.7 a la curva para obtener la posición "a mitad de camino". Necesita hacer una lista de longitudes de arco de varios segmentos de curva para hacer esto.
Probablemente hay mejores formas, pero aquí hay un código C # muy simple que escribí para hacer esto en mi juego. Debería ser fácil portar al objetivo C:
Editar: Vale la pena señalar que esto no le dará la longitud exacta del arco, ya que es imposible obtener la longitud del arco de una curva cúbica. Todo lo que hace es estimar la longitud de los diversos segmentos. Según la longitud de la curva, es posible que deba aumentar la resolución para evitar que cambie de velocidad cuando llegue a un nuevo segmento. Usualmente uso ~ 100, con el que nunca he tenido problemas.
fuente
Una solución muy ligera es aproximar la velocidad en lugar de aproximar la curva. En realidad, este enfoque es independiente de la función de curva y le permite usar cualquier curva exacta en lugar de usar derivadas o aproximaciones.
Aquí está el código para C # Unity 3D:
Aunque la solución es independiente de la función de curva, quería señalarla aquí, ya que también estaba buscando cómo lograr una velocidad constante en una curva de Bezier, y luego se me ocurrió esta solución. Teniendo en cuenta la popularidad de la función, esto puede ser útil aquí.
fuente
No sé nada acerca de cocos2, pero una curva bezier es una especie de ecuación paramétrica, por lo que debería poder obtener sus valores x e y en términos de tiempo.
fuente