Je travaille actuellement sur un programme qui devrait générer du bruit aléatoire sur un écran basé sur les «coordonnées» d'un pixel. Les coordonnées doivent avoir la même couleur à chaque redémarrage du programme. Cependant, en utilisant l'utilitaire Java, les résultats que j'obtiens ne sont pas aussi aléatoires que je le souhaiterais:
Je pensais que si j'utilisais les coordonnées combinées (comme dans un entier formé à partir des deux coordonnées l'une à côté de l'autre), chaque coordonnée aurait un nombre différent. En utilisant ce nombre comme graine, je m'attendais à obtenir un nombre aléatoire différent pour chaque coordonnée à utiliser pour la valeur RVB de cette coordonnée.
Voici le code que j'ai utilisé:
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;
}
}
Le modèle créé par le programme est-il dû au fonctionnement de la fonction aléatoire de Java ou est-ce que je fais quelque chose de mal et dois-je essayer une approche différente?
Mise à jour: j'ai maintenant essayé de me débarrasser des problèmes liés à la concaténation en utilisant le code suivant:
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;
}
D'une certaine manière, cela a également fourni (à mon avis) une image suffisamment aléatoire:
Ce code est cependant réensemencé trois fois par pixel. Même si ce n'est pas un problème pour moi en ce moment, j'envisage de changer ce code au cas où j'aurais besoin de meilleures performances plus tard.
Réponses:
La
java.util.Random
classe Java vous donne généralement des séquences de nombres pseudo-aléatoires qui sont suffisamment bonnes pour être utilisées dans les jeux 1 . Cependant, cette caractéristique ne s'applique qu'à une séquence de plusieurs échantillons basés sur une graine. Lorsque vous réinitialisez le RNG avec des valeurs de départ incrémentées et que vous ne regardez que la première valeur de chaque séquence, les caractéristiques de caractère aléatoire ne seront pas aussi bonnes.Ce que vous pourriez faire à la place:
Au lieu d'utiliser un générateur de nombres aléatoires, utilisez une fonction de résumé de message pour transformer une paire de coordonnées en une valeur de couleur. La sortie de la plupart des MDF est suffisamment imprévisible pour répondre à la plupart des tests d'aléatoire. La sortie est généralement supérieure au 24 bits dont vous avez besoin pour une valeur RVB, mais les tronquer n'est généralement pas un problème.
Pour améliorer les performances, vous pouvez combiner la génération de résumé de message avec des morceaux. Générez de petits morceaux de pixels qui sont juste assez grands pour utiliser toute la longueur d'une sortie de votre fonction de résumé.
1 quand il est absolument essentiel que personne ne puisse prédire le nombre suivant, utilisez le plus lent mais moins prévisible
java.security.SecureRandom
la source
Dans ce cas, vous souhaiterez utiliser une fonction de bruit déterministe telle que le bruit Perlin ou le bruit simplex .
( Voir cette question pour plus d'informations sur le bruit Perlin avec de jolies images. )
Pour la plupart, l'utilisation d'une fonction intégrée
random()
ou similaire vous donnera des valeurs différentes à chaque fois que vous exécuterez le programme, car ils peuvent utiliser l'horloge comme entrée ou une autre valeur pseudo-aléatoire.Une autre option consiste à générer une "carte de bruit" une fois, hors ligne, puis à l'utiliser comme source de nombre aléatoire plus tard.
Dans votre implémentation, vous concaténez les représentations de chaîne de x et
y
. C'est mauvais car ce n'est pas unique dans le domaine. Par exemple,Bonne chance!
la source
Voyons ce que vous faites exactement:
Tout cela sonne bien, mais vous recevez un motif parce que:
Pixel à 1,11 et pixel à 11,1 sont tous deux ensemencés le nombre 111 de sorte qu'ils sont certains d'avoir la même couleur.
Aussi, tant que vous faites toujours le même cycle, vous ne pouvez utiliser qu'un seul générateur, pas besoin d'en utiliser un pour chaque pixel. Un pour l'image entière fera l'affaire! Il y aura toujours des schémas à cause du pseudo-aléatoire. @David_Lively a raison d'utiliser un algorithme de bruit, cela le rendra plus aléatoire.
la source
Faites un générateur de couleurs, puis produisez vos couleurs pour votre carreau. Semez une seule fois! Vous n'avez pas besoin de semer plus que cela, au moins par tuile.
Et l'utilisation sera comme suit:
Avec cela, si vous n'êtes pas satisfait du résultat, changez simplement de
Random
graine. De plus, il vous suffit de stocker / communiquer la graine et les tailles afin que tous les clients aient la même image.la source
Au lieu d'utiliser Random, envisagez d'utiliser un condensé de hachage comme MD5. Il fournit une valeur «aléatoire» difficile à prévoir sur la base d'une certaine entrée, mais toujours la même valeur pour la même entrée.
Exemple:
REMARQUE: je ne sais pas d'où vient Color.rgb888 (..), donc je ne sais pas quelle est la plage autorisée. 0-255 est normal cependant.
Améliorations à considérer:
la source
D'autres ont souligné qu'une façon d'obtenir le comportement souhaité consiste à utiliser une fonction de hachage, également appelée «fonction de résumé des messages». Le problème est que ceux-ci sont souvent basés sur des algorithmes comme MD5, qui est cryptographiquement sécurisé (c'est-à-dire vraiment, vraiment, vraiment aléatoire) mais très lent. Si vous utilisez une fonction de hachage cryptographique chaque fois que vous avez besoin d'un pixel aléatoire, vous rencontrerez des problèmes de performances assez graves.
Cependant, il existe des fonctions de hachage non cryptographiques qui peuvent produire des valeurs suffisamment aléatoires pour votre objectif tout en étant rapides. Celui que j'atteins habituellement est murmure . Je ne suis pas un utilisateur Java mais il semble qu'il y ait au moins une implémentation Java disponible. Si vous constatez que vous avez vraiment besoin que chaque pixel soit généré à partir de ses coordonnées, plutôt que de les générer tous en même temps et de les stocker dans une texture, ce serait une bonne façon de le faire.
la source
J'utiliserais un nombre premier supérieur à 2000 (résolution typique maximale)
Cela minimisera (ou éliminera les graines en double)
la source
Random
est assez aléatoire. Vous l'utilisez mal pour deux raisons principales.Integer.valueOf(Integer.toString(x)+Integer.toString(y))
entre les pixels avec lesquels vous semez.J'utiliserais simplement une variante du code suivant, où vous pouvez choisir une fonction de hachage (n'utilisez pas Integer.getHashCode) dans les réponses à /programming/9624963/java-simplest-integer- hacher
où la fonction de hachage pourrait être
la source
Vous pouvez essayer d'utiliser l'heure actuelle du système comme une graine comme ceci:
Espérons que cela produise une valeur plus aléatoire.
la source
Voici une fonction de shader statique sur une ligne que j'ai trouvée - poltergeist (Noisy Ghost).
Il prend une coordonnée 2D et une graine, et s'affiche en monotone comme demandé. Il fonctionne à fps en temps réel, quelle que soit la résolution de l'écran. C'est à cela que servent les GPU.
N'importe quelle résolution, n'importe quelle texture, sur n'importe quel appareil (mobile aussi) prenant en charge GL (qui est à peu près n'importe quel écran).
Voyez-le courir ici, en ce moment!
https://www.shadertoy.com/view/ltB3zD
Vous pouvez facilement inclure ce shader dans votre programme java en utilisant opengl standard, ou dans n'importe quel navigateur en utilisant webgl standard.
Juste pour le plaisir, je jette le gant pour que quiconque bat Poltergeist en qualité et en performance sur tous les appareils. Règles de Noisy Ghost! Invaincu!
la source