Wunsch des Users (2026-10-03), aus der Frage nach mehreren Passes für einen Blur.
Befund
Ein Blur geht schon heute in einem Pass: Sample texture liest an einer beliebigen UV, und UV mit Texture size liefern den Abstand eines Pixels (1 / size). Mehrere Passes (horizontal, dann vertikal) bringen nur Tempo, sie sind keine Voraussetzung.
Der Haken ist die Verdrahtung: Der Graph hat keine Schleife. Ein 3x3-Blur sind 9 Sample texture plus Add-Kette plus Teilen, ein 5x5-Blur schon 25 Samples, alles von Hand.
Wer die Farbe naiv mittelt, bekommt am Rand dunkle Säume: Sample texture.color ist die gerade Farbe (straight), ein transparenter Nachbar zählt dann mit seiner Farbe voll mit. Richtig ist, die vormultiplizierten Samples zu mitteln und erst danach zu teilen. Das muss man heute wissen.
Die Shader laufen auf GLSL ES 3.00 (compile.ts), eine Schleife mit Grenze aus einem Uniform ist dort erlaubt.
Zu bauen (Vorschlag)
Node Blur in der Shader-Kategorie, neben Sample texture.
Eingänge: radius (Pixel des Bildes, inline mit Default 2), dazu u/v wie bei Sample texture (unverbunden der eigene Pixel).
Ausgänge: color und alpha, wie bei Sample texture.
Der Compiler schreibt die Schleife selbst ins GLSL (Hilfsfunktion im Prelude wie texelAt), es bleibt ein Pass.
Gemittelt wird vormultipliziert, color kommt danach gerade heraus. Kein dunkler Saum am Rand.
Der Rand folgt wie bei Sample texture der Einstellung Edge am Output. Mit Transparent und Padding läuft der Blur über das Sprite hinaus.
Gilt überall, wo ein Shader läuft: Sprite, Text, Partikel, Feld-Shader (#170) und später die Kamera (#299).
Messung wie in #67 und #170: Bilder je Sekunde mit einem Sprite bzw. einem Feld mit Blur bei Radius 2, 4 und 8.
Beweis beim Schließen
Radius 0 zeichnet das Bild unverändert.
Ein einzelnes weißes Pixel auf Transparent wird zu einem Fleck der erwarteten Größe, die Summe der Deckkraft bleibt gleich.
Eine harte Kante (Rot an Transparent) bekommt einen weichen Übergang ohne dunklen Saum.
radius aus einer Property lässt sich am Sprite ändern, ohne den Shader neu zu bauen.
Offen (mit Vorschlag)
Form: Box (alle Samples gleich gewichtet) oder Gauß (die Mitte zählt mehr)? Vorschlag: Gauß, das sieht bei gleichem Radius weicher aus und kostet gleich viel. Box wäre als Setting Kind am Node billig mitzunehmen.
Obergrenze für radius: Die Kosten wachsen mit (2r+1)². Vorschlag: höchstens 8 (289 Samples). Darüber wird es auch auf schneller Hardware teuer, und ab dort lohnen sich mehrere Passes wirklich (eigenes Issue, wenn gebraucht).
Bruchteile beim Radius: Vorschlag: erlaubt, der Rand wird anteilig gewichtet. Dann lässt sich ein Blur per Animation weich ein- und ausblenden, statt in ganzen Pixeln zu springen.
Richtung: Ein Setting Direction (Both / Horizontal / Vertical) wäre fast gratis und deckt Bewegungsunschärfe in einer Achse ab. Vorschlag: mitnehmen, Standard Both.
Wunsch des Users (2026-10-03), aus der Frage nach mehreren Passes für einen Blur.
## Befund
- Ein Blur geht schon heute in **einem** Pass: `Sample texture` liest an einer beliebigen UV, und `UV` mit `Texture size` liefern den Abstand eines Pixels (`1 / size`). Mehrere Passes (horizontal, dann vertikal) bringen nur Tempo, sie sind keine Voraussetzung.
- Der Haken ist die Verdrahtung: Der Graph hat keine Schleife. Ein 3x3-Blur sind 9 `Sample texture` plus `Add`-Kette plus Teilen, ein 5x5-Blur schon 25 Samples, alles von Hand.
- Wer die Farbe naiv mittelt, bekommt am Rand dunkle Säume: `Sample texture.color` ist die gerade Farbe (`straight`), ein transparenter Nachbar zählt dann mit seiner Farbe voll mit. Richtig ist, die vormultiplizierten Samples zu mitteln und erst danach zu teilen. Das muss man heute wissen.
- Die Shader laufen auf GLSL ES 3.00 (`compile.ts`), eine Schleife mit Grenze aus einem Uniform ist dort erlaubt.
## Zu bauen (Vorschlag)
- Node **`Blur`** in der Shader-Kategorie, neben `Sample texture`.
- Eingänge: `radius` (Pixel des Bildes, inline mit Default 2), dazu `u`/`v` wie bei `Sample texture` (unverbunden der eigene Pixel).
- Ausgänge: `color` und `alpha`, wie bei `Sample texture`.
- Der Compiler schreibt die Schleife selbst ins GLSL (Hilfsfunktion im Prelude wie `texelAt`), es bleibt ein Pass.
- Gemittelt wird vormultipliziert, `color` kommt danach gerade heraus. Kein dunkler Saum am Rand.
- Der Rand folgt wie bei `Sample texture` der Einstellung *Edge* am `Output`. Mit *Transparent* und `Padding` läuft der Blur über das Sprite hinaus.
- Gilt überall, wo ein Shader läuft: Sprite, Text, Partikel, Feld-Shader (#170) und später die Kamera (#299).
- Messung wie in #67 und #170: Bilder je Sekunde mit einem Sprite bzw. einem Feld mit Blur bei Radius 2, 4 und 8.
## Beweis beim Schließen
- Radius 0 zeichnet das Bild unverändert.
- Ein einzelnes weißes Pixel auf Transparent wird zu einem Fleck der erwarteten Größe, die Summe der Deckkraft bleibt gleich.
- Eine harte Kante (Rot an Transparent) bekommt einen weichen Übergang ohne dunklen Saum.
- `radius` aus einer `Property` lässt sich am Sprite ändern, ohne den Shader neu zu bauen.
## Offen (mit Vorschlag)
1. **Form:** Box (alle Samples gleich gewichtet) oder Gauß (die Mitte zählt mehr)? Vorschlag: Gauß, das sieht bei gleichem Radius weicher aus und kostet gleich viel. Box wäre als Setting `Kind` am Node billig mitzunehmen.
2. **Obergrenze für `radius`:** Die Kosten wachsen mit (2r+1)². Vorschlag: höchstens 8 (289 Samples). Darüber wird es auch auf schneller Hardware teuer, und ab dort lohnen sich mehrere Passes wirklich (eigenes Issue, wenn gebraucht).
3. **Bruchteile beim Radius:** Vorschlag: erlaubt, der Rand wird anteilig gewichtet. Dann lässt sich ein Blur per Animation weich ein- und ausblenden, statt in ganzen Pixeln zu springen.
4. **Richtung:** Ein Setting `Direction` (Both / Horizontal / Vertical) wäre fast gratis und deckt Bewegungsunschärfe in einer Achse ab. Vorschlag: mitnehmen, Standard Both.
meleki
added the shader label 2026-10-03 12:33:38 +02:00
admin
added this to the Development project 2026-10-03 12:34:49 +02:00
Erledigt mit df61b08, Wiki e281297 (Shaders, Development).
Deine Antworten (Kommentar 3003)
Setting Kind, Standard Box, dazu Gaussian.
Radius höchstens 8. Das Folge-Issue für mehrere Passes ist #301.
Bruchteile sind erlaubt, der äußerste Ring zählt anteilig.
Direction (Both / Horizontal / Vertical, Standard Both) ist mit drin.
Was neu ist
Node Blur in der Shader-Palette:
Eingänge radius (Pixel des Bildes, Standard 2, 0 bis 8) und u/v wie bei Sample texture.
Ausgänge color und alpha.
Settings Kind und Direction.
Die Schleife steht als Hilfsfunktion blur() im Prelude und kommt nur in Shader, die einen Blur erreichen. Es bleibt ein Pass.
Kein dunkler Saum: Gemittelt wird vormultipliziert, erst danach wird daraus die gerade Farbe. Ein transparenter Nachbar senkt nur die Deckkraft.
Radius aus einer Property ist ein Uniform: Ändern kompiliert nichts neu.
Der Rand folgt Edge am Output. Für einen freistehenden weichen Rand Transparent und Padding setzen.
Gilt überall, wo ein Shader läuft: Sprite, Text, Partikel, Feld-Shader.
GM_PERF_BLUR=<radius> in tools/perf-shaders.mjs und tools/perf-field-shaders.mjs.
Was ich selbst festgelegt habe
Gaussian: sigma = radius / 2.
Ein Ergebnis für beide Ausgänge: Ein Node darf jetzt eine Vorarbeit (prepare) melden, die der Compiler einmal in eine lokale Variable legt. Sonst hätten color und alpha je einen eigenen Blur gerechnet, also doppelte Kosten.
Ein Blur zählt als verschobenes Sample. Er bekommt deshalb die Texturvariante für Edge, wie ein Sample texture mit gespeister UV.
Pixel des Bildes: Beim Text ist das ein Pixel der gerasterten Schrift. Bei Linear hängt dessen Größe vom Zoom ab, der Blur wirkt dann je nach Zoom verschieden breit. Beim Feld-Shader ist es ein Bildschirmpixel.
Der Wert im Feld radius hat Schrittweite 0,5.
Messung (stein2, Intel HD 630, Bilder je Sekunde, ein Lauf je Wert, Box)
Ohne Shader hielten dieselben Szenen 59,0 bis 60,1.
Sprites 48x48
100
400
800
Radius 2
59,8
58,4
55,6
Radius 4
53,1
51,4
36,3
Radius 8
46,6
24,4
14,4
Feld-Shader 256x256 Pixel
1
10
50
Radius 2
60,2
56,0
49,0
Radius 4
60,1
49,0
27,1
Radius 8
52,4
34,9
11,4
Radius 2 ist billig. Ab 4 bestimmen die Samples den Preis. Ein einziges Feld mit Radius 8 kostet schon 8 Bilder je Sekunde (289 Samples je Pixel). Zwei Passes (#301) kämen dort mit 34 aus.
Der Beweis aus dem Issue, e2e 28l-vi (32-px-Bild links rot, rechts grün, Filter Nearest):
Radius 0 zeichnet das Bild bytegleich.
Das letzte rote Pixel, waagrecht über eine Property weichgezeichnet: 187 / 173 / 154 im Rotkanal bei Radius 0,5 / 1 / 4. Gerechnet sind 188 / 173 / 154. Dazwischen wird nichts kompiliert.
Vertical bleibt rot, Gaussian behält mehr Rot als Box (162 gegen 154).
Mit Edge Transparent bleibt das erste Pixel rot (#e63c3c) und hat 5/9 Deckkraft (gemessen 0,556), also kein Saum.
Ein einzelnes weißes Pixel wird bei Radius 1 zu einem Fleck aus 3x3 Pixeln mit je 1/9 Deckkraft (Summe 0,977 bei 8-Bit-Rundung).
7 Unit-Tests in tests/core/shader-blur.test.ts.
Gegenproben:
Zählt der Blur nicht als verschobenes Sample, fällt 1 Unit-Test.
Gibt der Blur die vormultiplizierte Farbe aus, fallen im Browser der Saum- und der Fleck-Check (Rand #802121).
Die e2e-Summe 1712 ist gerechnet (1707 + 5).
Nicht im Browser geprüft: Blur an Text, Partikeln und im Feld-Shader (nur die Messung lief dort), Gaussian mit Both, das Glow-Rezept aus dem Wiki und die Vorschau im Shader-Tab.
Erledigt mit df61b08, Wiki e281297 (*Shaders*, *Development*).
## Deine Antworten (Kommentar 3003)
1. Setting `Kind`, Standard **Box**, dazu **Gaussian**.
2. Radius höchstens 8. Das Folge-Issue für mehrere Passes ist **#301**.
3. Bruchteile sind erlaubt, der äußerste Ring zählt anteilig.
4. `Direction` (Both / Horizontal / Vertical, Standard Both) ist mit drin.
## Was neu ist
- Node **`Blur`** in der Shader-Palette:
- Eingänge `radius` (Pixel des Bildes, Standard 2, 0 bis 8) und `u`/`v` wie bei `Sample texture`.
- Ausgänge `color` und `alpha`.
- Settings *Kind* und *Direction*.
- Die Schleife steht als Hilfsfunktion `blur()` im Prelude und kommt nur in Shader, die einen Blur erreichen. Es bleibt **ein** Pass.
- **Kein dunkler Saum:** Gemittelt wird vormultipliziert, erst danach wird daraus die gerade Farbe. Ein transparenter Nachbar senkt nur die Deckkraft.
- **Radius aus einer `Property`** ist ein Uniform: Ändern kompiliert nichts neu.
- Der Rand folgt *Edge* am `Output`. Für einen freistehenden weichen Rand *Transparent* und *Padding* setzen.
- Gilt überall, wo ein Shader läuft: Sprite, Text, Partikel, Feld-Shader.
- `GM_PERF_BLUR=<radius>` in `tools/perf-shaders.mjs` und `tools/perf-field-shaders.mjs`.
## Was ich selbst festgelegt habe
- **Gaussian:** sigma = radius / 2.
- **Ein Ergebnis für beide Ausgänge:** Ein Node darf jetzt eine Vorarbeit (`prepare`) melden, die der Compiler einmal in eine lokale Variable legt. Sonst hätten `color` und `alpha` je einen eigenen Blur gerechnet, also doppelte Kosten.
- **Ein Blur zählt als verschobenes Sample.** Er bekommt deshalb die Texturvariante für *Edge*, wie ein `Sample texture` mit gespeister UV.
- **Pixel des Bildes:** Beim Text ist das ein Pixel der gerasterten Schrift. Bei *Linear* hängt dessen Größe vom Zoom ab, der Blur wirkt dann je nach Zoom verschieden breit. Beim Feld-Shader ist es ein Bildschirmpixel.
- Der Wert im Feld `radius` hat Schrittweite 0,5.
## Messung (stein2, Intel HD 630, Bilder je Sekunde, ein Lauf je Wert, Box)
Ohne Shader hielten dieselben Szenen 59,0 bis 60,1.
| Sprites 48x48 | 100 | 400 | 800 |
| --- | --- | --- | --- |
| Radius 2 | 59,8 | 58,4 | 55,6 |
| Radius 4 | 53,1 | 51,4 | 36,3 |
| Radius 8 | 46,6 | 24,4 | 14,4 |
| Feld-Shader 256x256 Pixel | 1 | 10 | 50 |
| --- | --- | --- | --- |
| Radius 2 | 60,2 | 56,0 | 49,0 |
| Radius 4 | 60,1 | 49,0 | 27,1 |
| Radius 8 | 52,4 | 34,9 | 11,4 |
Radius 2 ist billig. Ab 4 bestimmen die Samples den Preis. Ein einziges Feld mit Radius 8 kostet schon 8 Bilder je Sekunde (289 Samples je Pixel). Zwei Passes (#301) kämen dort mit 34 aus.
## Tests
```
Gate → 224 Files, 3467 Tests, CHECK EXIT 0 (3460 + 7)
e2e 28 → ALL PASSED – 94 checks (89 + 5)
```
- **Der Beweis aus dem Issue, e2e 28l-vi** (32-px-Bild links rot, rechts grün, Filter *Nearest*):
- Radius 0 zeichnet das Bild bytegleich.
- Das letzte rote Pixel, waagrecht über eine `Property` weichgezeichnet: 187 / 173 / 154 im Rotkanal bei Radius 0,5 / 1 / 4. Gerechnet sind 188 / 173 / 154. Dazwischen wird nichts kompiliert.
- *Vertical* bleibt rot, *Gaussian* behält mehr Rot als *Box* (162 gegen 154).
- Mit Edge *Transparent* bleibt das erste Pixel rot (`#e63c3c`) und hat 5/9 Deckkraft (gemessen 0,556), also kein Saum.
- Ein einzelnes weißes Pixel wird bei Radius 1 zu einem Fleck aus 3x3 Pixeln mit je 1/9 Deckkraft (Summe 0,977 bei 8-Bit-Rundung).
- **7 Unit-Tests** in `tests/core/shader-blur.test.ts`.
- **Gegenproben:**
- Zählt der Blur nicht als verschobenes Sample, fällt 1 Unit-Test.
- Gibt der Blur die vormultiplizierte Farbe aus, fallen im Browser der Saum- und der Fleck-Check (Rand `#802121`).
- Die e2e-Summe **1712** ist gerechnet (1707 + 5).
- **Nicht im Browser geprüft:** Blur an Text, Partikeln und im Feld-Shader (nur die Messung lief dort), *Gaussian* mit *Both*, das Glow-Rezept aus dem Wiki und die Vorschau im Shader-Tab.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Wunsch des Users (2026-10-03), aus der Frage nach mehreren Passes für einen Blur.
Befund
Sample textureliest an einer beliebigen UV, undUVmitTexture sizeliefern den Abstand eines Pixels (1 / size). Mehrere Passes (horizontal, dann vertikal) bringen nur Tempo, sie sind keine Voraussetzung.Sample textureplusAdd-Kette plus Teilen, ein 5x5-Blur schon 25 Samples, alles von Hand.Sample texture.colorist die gerade Farbe (straight), ein transparenter Nachbar zählt dann mit seiner Farbe voll mit. Richtig ist, die vormultiplizierten Samples zu mitteln und erst danach zu teilen. Das muss man heute wissen.compile.ts), eine Schleife mit Grenze aus einem Uniform ist dort erlaubt.Zu bauen (Vorschlag)
Blurin der Shader-Kategorie, nebenSample texture.radius(Pixel des Bildes, inline mit Default 2), dazuu/vwie beiSample texture(unverbunden der eigene Pixel).colorundalpha, wie beiSample texture.texelAt), es bleibt ein Pass.colorkommt danach gerade heraus. Kein dunkler Saum am Rand.Sample textureder Einstellung Edge amOutput. Mit Transparent undPaddingläuft der Blur über das Sprite hinaus.Beweis beim Schließen
radiusaus einerPropertylässt sich am Sprite ändern, ohne den Shader neu zu bauen.Offen (mit Vorschlag)
Kindam Node billig mitzunehmen.radius: Die Kosten wachsen mit (2r+1)². Vorschlag: höchstens 8 (289 Samples). Darüber wird es auch auf schneller Hardware teuer, und ab dort lohnen sich mehrere Passes wirklich (eigenes Issue, wenn gebraucht).Direction(Both / Horizontal / Vertical) wäre fast gratis und deckt Bewegungsunschärfe in einer Achse ab. Vorschlag: mitnehmen, Standard Both.Erledigt mit
df61b08, Wiki e281297 (Shaders, Development).Deine Antworten (Kommentar 3003)
Kind, Standard Box, dazu Gaussian.Direction(Both / Horizontal / Vertical, Standard Both) ist mit drin.Was neu ist
Blurin der Shader-Palette:radius(Pixel des Bildes, Standard 2, 0 bis 8) undu/vwie beiSample texture.colorundalpha.blur()im Prelude und kommt nur in Shader, die einen Blur erreichen. Es bleibt ein Pass.Propertyist ein Uniform: Ändern kompiliert nichts neu.Output. Für einen freistehenden weichen Rand Transparent und Padding setzen.GM_PERF_BLUR=<radius>intools/perf-shaders.mjsundtools/perf-field-shaders.mjs.Was ich selbst festgelegt habe
prepare) melden, die der Compiler einmal in eine lokale Variable legt. Sonst hättencolorundalphaje einen eigenen Blur gerechnet, also doppelte Kosten.Sample texturemit gespeister UV.radiushat Schrittweite 0,5.Messung (stein2, Intel HD 630, Bilder je Sekunde, ein Lauf je Wert, Box)
Ohne Shader hielten dieselben Szenen 59,0 bis 60,1.
Radius 2 ist billig. Ab 4 bestimmen die Samples den Preis. Ein einziges Feld mit Radius 8 kostet schon 8 Bilder je Sekunde (289 Samples je Pixel). Zwei Passes (#301) kämen dort mit 34 aus.
Tests
Propertyweichgezeichnet: 187 / 173 / 154 im Rotkanal bei Radius 0,5 / 1 / 4. Gerechnet sind 188 / 173 / 154. Dazwischen wird nichts kompiliert.#e63c3c) und hat 5/9 Deckkraft (gemessen 0,556), also kein Saum.tests/core/shader-blur.test.ts.#802121).