3d - simulacion - tutorial metodo montecarlo
DistribuciĆ³n uniforme aleatoria(Monte-Carlo) en la esfera de la unidad (6)
Necesito una aclaración con algoritmo que genere valores aleatorios para mi rastreador de rayos de mascota.
Emite rayos desde un punto. Y tengo el problema con la distribución de estos rayos: necesito que la distribución sea uniforme, pero no es ...
El problema al que me enfrento ahora es que la distribución que es uniforme inicialmente no es uniforme después de mis distorsiones del espacio de resultados.
Entonces, por ejemplo, genero ángulos r y t si el sistema de coordenadas polares. La distribución no es uniforme y no puede ser uniforme: el espacio cerca de cada polo tiene una densidad de resultados mucho mayor que, por ejemplo, cerca del ecuador. La razón es bastante clara: convierto puntos distribuidos uniformemente del espacio cilíndrico al esférico. Y yo distorsiono los resultados. El mismo problema es si normalizo los puntos generados aleatoriamente en el cubo.
Mi idea ahora es la siguiente: quiero crear un tetraedro, normalizar sus vértices, dividir cada cara (triángulo) con el punto en el medio, normalizarla y repetir recursivamente hasta que tenga suficientes puntos. Luego "distorsiono" estos puntos un poco. Luego los normalizo de nuevo. Eso es.
Entiendo que este método no es puro método matemático de Monte-Carlo, porque no uso la distribución aleatoria en ningún paso, excepto en el último. Y no me gusta esta solución para esta complejidad.
¿Alguien puede sugerir algo más simple y aún así
- aleatorio
- uniforme
- rápido
- sencillo
¡Gracias!
EDITAR:
Necesito un método rápido, no solo el correcto. Es por eso que estoy preguntando por Montecarlo. Las respuestas proporcionadas son correctas, pero no rápidas. El método con tetraedro es rápido, pero no muy "aleatorio" => incorrecto.
Realmente necesito algo más adecuado.
No estoy seguro de si esto tiene algún sentido, pero aquí tienes:
Parte fraccional uniforme: un método simple rápido para generar variaciones aleatorias continuas
Para las secciones esféricas genere su ángulo de manera uniforme en phi
(el ángulo polar) y cos(theta)
(para theta el ángulo azimutal) entre sus límites.
En pseudo código:
phi = phi_low_limit + rand()*(phi_high_limit - phi_low_limit)
ct = cos(theta_high_limit) + rand()*(cos(theta_low_limit) - cos(theta_high_limit))
// The order is inverted here because cos heads down for increasing theta
theta = arccos(ct)
Este es un caso especial de la regla que dice invertir el jacobiano y generar uniformemente en ese espacio de esas coordenadas.
Nota: Tenga en cuenta que estoy usando la convención opuesta para phi y theta de la línea de David Norman.
Tenga en cuenta también: Este no es realmente el método más rápido, sino más bien uno que ilustra el principio general.
Aquí hay un algoritmo que le permite generar puntos distribuidos aleatoriamente en la esfera de la unidad.
A menos que estés trazado de rayos solo en escenas triviales, ¿tu tiempo de renderización estará dominado por el tiempo de recolección de muestras? Si no, probablemente aún no valga la pena optimizarlo, aunque vale la pena leer y comprender las técnicas uniformes de muestreo que se dan en las otras respuestas.
Además, sus muestras no necesitan ser muy aleatorias para producir una buena estimación de la función que está muestreando. Es posible que desee investigar el uso de una secuencia de números cuasialeatorios, como la secuencia de Halton . Su idea de subdivisión tetraedro no está mal. Debería tener como resultado buenos puntos bien distribuidos que deberían ser mejores que las muestras pseudoaleatorias uniformes para la mayoría de las escenas, aunque podría dar lugar a artefactos horripilantes en algunas circunstancias.
De todos modos, realmente deberías consultar los foros en ompf.org. Tengo algunos nerds super rastreadores de rayos por allá.
Aquí hay una implementación de Java que he usado en el pasado:
public static double[] randomPointOnSphere(Random rnd)
{
double x, y, z, d2;
do {
x = rnd.nextGaussian();
y = rnd.nextGaussian();
z = rnd.nextGaussian();
d2 = x*x + y*y + z*z;
} while (d2 <= Double.MIN_NORMAL);
double s = Math.sqrt(1.0 / d2);
return new double[] {x*s, y*s, z*s};
}
¿Realmente necesitas una distribución aleatoria o una distribución uniforme en la esfera?
Luego sugeriría los ángulos ZCW, que se distribuyen por igual en toda la esfera y son rápidos de calcular. Otros métodos son TheSydneyOperaHouse (SOPHE) y Repulsion. (buscar repulsion.c) El método de repulsión es bastante bueno pero lento: distribuye puntos de manera uniforme sobre una esfera. Afortunadamente tiene que hacerse solo una vez.
Esto se usa en cristalografía y RMN, porque para los patrones de polvo es más rápido usar una distribución uniforme versus distribución aleatoria (necesita menos puntos).
Aquí hay una implementación de Python para ZCW.
Más detalles en estos documentos:
Investigaciones de un método numérico no aleatorio para la integración multidimensional , Cheng, Vera B. y Henry H. Suzukawa, Jr. y Wolfsberg, Max
Simulaciones de computadora en RMN de estado sólido. III. Promediado en polvo , Matthias Edén