0t1 steckt noch in den Kinderschuhen.

Geometrische Muster in p5.js

Zufällige geometrische Mustergenerierung

Ziel der Übung

In dieser Übung programmierst du ein zufällig generiertes Muster in einem 800x800px Canvas. Verschiedene geometrische Formen werden dabei in Segmente unterteilt und miteinander kombiniert. Durch das Drücken der Leertaste wird ein neues Muster erzeugt und mit den Pfeiltasten kann die Farbpalette gewechselt werden.

Muster Beispiel

p5.js

Wir verwenden für diese Übung die JavaScript Bibliothek p5.js. Du kannst den online Editor verwenden, um damit Programme zu bauen. Alternativ kann die Bibliothek auch in deine eigene Webseite integriert oder mit einem beliebigen Quellcode-Editor bearbeitet werden.

Öffne zum Starten den p5.js Editor.

Dort wird dir folgender Code angezeigt:

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
}

Diese beiden Funktionen sind das Skelett deines p5.js-Programms:

Die setup()-Funktion wird einmalig ausgeführt, wenn das Programm zum ersten Mal geladen wird. Hier kannst du die Zeichenfläche erstellen, die p5.js zum Anzeigen von Grafiken verwendet. Textformatierung und die Farben für das Zeichnen können hier ebenfalls festgelegt werden.

Die draw()-Funktion wiederholt sich, solange das Programm läuft. Es steuert, wie sich das Programm im Laufe der Zeit entwickeln soll, einschließlich Animationen und anderer dynamischer Elemente.

Falls du das erste Mal mit p5.js arbeitest, wirf ebenfalls einen Blick auf die get started Anleitung von p5.js.

Setup()-Funktion

Zunächst definieren wir die Größe des Canvas auf 800x800px. Die Funktion noLoop() stoppt die draw()-Funktion nach erstmaligem Durchlauf. Somit wird gewährleistet, dass das generierte Muster nicht sofort von einem Neuen überschrieben wird. noStroke() deaktiviert das Zeichnen der Kontur.

function setup() {
    createCanvas(800, 800);
    noLoop();
    noStroke();
}

Farbpaletten

Nun geht es um die Auswahl der Farbwerte bzw. -paletten, die im weiteren Verlauf auf die Formen angewandt werden. Hierzu wird ein zweidimensionales array über der setup()-Funktion definiert, welches mit Hexadezimalwerten gefüllt wird. Dabei ist die Anzahl der Farben und Paletten variabel. Du kannst die vorgegeben Werte benutzen oder selbst eigene Farbpaletten entwerfen.

//Definition der Farbpaletten
let paletten = [
    ["#0B090A", "#161A1D", "#660708", "#A4161A", "#BA181B", "#E5383B", "#B1A7A6", "D3D3D3", "#F5F3F4", "#FFFFFF"],
    ["#800016", "#a0001c", "#c00021", "#ff002b", "#ffffff", "#407ba7", "#004e89", "002962", "#00043a"],
    ["#03071e", "#370617", "#6a040f", "#9d0208", "#d00000", "#dc2f02", "#e85d04", "f48c06", "#faa307", "#ffba08"],
    ["#132a13", "#31572c", "#4f772d", "#90a955", "#ecf39e", "#edf0c6", "#f7f8ec"]
];

Darunter wird die Anzahl der Segmente einer Reihe bzw. Spalte definiert sowie eine Zählvariable, die zum Wechseln der Farbpaletten benötigt wird.

let segmentAnz = 5;   //Anzahl der Segmente in x und y Richtung
let counter = 0;      //Zählvariable für die Palettenauswahl

makeTile()-Funktion

Als Nächstes legen wir eine neue Funktion an, die in den Segmenten zufällige geometrische Formen erstellt. Mit Hilfe der shuffel()-Funktion werden die Farben in einer Palette willkürlich angeordnet, sodass der darauffolgenden fill()-Funktion ein zufälliger Farbwert aus der Palette übergeben wird. Mit dieser Farbe wird ein Quadrat erzeugt, welches das erste Segment ausfüllt.

Nun werden diese Quadrate mit weiteren geometrischen Formen gefüllt. Durch die push()-Funktion können die momentanen Zeichenstileinstellungen gespeichert werden, während die pop()-Funktion diese wiederherstellt. Dadurch lassen sich zwischen diesen Funktionen neue temporäre Zeichenstile definieren. Das gewährleistet, dass die erzeugten geometrischen Formen nicht die gleiche Farbe annehmen wie das Segment.

