J'allais initialement avoir la même réponse que tout le monde et attribuer cela aux problèmes avec rand()
. Cependant, j'ai pensé qu'il valait mieux le faire et j'ai plutôt analysé la distribution que vos calculs produisent réellement.
TL; DR: Le modèle que vous voyez n'a rien à voir avec le générateur de nombres aléatoires sous-jacent et est simplement dû à la façon dont votre programme manipule les nombres.
Je vais m'en tenir à votre fonction bleue car ils sont tous similaires.
uint8_t blue(uint32_t x, uint32_t y) {
return (rand() % 2) ? (x + y) % rand() :
((x * y % 1024) % rand()) % 2 ? (x - y) % rand() :
rand();
}
Chaque valeur de pixel est choisi parmi l' une des trois fonctions suivantes: (x + y) % rand()
, (x - y) % rand()
et rand()
;
Regardons les images produites par chacun d'eux seul.
C'est ce à quoi vous vous attendez, juste du bruit. Appelez cela "Image C"
Ici, vous additionnez les coordonnées des pixels et prenez le reste de la division par un nombre aléatoire. Si l'image est de 1024x1024, alors la somme est dans la plage [0-2046]. Le nombre aléatoire par lequel vous plongez est dans la plage [0, RAND_MAX], où RAND_MAX vaut au moins 32k et sur certains systèmes est de 2 milliards. En d'autres termes, il y a au mieux 1 chance sur 16 que le reste ne soit pas juste (x + y)
. Donc, pour la plupart, cette fonction produira simplement un gradient de bleu croissant vers la direction + x + y.
Cependant, vous n'utilisez que les 8 bits les plus bas, car vous renvoyez a uint8_t
, vous aurez donc des bandes de dégradés de 256 pixels de large.
Appelez cela "Image A"
Ici, vous faites quelque chose de similaire, mais avec soustraction. Tant que x est supérieur à y, vous aurez quelque chose de similaire à l'image précédente. Mais où y est supérieur, le résultat est un très grand nombre car x
et y
sont non signés (les résultats négatifs s'enroulent vers le haut de la plage du type non signé), puis le% rand()
coup de pied et vous obtenez en fait du bruit.
Appelez cela "Image B"
Chaque pixel de votre image finale est extrait de l'une de ces trois images à l'aide des fonctions rand() % 2
et ((x * y % 1024) % rand()) % 2
. Le premier d'entre eux peut être lu comme un choix avec une probabilité de 50% (en ignorant les problèmes avecrand()
et ses bits de poids faible.)
Voici un gros plan de l'endroit où rand() % 2
est vrai (pixels blancs) pour que l'image A soit sélectionnée.
La deuxième fonction a ((x * y % 1024) % rand()) % 2
encore une fois le problème où rand()
est généralement supérieur à la chose que vous divisez (x * y % 1024)
, qui est au maximum de 1023. Ensuite, (x*y%1024)%2
ne produit pas 0 et 1 aussi souvent. Tout nombre impair multiplié par un nombre pair est pair. Tout nombre pair multiplié par un nombre pair est également pair. Seul un nombre impair multiplié par un nombre impair est impair, donc%2
suite des valeurs paires trois quarts du temps produiront 0 trois quarts du temps.
Voici un gros plan de l'endroit où ((x * y % 1024) % rand()) % 2
est vrai pour que l'image B puisse être sélectionnée. Il sélectionne exactement où les deux coordonnées sont impaires.
Et voici un gros plan de l'endroit où l'image C pourrait être sélectionnée:
Enfin, en combinant les conditions, voici où l'image B est sélectionnée:
Et là où l'image C est sélectionnée:
La combinaison résultante peut être lue comme suit:
Avec une probabilité de 50%, utilisez le pixel de l'image A. Le reste du temps, choisissez entre l'image B et l'image C, B où les deux coordonnées sont impaires, C où l'une ou l'autre est paire.
Enfin, puisque vous faites la même chose pour trois couleurs différentes, mais avec des orientations différentes, les motifs sont orientés différemment dans chaque couleur et produisent les bandes de croisement ou le motif de grille que vous voyez.