GitHub
Skizzepackages/webgl-sand-engine/src

WebGL Sand Engine

@ralphschuler/webgl-sand-engine

Skizziert eine zellulare Partikelsimulation, in der Materialregeln auf einem diskreten Raster ausgeführt werden.

cellular automatagridWebGL

01 · Problem

Wofür braucht man das?

Sand, Wasser und Hindernisse benötigen lokale Nachbarschaftsregeln, deterministische Updates und eine effiziente Darstellung vieler Rasterzellen.

02 · Denkmodell

Das mentale Modell

Jede Zelle enthält einen Materialcode. Ein Simulationsschritt liest den alten Buffer und schreibt Entscheidungen in einen zweiten Buffer; Rendering ist davon getrennt.

Im Repository

Das Paket enthält Interfaces, einen leeren NeighborProvider und Fragmente eines Pixel-Renderers beziehungsweise Shaders. Root-Exports, Engine, Materialregeln und vollständiger GPU-Lebenszyklus fehlen.

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. Raster als flachen typisierten Buffer mit Breite und Höhe anlegen.
  2. Für jede aktive Zelle gültige Nachbarn aus dem alten Zustand lesen.
  3. Materialregel anwenden und Ergebnis konfliktfrei in den nächsten Buffer schreiben.
  4. Buffer tauschen und den neuen Zustand separat rendern.

04 · Bauteile

Die entscheidenden Verträge

Pixel / Material Interfaces Unvollständige Datentypen für Zellen und Materialverhalten.
NeighborProvider Platzhalter für Nachbarschaftsabfragen.
pixel-renderer Teilweiser WebGL-Renderer ohne vollständige Engineintegration.

05 · Build it yourself

Selbst implementieren

Starte auf der CPU mit einer einzigen Sandregel; danach kann derselbe Zustandsvertrag auf die GPU wandern.

  1. Leere Zelle und Sand als numerische Codes festlegen.
  2. Von unten nach oben arbeiten, damit ein Korn pro Tick höchstens einmal fällt.
  3. Grenzen prüfen und für komplexere Regeln einen zweiten Buffer einführen.
minimal.ts · unabhängig vom Package
const EMPTY = 0, SAND = 1;
function stepSand(grid: Uint8Array, width: number, height: number) {
  const next = grid.slice();
  for (let y = height - 2; y >= 0; y--) for (let x = 0; x < width; x++) {
    const from = y * width + x, below = from + width;
    if (grid[from] === SAND && grid[below] === EMPTY) {
      next[from] = EMPTY; next[below] = SAND;
    }
  }
  return next;
}

06 · Verifizieren

Was du testen solltest

  • Ein Korn fällt genau eine Zelle und verlässt niemals den Rasterrand.
  • Blockierter Sand bleibt stehen; Eingabebuffer wird nicht verändert.
  • Mehrere Körner erzeugen unabhängig von Iterationsdetails ein dokumentiertes Ergebnis.

07 · Grenzen

Kompromisse und Stolperfallen

  • CPU-Regeln sind leicht zu debuggen, skalieren aber schlechter als parallele Shader.
  • Double Buffering vermeidet Lese-/Schreibkonflikte und verdoppelt den Zustandsbedarf.
  • Zufällige Diagonalwahl wirkt natürlich, erschwert ohne seedbaren RNG die Reproduktion.
Wichtig

GPU-Optimierung lohnt sich erst, wenn Update-Reihenfolge, Konfliktauflösung und Randregeln als Referenz auf der CPU feststehen.

08 · Weiterdenken

Quellcode und Nachbarn

Originalcode auf GitHub ansehen