Die neu erstellten Formen werden mit der translate()-Funktion um die Hälfte des Segments s verschoben und dann mittels der rotate()-Funktion um einen zufälligen Wert gedreht. Damit der Rotationswert nicht immer derselbe ist, wird die random()-Funktion verwendet.

In der Variable r wird eine Zufallszahl von 0 bis einschließlich 3 definiert, diese wird in der darauf folgenden if()-Abfrage verwendet, um die geometrische Form zu bestimmen. Dabei werden die Funktionen arc(), rect() und triangle() verwendet, um Kurven, Rechtecke oder Dreiecke zu generieren.

//Generierung zufälliger geometrischer Formen
function makeTile(x, y, s) {
    shuffle(paletten[counter], true);
    fill(paletten[counter][0]);
    square(x, y, s);
    push();
    translate(x + s / 2, y + s / 2);
    rotate(random([0, PI / 2, PI, 3 * PI / 2]));
    fill(paletten[counter][1]);
    let r = floor(random(4));
    if (r == 0) {
        arc(-s / 2, 0, s, s, -PI / 2, PI / 2);
    } else if (r == 1) {
        rect(-s / 2, -s / 2, s / 2, s);
    } else if (r == 2) {
        triangle(-s / 2, -s / 2, s / 2, -s / 2, -s / 2, s / 2);
    }
    pop();
}

draw()-Funktion

Nun wird neben der setup()-Funktion ebenfalls die draw()-Funktion angepasst. Dabei wird als Erstes die Variable s definiert, welche die Breite der Segmente angibt. In einer verschachtelten for-Schleife werden spaltenweise einzelne Segmente generiert. Die random()-Funktion in der if-Abfrage entscheidet dabei, ob das Segment weiter untergliedert wird. Hierzu werden die Variablen x, y und s an die makeTile()-Funktion übergeben.

function draw() {
    let s = width / segmentAnz;  //s ist die Laenge der einzelnen Segmente

    //Generierung der einzelnen Segmente
    for (let x = 0; x < width; x += s) {
        for (let y = 0; y < height; y += s) {
          
            //Segmentunterteilung
            if (random() < 1 / 2) {
                makeTile(x, y, s / 2);
                makeTile(x + s / 2, y, s / 2);
                makeTile(x, y + s / 2, s / 2);
                makeTile(x + s / 2, y + s / 2, s / 2);
            } else {
                makeTile(x, y, s);
            }
        }
    }
}

keyPressed()-Funktion

Um per Tastatur ein neues Muster zu generieren oder die Farbpalette zu wechseln, wird die keyPressed()-Funktion erstellt. In einer verschachtelten if-Abfrage wird überprüft, ob die Leertaste, linke Pfeiltaste oder rechte Pfeiltaste gedrückt ist. Sobald das der Fall ist, wird am Ende der Abfrage die redraw()-Funktion aufgerufen, welche ein neues Muster generiert. Die Pfeiltasten wechseln zusätzlich noch die Farbpalette mithilfe der zuvor definierten Zählvariable counter.

//Ermöglicht das Wechseln der Farbpalette und die Neugenerierung mit der Tastatur
function keyPressed() {
    if (key == (" ") ||  keyIsDown(LEFT_ARROW) || keyIsDown(RIGHT_ARROW)) {
        if (keyIsDown(LEFT_ARROW) && counter > 0) {
            counter--;
        } else if (keyIsDown(LEFT_ARROW) && counter == 0) {
            counter = paletten.length - 1;
        } else if (keyIsDown(RIGHT_ARROW) && counter < paletten.length - 1) {
            counter++;
        } else if (keyIsDown(RIGHT_ARROW) && counter == paletten.length - 1) {
            counter = 0;
        }
        redraw();
    }

Variationen

Die generierten Muster können ganz leicht durch das Anpassen der Variablen abgeändert werden (z.B. seqmentAnz = 80). Durch das Arbeiten mit dem Code lernt man am besten. Probiere es einfach selbst aus!

Varianz der Mustergenerierung

Quellcode

Hier findest du den gesamten Quellcode.

Das Tutorial wurde inspiriert von den Werken Roni Kaufmans.


© 0t1

Cookies

0t1 mag keine Kekse (und kein Tracking). Wir verwenden lediglich notwendige Cookies für essentielle Funktionen.

Wir verwenden Schriftarten von Adobe Fonts. Dafür stellt dein Browser eine Verbindung zu den Servern von Adobe in den USA her. Wenn du unsere Seite nutzen möchtest, musst du dich damit einverstanden erklären.

Weitere Informationen in unserer Datenschutzerklärung.