Shader: Divide durch 0 liefert NaN, clamp(NaN) ist treiberabhaengig #64

Closed
opened 2026-09-13 11:27:43 +02:00 by meleki · 1 comment
Owner

Befund

ShaderDivide (src/core/shader/nodes.ts) emittiert (a / b) ohne Guard. Eine Property mit Default 0 an b (oder ein Wert, der zur Laufzeit auf 0 laeuft) ergibt NaN; der Epilog clamp(NaN, 0.0, 1.0) ist in GLSL undefiniert, das Ergebnis haengt vom Treiber ab (Intel, Nvidia und Handy zeigen verschiedene Pixel).

Vorschlag

Eine von beiden Richtungen, oder beide:

  • Guard im Divide-Emit (z. B. b == 0 ? 0 : a / b per mix/step, per Kanal bei vec3).
  • Ein Clamp-Node im Katalog, plus ein Satz auf der Wiki-Seite Shaders, was bei Division durch 0 passiert.

Unit-Test: der erzeugte GLSL-Text enthaelt den Guard; e2e-Pixelcheck mit b = 0 liefert einen definierten Wert.

## Befund `ShaderDivide` (`src/core/shader/nodes.ts`) emittiert `(a / b)` ohne Guard. Eine Property mit Default 0 an `b` (oder ein Wert, der zur Laufzeit auf 0 laeuft) ergibt NaN; der Epilog `clamp(NaN, 0.0, 1.0)` ist in GLSL undefiniert, das Ergebnis haengt vom Treiber ab (Intel, Nvidia und Handy zeigen verschiedene Pixel). ## Vorschlag Eine von beiden Richtungen, oder beide: - Guard im `Divide`-Emit (z. B. `b == 0 ? 0 : a / b` per `mix`/`step`, per Kanal bei vec3). - Ein `Clamp`-Node im Katalog, plus ein Satz auf der Wiki-Seite *Shaders*, was bei Division durch 0 passiert. Unit-Test: der erzeugte GLSL-Text enthaelt den Guard; e2e-Pixelcheck mit `b = 0` liefert einen definierten Wert.
meleki added the low-priorityshader labels 2026-09-13 11:27:43 +02:00
admin added this to the Development project 2026-09-13 13:29:59 +02:00
admin removed this from the Development project 2026-09-13 13:30:59 +02:00
admin added this to the Development project 2026-09-13 13:45:44 +02:00
admin moved this to Next in Development on 2026-09-15 13:34:31 +02:00
Author
Owner

Erledigt in c990dbc.

Divide emittiert nicht mehr (a / b), sondern divide(a, b) — der Guard steht als Funktion im
Prolog neben straight() (src/core/shader/nodes.ts:297):

float divide(float a, float b) { return b == 0.0 ? 0.0 : a / b; }
vec3 divide(vec3 a, vec3 b) { return vec3(divide(a.x, b.x), divide(a.y, b.y), divide(a.z, b.z)); }

Null ist die Antwort, per Kanal bei Farben. Das war im Behavior- und im Partikel-Graphen schon
Hausregel — nur der Shader hatte sie nie bekommen. Damit ist auch clamp(NaN) kein Thema mehr,
weil gar kein NaN mehr entsteht.

Dazu, wie im Issue vorgeschlagen, ein Clamp-Node im Shader-Katalog (value, min, max,
per Kanal bei Farben); der Behavior-Katalog hatte ihn laengst.

Belegt: npm run check gruen (1090 Tests) und — das ist hier der eigentliche Beweis — ein
Pixel-Check im e2e-Schritt 28 auf echter GPU: Divide durch 2 gibt #800000, durch 0 gibt
#000000
statt einer treiberabhaengigen Farbe. CI-Task 53 auf 7e5003b gruen,
ALL PASSED - 930 checks.

Erledigt in `c990dbc`. `Divide` emittiert nicht mehr `(a / b)`, sondern `divide(a, b)` — der Guard steht als Funktion im Prolog neben `straight()` (`src/core/shader/nodes.ts:297`): ```glsl float divide(float a, float b) { return b == 0.0 ? 0.0 : a / b; } vec3 divide(vec3 a, vec3 b) { return vec3(divide(a.x, b.x), divide(a.y, b.y), divide(a.z, b.z)); } ``` Null ist die Antwort, per Kanal bei Farben. Das war im Behavior- und im Partikel-Graphen schon Hausregel — nur der Shader hatte sie nie bekommen. Damit ist auch `clamp(NaN)` kein Thema mehr, weil gar kein NaN mehr entsteht. Dazu, wie im Issue vorgeschlagen, ein **`Clamp`-Node** im Shader-Katalog (`value`, `min`, `max`, per Kanal bei Farben); der Behavior-Katalog hatte ihn laengst. **Belegt:** `npm run check` gruen (1090 Tests) und — das ist hier der eigentliche Beweis — ein Pixel-Check im e2e-Schritt 28 auf echter GPU: `Divide` durch 2 gibt `#800000`, durch **0 gibt `#000000`** statt einer treiberabhaengigen Farbe. CI-Task 53 auf `7e5003b` gruen, `ALL PASSED - 930 checks`.
admin moved this to Done in Development on 2026-09-16 08:18:44 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#64