Ich würde anfangs die gleiche Antwort haben wie alle anderen und dies auf die Probleme mit bringen rand()
. Ich dachte jedoch besser darüber nach und analysierte stattdessen die Verteilung, die Ihre Mathematik tatsächlich erzeugt.
TL; DR: Das Muster, das Sie sehen, hat nichts mit dem zugrunde liegenden Zufallszahlengenerator zu tun und ist stattdessen einfach auf die Art und Weise zurückzuführen, wie Ihr Programm die Zahlen manipuliert.
Ich bleibe bei deiner blauen Funktion, da sie alle ähnlich sind.
uint8_t blue(uint32_t x, uint32_t y) {
return (rand() % 2) ? (x + y) % rand() :
((x * y % 1024) % rand()) % 2 ? (x - y) % rand() :
rand();
}
Jeder Pixelwert wird von einem der drei Funktionen ausgewählt ist : (x + y) % rand()
, (x - y) % rand()
und rand()
;
Schauen wir uns die Bilder an, die von jedem dieser Bilder alleine erstellt wurden.
Dies ist, was Sie erwarten würden, nur Lärm. Nennen Sie dies "Bild C"
Hier addieren Sie die Pixelkoordinaten und nehmen den Rest von der Division durch eine Zufallszahl. Wenn das Bild 1024 x 1024 ist, liegt die Summe im Bereich [0-2046]. Die Zufallszahl, nach der Sie tauchen, liegt im Bereich [0, RAND_MAX], wobei RAND_MAX mindestens 32.000 und auf einigen Systemen 2 Milliarden beträgt. Mit anderen Worten, es besteht bestenfalls eine 1: 16-Chance, dass der Rest nicht gerecht ist (x + y)
. Zum größten Teil erzeugt diese Funktion nur einen Gradienten mit zunehmendem Blau in Richtung + x + y.
Sie verwenden jedoch nur die niedrigsten 8 Bits, da Sie a zurückgeben uint8_t
, sodass Sie Streifen mit Farbverläufen von 256 Pixel Breite haben.
Nennen Sie dies "Bild A"
Hier machst du etwas ähnliches, aber mit Subtraktion. Solange x größer als y ist, haben Sie etwas Ähnliches wie das vorherige Bild. Aber wenn y größer ist, ist das Ergebnis eine sehr große Zahl, weil x
und y
ohne Vorzeichen (negative Ergebnisse werden bis zum oberen Rand des Bereichs des vorzeichenlosen Typs verschoben), und dann % rand()
tritt das ein und Sie erhalten tatsächlich Rauschen.
Nennen Sie dies "Bild B"
Jedes Pixel in Ihrem endgültigen Bild wird mithilfe der Funktionen rand() % 2
und aus einem dieser drei Bilder entnommen ((x * y % 1024) % rand()) % 2
. Die erste davon kann als Auswahl mit einer Wahrscheinlichkeit von 50% gelesen werden (Ignorieren von Problemen mit rand()
und ihren Bits niedriger Ordnung).
Hier ist eine Nahaufnahme, wo rand() % 2
wahr ist (weiße Pixel), also ist Bild A ausgewählt.
Die zweite Funktion hat ((x * y % 1024) % rand()) % 2
wieder das Problem, wo rand()
normalerweise größer ist als das, was Sie teilen (x * y % 1024)
, was höchstens 1023 ist. Dann werden (x*y%1024)%2
0 und 1 nicht gleich oft erzeugt. Jede ungerade Zahl multipliziert mit einer geraden Zahl ist gerade. Jede gerade Zahl multipliziert mit einer geraden Zahl ist auch gerade. Nur eine ungerade Zahl multipliziert mit einer ungeraden Zahl ist ungerade, und so %2
weiter erzeugen Werte, die gerade drei Viertel der Zeit sind, 0 drei Viertel der Zeit.
Hier ist eine Nahaufnahme, wo ((x * y % 1024) % rand()) % 2
wahr ist, damit Bild B ausgewählt werden kann. Es wird genau ausgewählt, wo beide Koordinaten ungerade sind.
Und hier ist eine Nahaufnahme, wo Bild C ausgewählt werden könnte:
Kombinieren Sie abschließend die Bedingungen, unter denen Bild B ausgewählt ist:
Und wo Bild C ausgewählt ist:
Die resultierende Kombination kann wie folgt gelesen werden:
Verwenden Sie mit einer Wahrscheinlichkeit von 50% das Pixel aus Bild A. Der Rest der Zeit wählt zwischen Bild B und Bild C, B, wo beide Koordinaten ungerade sind, C, wo eines der beiden gerade ist.
Da Sie dasselbe für drei verschiedene Farben tun, aber mit unterschiedlichen Ausrichtungen, werden die Muster in jeder Farbe unterschiedlich ausgerichtet und erzeugen die Kreuzungsstreifen oder Gittermuster, die Sie sehen.