Me gustaría que una función anime un objeto que se mueve del punto A al punto B con el tiempo, de modo que llegue a B en un momento fijo, pero su posición en cualquier momento se perturba aleatoriamente de manera continua, pero nunca retrocede. Los objetos se mueven a lo largo de líneas rectas, por lo que solo necesito una dimensión.
Matemáticamente, eso significa que estoy buscando algunos f (x), x ∈ [0,1] continuos, de modo que:
- f (0) = 0
- f (1) = 1
- x <y → f (x) ≤ f (y)
- En "la mayoría" de los puntos f (x + d) - f (x) no tiene ninguna relación obvia con d. (La función no aumenta uniformemente ni es predecible; creo que eso también es equivalente a decir que ningún grado de derivada es una constante).
Idealmente, en realidad me gustaría tener alguna forma de tener una familia de estas funciones, proporcionando un estado de semilla. Necesitaría al menos 4 bits de semilla (16 funciones posibles), para mi uso actual, pero dado que no es mucho, siéntase libre de proporcionar aún más.
Para evitar varios problemas con los errores de acumulación, prefiero que la función no requiera ningún tipo de estado interno. Es decir, quiero que sea una función real, no una "función" de programación.
f'(x)>0
, por lo que la integración normalizada del valor absoluto de cualquier función de ruido cumplirá todos sus requisitos. Lamentablemente, no conozco ninguna forma fácil de calcular eso, pero tal vez alguien más sí. :)Respuestas:
Para esta publicación, y = f (t) donde t es el parámetro que usted varía (tiempo / progreso) e y es la distancia al objetivo. Así que hablaré en términos de puntos en diagramas 2D donde el eje horizontal es tiempo / progreso y el vertical es distancia.
Creo que puedes hacer una curva de Bezier cúbica con el primer punto en (0, 1) y el cuarto (último) punto en (1, 0). Los dos puntos medios se pueden colocar aleatoriamente (x = rand, y = rand) dentro de este rectángulo 1 por 1. No puedo verificar esto analíticamente, pero solo jugando con un applet (sí, adelante y riéndose) parece que la curva de Bezier nunca disminuirá con tal restricción.
Esta será su función elemental b (p1, p2) que proporciona una ruta no decreciente desde el punto p1 hasta el punto p2.
Ahora puede generar ab (p (1) = (0, 1), p (n) = (1, 0)) y elegir un número de p (i) a lo largo de esta curva de manera que 1
Esencialmente, está generando una ruta "general", y luego la divide en segmentos y regenera cada segmento.
Como desea una función matemática: Suponga que el procedimiento anterior está empaquetado en una función y = f (t, s) que le da la distancia en t para la función de la semilla s. Necesitará:
Por lo tanto, cada semilla debe suministrar uno de los siguientes:
Me imagino que puede lograr cualquiera de estos simplemente suministrando una serie de números como la semilla s. Alternativamente, podría hacer algo como suministrar un número s como semilla, y luego llamar al generador de números aleatorios incorporado con rand (s), rand (s + 1), rand (s + 2) y así sucesivamente (o inicializar con sy luego sigue llamando a rand.NextNumber).
Tenga en cuenta que aunque toda la función f (t, s) esté compuesta por muchos segmentos, solo está evaluando un segmento para cada t. Usted tendrá que calcular repetidamente los límites de los segmentos con este método, ya que tendrá que ordenarlos para asegurarse de que no hay dos segmentos se superponen. Probablemente pueda optimizar y deshacerse de este trabajo adicional y solo encontrar los puntos finales de un segmento para cada llamada, pero no es obvio para mí en este momento.
Además, las curvas de Bezier no son necesarias, cualquier spline que se comporte adecuadamente servirá.
Creé una implementación de muestra de Matlab.
La función Bezier (vectorizada):
La función de Bezier compuesta descrita anteriormente (se dejó deliberadamente sin vectorizar para dejar en claro cuánta evaluación se necesita para cada llamada):
El script que traza la función para una semilla aleatoria (tenga en cuenta que este es el único lugar donde se llama una función aleatoria, las variables aleatorias a todos los demás códigos se propagan desde esta matriz aleatoria):
Aquí hay una muestra de salida:
Parece cumplir con la mayoría de sus criterios. Sin embargo:
fuente
Supongo que en lugar de mezclar un montón de cosenos transformados (como los productos de punto en el ruido perlin te dan), podrías combinar varias funciones monotónicas que comienzan en f (0) = 0, como f (x) = x, o 2x, o x ^ 2, etc. De hecho, dado que su dominio está limitado a 0 => 1, también puede combinar funciones trigonométricas que se ajusten a la factura dentro de ese dominio como cos (90 * x + 270). Para normalizar sus métodos para terminar en 1, simplemente puede dividir la suma ponderada de estos métodos monotónicos comenzando en f (0) = 0 por f (1). Algo como esto también debería ser bastante fácil de invertir (lo que creo que quiere del bit sobre funciones reales sin estado versus funciones de programación).
Espero que esto ayude.
fuente
Uno puede analizar esta imagen cruda. Puede terminar con una función que realiza su animación sobre la marcha, utilizando una función de rand uniforme. Sé que esta no es la fórmula matemática exacta, pero en realidad no hay una fórmula matemática para una función aleatoria, e incluso si hubiera una, estarías codificando mucho para lograr esto. Teniendo en cuenta que no especificó ninguna condición de suavidad, el perfil de velocidad es $ C ^ 0 $ continuo (pero como no se trata de robots, no debe preocuparse por los perfiles de aceleración discontinuos).
fuente
La forma habitual de generar una secuencia creciente de N números aleatorios a partir de [0,1] es generar N números aleatorios en cualquier rango, luego dividirlos por su suma total, luego sumar uno por uno para obtener el secuencia.
Esto puede extenderse a 2D generando estos valores para X e Y. Puede aumentar N para obtener la granularidad que desee.
En la respuesta similar de @teodron, usted citó preocupaciones de eficiencia con grandes escalas de tiempo. Sin saber el problema real que enfrenta, no puedo decir si esa preocupación es válida; pero otra opción sería generar un N pequeño y simplemente suavizar el resultado. Dependiendo de la aplicación, esto puede dar mejores resultados.
N = 100, sin suavizado
N = 15, con suavizado
fuente
Sugiero esta implementación inspirada en la suma de octavas encontradas en el ruido fractal, con un poco de culo barato revoloteando aquí y allá. Creo que es razonablemente rápido y se puede ajustar pidiendo menos octavas que las almacenadas en los parámetros con una pérdida de precisión de aproximadamente
1/2^octave
.Podrías verlo como una implementación por partes que solo requiere O (log (piezas)) . La matriz de parámetros se usa tanto para la posición de pivote de dividir y conquistar como para la distancia recorrida al alcanzar el pivote.
Podría hacerse más rápido calculando previamente las divisiones de coma flotante, a costa de almacenar el triple de información.
Este es un ejemplo rápido:
El ejemplo se obtuvo con el siguiente código:
fuente
Pensar en voz alta y admitir que el cálculo no es mi punto fuerte ... ¿acaso esto no es posible? Para evitar cualquier patrón obvio, el promedio de la función de ruido sobre cualquier cambio en x debe ser cercano a cero, y para garantizar la monotonicidad, la amplitud del ruido sobre ese cambio en x debe ser menor que el cambio en x, ya que cualquier amplitud mayor podría resultar en un valor más bajo en x 'en relación a x. Pero eso significaría que a medida que reduce dx hacia 0, dicha función también debe reducir dA (donde A es la amplitud) hacia cero, lo que significa que no obtendrá ninguna contribución de ninguna función de ruido compatible.
Me imagino que es posible formular una función que disminuya gradualmente la contribución del ruido a medida que x se acerca a 1, pero eso le dará una función curva que se desacelera a medida que x se acerca a 1, que no es lo que creo que desea.
fuente
g(x) = 1 - f(1 - x)
, que en cambio acelera a medida que x sale 0.