Inizialmente avrei avuto la stessa risposta di tutti gli altri e avrei risolto il problema con i problemi rand()
. Tuttavia, ho pensato meglio di farlo e ho invece analizzato la distribuzione che la tua matematica sta effettivamente producendo.
TL; DR: il modello che vedi non ha nulla a che fare con il generatore di numeri casuali sottostante e invece è semplicemente dovuto al modo in cui il tuo programma sta manipolando i numeri.
Seguirò la tua funzione blu poiché sono tutti simili.
uint8_t blue(uint32_t x, uint32_t y) {
return (rand() % 2) ? (x + y) % rand() :
((x * y % 1024) % rand()) % 2 ? (x - y) % rand() :
rand();
}
Ciascun valore di pixel è selezionato da uno dei tre funzioni: (x + y) % rand()
, (x - y) % rand()
e rand()
;
Diamo un'occhiata alle immagini prodotte da ciascuno di questi da solo.
Questo è quello che ti aspetteresti, solo rumore. Chiama questa "Immagine C"
Qui stai sommando le coordinate dei pixel e stai prendendo il resto dalla divisione per un numero casuale. Se l'immagine è 1024x1024, la somma è compresa nell'intervallo [0-2046]. Il numero casuale per cui ti stai immergendo è nell'intervallo [0, RAND_MAX], dove RAND_MAX è almeno 32k e su alcuni sistemi è 2 miliardi. In altre parole, nella migliore delle ipotesi c'è una probabilità 1 su 16 che il resto non sia solo (x + y)
. Quindi per la maggior parte questa funzione produrrà solo un gradiente di blu crescente verso la direzione + x + y.
Tuttavia stai usando solo gli 8 bit più bassi, perché restituisci a uint8_t
, quindi avrai strisce di gradienti larghe 256 pixel.
Chiama questa "Immagine A"
Qui fai qualcosa di simile, ma con sottrazione. Finché x è maggiore di y avrai qualcosa di simile all'immagine precedente. Ma dove y è maggiore, il risultato è un numero molto grande perché x
e y
sono senza segno (i risultati negativi si spostano in cima all'intervallo del tipo senza segno), quindi i % rand()
calci entrano e si ottiene effettivamente rumore.
Chiama questa "Immagine B"
Ogni pixel nell'immagine finale viene preso da una di queste tre immagini usando le funzioni rand() % 2
e ((x * y % 1024) % rand()) % 2
. Il primo di questi può essere letto come una scelta con probabilità del 50% (ignorando i problemi con rand()
e i suoi bit di basso ordine).
Ecco un primo piano di dove rand() % 2
è vero (pixel bianchi), quindi è selezionata l'immagine A.
La seconda funzione ((x * y % 1024) % rand()) % 2
ha di nuovo il problema in cui di rand()
solito è maggiore della cosa che stai dividendo (x * y % 1024)
, che è al massimo 1023. Quindi (x*y%1024)%2
non produce 0 e 1 ugualmente spesso. Qualsiasi numero dispari moltiplicato per qualsiasi numero pari è pari. Qualsiasi numero pari moltiplicato per qualsiasi numero pari è anche pari. Solo un numero dispari moltiplicato per un numero dispari è dispari, e così %2
via valori che sono anche tre quarti del tempo produrranno 0 tre quarti del tempo.
Ecco un primo piano di dove ((x * y % 1024) % rand()) % 2
è vero in modo che l'immagine B possa essere selezionata. Sta selezionando esattamente dove entrambe le coordinate sono dispari.
Ed ecco un primo piano di dove è possibile selezionare l'immagine C:
Infine, combinando le condizioni qui è selezionata l'immagine B:
E dove è selezionata l'immagine C:
La combinazione risultante può essere letta come:
Con una probabilità del 50% usa il pixel dell'immagine A. Il resto del tempo seleziona tra Immagine B e Immagine C, B dove entrambe le coordinate sono dispari, C dove una delle due è pari.
Infine, poiché stai facendo lo stesso per tre colori diversi, ma con orientamenti diversi, i motivi sono orientati in modo diverso in ciascun colore e producono le strisce incrociate o il motivo a griglia che stai vedendo.