Actualmente estoy trabajando en un programa que debería generar ruido aleatorio en una pantalla basada en las 'coordenadas' de un píxel. Las coordenadas deben tener el mismo color cada vez que reinicie el programa. Sin embargo, usando el util.Random de Java, los resultados que obtengo no son tan aleatorios como me gustaría:
Pensé que si usaba las coordenadas combinadas (como en un entero formado a partir de ambas coordenadas una al lado de la otra) cada coordenada tendría un número diferente. Al usar ese número como semilla, esperaba obtener un número aleatorio diferente para cada coordenada que se usaría para el valor rgb de esa coordenada.
Este es el código que usé:
public class Generate {
static Random Random;
public static int TileColor(int x, int y){
Random = new Random(Integer.valueOf(Integer.toString(x)+Integer.toString(y)));
int b = 1 + Random.nextInt(50);
int g = 1 + Random.nextInt(50);
int r = 1 + Random.nextInt(50);
int color = -Color.rgb888(r, g, b);
return color;
}
}
¿El patrón que crea el programa se debe a la forma en que funciona la función Aleatoria de Java o estoy haciendo algo mal? ¿Debería intentar un enfoque diferente?
Actualización: ahora intenté deshacerme de los problemas relacionados con la concatenación utilizando el siguiente código:
public static int TileColor(int x, int y){
Randomy = new Random(y);
Randomx = new Random(x);
Random = new Random(Integer.valueOf(Integer.toString(Randomx.nextInt(1234))+Integer.toString(Randomy.nextInt(1234))));
int b = 1 + Random.nextInt(100);
int g = 1 + Random.nextInt(100);
int r = 1 + Random.nextInt(100);
int color = -Color.rgb888(r, g, b);
return color;
}
De alguna manera, esto también proporcionó (en mi opinión) una imagen suficientemente aleatoria:
Sin embargo, este código se reinicia tres veces por píxel. Aunque esto no es un problema para mí en este momento, considero cambiar este código en caso de que necesite una mejor actuación más adelante.
Respuestas:
La
java.util.Random
clase de Java generalmente te proporciona secuencias de números pseudoaleatorios que son lo suficientemente buenos para usar en los juegos 1 . Sin embargo, esa característica solo se aplica a una secuencia de muestras múltiples basadas en una semilla. Cuando reinicializa el RNG con valores de semilla incrementales y solo mira el primer valor de cada secuencia, las características de aleatoriedad no serán tan buenas.Lo que podrías hacer en su lugar:
En lugar de usar un generador de números aleatorios, use una función de resumen de mensaje para convertir un par de coordenadas en un valor de color. El resultado de la mayoría de los MDF es lo suficientemente impredecible como para cumplir con la mayoría de las pruebas de aleatoriedad. La salida suele ser superior a los 24 bits que necesita para un valor RGB, pero truncarlos no suele ser un problema.
Para mejorar el rendimiento, puede combinar la generación de resumen de mensajes con fragmentos. Genere pequeños fragmentos de píxeles que sean lo suficientemente grandes como para utilizar la longitud total de una salida de su función de resumen.
1 cuando es absolutamente esencial que nadie pueda predecir el próximo número, use el más lento pero menos predecible
java.security.SecureRandom
fuente
En ese caso, querrás usar una función de ruido determinista como el ruido Perlin o el ruido simplex .
( Consulte esta pregunta para obtener más información sobre el ruido Perlin con algunas imágenes bonitas ) .
En su mayor parte, el uso de una función incorporada
random()
o similar le dará diferentes valores cada vez que ejecute el programa, ya que pueden usar el reloj como entrada o algún otro valor pseudoaleatorio.Otra opción es generar un "mapa de ruido" una vez, sin conexión, y luego usarlo como fuente de números aleatorios más adelante.
En su implementación, está concatenando las representaciones de cadena de x y
y
. Eso es malo, ya que no es único en todo el dominio. Por ejemplo,¡Buena suerte!
fuente
Veamos qué estás haciendo exactamente:
Todo esto suena bien, pero está recibiendo un patrón porque:
El píxel en 1,11 y el píxel en 11,1 tienen ambos el número 111, por lo que seguramente tendrán el mismo color.
Además, siempre que realice el ciclo de la misma manera, puede usar solo un generador, sin necesidad de usar uno para cada píxel. ¡Uno para toda la imagen servirá! Todavía habrá algún tipo de patrón debido a la seudoaleatoriedad. @David_Lively tiene razón sobre el uso de algún algoritmo de ruido, lo hará parecer más aleatorio.
fuente
Haga un generador de color, luego produzca sus colores para su mosaico. ¡Semilla solo una vez! No necesita sembrar más que eso, al menos por ficha.
Y el uso será como sigue:
Con esto, si no está satisfecho con el resultado, simplemente cambie la
Random
semilla. Además, solo tiene que almacenar / comunicar la semilla y los tamaños para que todos los clientes tengan la misma imagen.fuente
En lugar de usar Random, considere usar un resumen de hash como MD5. Proporciona un valor 'aleatorio' difícil de predecir basado en una determinada entrada, pero siempre el mismo valor para la misma entrada.
Ejemplo:
NOTA: No sé de dónde viene Color.rgb888 (..), así que no sé cuál es el rango permitido. Sin embargo, 0-255 es normal.
Mejoras a considerar:
fuente
Otros han señalado que una forma de obtener el comportamiento que desea es utilizar una función hash, también conocida como "función de resumen de mensajes". El problema es que a menudo se basan en algoritmos como MD5, que es criptográficamente seguro (es decir, muy, muy aleatorio) pero muy lento. Si utiliza una función hash criptográfica cada vez que necesita un píxel aleatorio, se encontrará con problemas de rendimiento bastante graves.
Sin embargo, hay funciones hash no criptográficas que pueden producir valores que son lo suficientemente aleatorios para su propósito y al mismo tiempo son rápidos. El que generalmente busco es murmurhash . No soy un usuario de Java, pero parece que hay al menos una implementación de Java disponible. Si descubre que realmente necesita que cada píxel se genere a partir de sus coordenadas, en lugar de generarlos todos a la vez y almacenarlos en una textura, entonces esta sería una buena manera de hacerlo.
fuente
Usaría un primer sobre 2000 (resolución típica máxima)
Esto minimizará (o eliminará semillas duplicadas)
fuente
Random
es lo suficientemente aleatorio Lo estás usando mal por dos razones principales.Integer.valueOf(Integer.toString(x)+Integer.toString(y))
entre los píxeles con los que está sembrando.Simplemente usaría alguna variación del siguiente código, donde puede elegir una función hash (no use Integer.getHashCode) de las respuestas en /programming/9624963/java-simplest-integer- picadillo
donde podría estar la función hash
fuente
Puede intentar usar la hora actual del sistema como una semilla como esta:
Esperemos que produzca un valor más aleatorio.
fuente
Aquí hay una función de sombreador estático de una línea que se me ocurrió: poltergeist (Noisy Ghost).
Toma una coordenada 2D y una semilla, y se procesa en tono monótono según lo solicitado. Se ejecuta en fps en tiempo real, independientemente de la resolución de la pantalla. Para eso están las GPU.
Cualquier resolución, cualquier textura, en cualquier dispositivo (también móvil) compatible con GL (que es prácticamente cualquier con una pantalla).
¡Véalo corriendo aquí, ahora mismo!
https://www.shadertoy.com/view/ltB3zD
Puede incluir fácilmente este sombreador en su programa java usando opengl estándar, o en cualquier navegador usando webgl estándar.
Solo por diversión, tiro el guante para que cualquiera pueda vencer a Poltergeist en calidad y rendimiento en todos los dispositivos. ¡Ruidoso fantasma gobierna! Invicto!
fuente