Folge-Issue aus #299 (Antwort 4 im Kommentar vom 2026-10-03): eigene Shader-Funktionen als Asset, selbst wieder ein Graph, die man in einem Shader als Node verwendet. Laut User „später überlegen“, also erst einmal als Idee festgehalten.
Befund
Ein Shader-Graph lässt sich heute nicht zerlegen. Wer dieselbe Rechnung in mehreren Shadern braucht (z. B. Graustufen, ein Rauschen, eine Vignette, ein Umriss aus acht Sample texture), baut sie in jedem Shader neu und pflegt sie an jeder Stelle.
Im Behavior-Graph gibt es das schon: #16 macht ein Behavior mit Start- und End-Node zu einem Node in einem anderen Graph. Die Ports des Aufrufs werden aus Start und End abgeleitet, die Palette listet die Behaviors namentlich, ein Doppelklick öffnet den Graph (#18).
Neuer Asset-Typ Shader function mit eigenem Graph im Shader-Tab. Ein eigener Typ statt eines normalen Shaders, weil eine Funktion keinen Träger hat: kein Output mit Edge und Padding, keine Vorschau an einem Sprite.
Zwei Nodes darin:
Function input deklariert die Eingänge des Aufrufs, je Eintrag Name und Typ (Number oder Color).
Der Aufruf ist ein Node, der den Namen der Funktion trägt. Die Palette listet die Funktionen, ein Ziehen aus der Asset-Liste legt einen Aufruf an, ein Doppelklick öffnet die Funktion.
Kompiliert wird eingebettet: Der Compiler setzt den Graph der Funktion an der Stelle des Aufrufs ein. Es bleibt also ein Pass, und die Bild-Nodes (Texture color, Sample texture, Blur) lesen darin das Bild des Trägers, der den Shader aufruft.
Ändert sich eine Funktion, kompilieren alle Shader neu, die sie aufrufen. Eine umbenannte oder entfernte Ein-/Ausgabe räumt die Verbindungen an den Aufrufen mit auf, wie bei #16.
Eine Funktion, die sich selbst aufruft, auch über Umwege, meldet am Node ein Problem.
Beweis beim Schließen
Eine Funktion „Grayscale“ (color rein, color raus), aus zwei Shadern aufgerufen, zeichnet in beiden dasselbe wie dieselbe Rechnung direkt im Graph.
Eine Änderung an der Funktion wirkt ohne Zutun in beiden Shadern.
Ein neuer Eingang an Function input lässt den Aufruf-Node in einem anderen Shader wachsen, Undo nimmt ihn in beiden zurück.
Ein Selbstaufruf wird gemeldet und kompiliert nicht endlos.
Offen (mit Vorschlag)
Property und Color property in einer Funktion: Vorschlag: nicht erlaubt. Werte kommen über die Eingänge herein, der aufrufende Shader hängt seine eigenen Properties daran. Sonst wüsste niemand, wem die Zeile am Sprite gehört.
Time in einer Funktion: Vorschlag: erlaubt, es ist dieselbe Zeit wie im Aufrufer.
Vertex output in einer Funktion: Vorschlag: nein, eine Funktion rechnet nur Werte.
Funktionen im Behavior-Graph wiederverwenden (gleiche Rechnung auf der CPU): Vorschlag: nein, das sind zwei verschiedene Welten.
Folge-Issue aus #299 (Antwort 4 im Kommentar vom 2026-10-03): eigene Shader-Funktionen als Asset, selbst wieder ein Graph, die man in einem Shader als Node verwendet. Laut User „später überlegen“, also erst einmal als Idee festgehalten.
## Befund
- Ein Shader-Graph lässt sich heute nicht zerlegen. Wer dieselbe Rechnung in mehreren Shadern braucht (z. B. Graustufen, ein Rauschen, eine Vignette, ein Umriss aus acht `Sample texture`), baut sie in jedem Shader neu und pflegt sie an jeder Stelle.
- Im Behavior-Graph gibt es das schon: #16 macht ein Behavior mit `Start`- und `End`-Node zu einem Node in einem anderen Graph. Die Ports des Aufrufs werden aus `Start` und `End` abgeleitet, die Palette listet die Behaviors namentlich, ein Doppelklick öffnet den Graph (#18).
## Zu bauen (Vorschlag, nach dem Muster von #16)
- **Neuer Asset-Typ `Shader function`** mit eigenem Graph im Shader-Tab. Ein eigener Typ statt eines normalen Shaders, weil eine Funktion keinen Träger hat: kein `Output` mit *Edge* und *Padding*, keine Vorschau an einem Sprite.
- **Zwei Nodes darin:**
- `Function input` deklariert die Eingänge des Aufrufs, je Eintrag Name und Typ (Number oder Color).
- `Function output` deklariert die Ausgänge.
- Je Funktion genau einer von beiden, wie bei #16.
- **Der Aufruf** ist ein Node, der den Namen der Funktion trägt. Die Palette listet die Funktionen, ein Ziehen aus der Asset-Liste legt einen Aufruf an, ein Doppelklick öffnet die Funktion.
- **Kompiliert wird eingebettet:** Der Compiler setzt den Graph der Funktion an der Stelle des Aufrufs ein. Es bleibt also ein Pass, und die Bild-Nodes (`Texture color`, `Sample texture`, `Blur`) lesen darin das Bild des Trägers, der den Shader aufruft.
- Ändert sich eine Funktion, kompilieren alle Shader neu, die sie aufrufen. Eine umbenannte oder entfernte Ein-/Ausgabe räumt die Verbindungen an den Aufrufen mit auf, wie bei #16.
- Eine Funktion, die sich selbst aufruft, auch über Umwege, meldet am Node ein Problem.
## Beweis beim Schließen
- Eine Funktion „Grayscale“ (color rein, color raus), aus zwei Shadern aufgerufen, zeichnet in beiden dasselbe wie dieselbe Rechnung direkt im Graph.
- Eine Änderung an der Funktion wirkt ohne Zutun in beiden Shadern.
- Ein neuer Eingang an `Function input` lässt den Aufruf-Node in einem anderen Shader wachsen, Undo nimmt ihn in beiden zurück.
- Ein Selbstaufruf wird gemeldet und kompiliert nicht endlos.
## Offen (mit Vorschlag)
1. **`Property` und `Color property` in einer Funktion:** Vorschlag: nicht erlaubt. Werte kommen über die Eingänge herein, der aufrufende Shader hängt seine eigenen Properties daran. Sonst wüsste niemand, wem die Zeile am Sprite gehört.
2. **`Time` in einer Funktion:** Vorschlag: erlaubt, es ist dieselbe Zeit wie im Aufrufer.
3. **`Vertex output` in einer Funktion:** Vorschlag: nein, eine Funktion rechnet nur Werte.
4. **Funktionen im Behavior-Graph wiederverwenden** (gleiche Rechnung auf der CPU): Vorschlag: nein, das sind zwei verschiedene Welten.
meleki
added the shader label 2026-10-03 13:18:11 +02:00
Asset-Typ „Shader function“ (+ in der Asset-Liste), bearbeitet im Shader-Tab. Statt der Vorschau steht dort „A function shows in the shaders calling it“, die Anzeige rechts zählt Ein- und Ausgänge.
Function input und Function output, je einer pro Funktion. Die Ports legst du im Inspector an, nur Number oder Color.
Der Aufruf trägt den Namen der Funktion. Die Palette im Shader-Tab listet alle Funktionen, man kann sie aus der Asset-Liste in den Graph ziehen, ein Doppelklick öffnet die Funktion.
Eingesetzt, nicht aufgerufen: Der Compiler kopiert den Graph der Funktion an die Stelle des Aufrufs. Das kostet genau so viel wie dieselben Nodes direkt im Graph. Bild-Nodes lesen das Bild des Trägers, Time ist dieselbe Uhr.
Ports wandern mit: Ein neuer Eingang lässt jeden Aufruf wachsen, Umbenennen nimmt die Kanten mit, Entfernen räumt sie auf, Undo nimmt alles zurück.
Änderungen wirken überall: Jeder Shader, der eine Funktion aufruft, kompiliert neu, auch über mehrere Ebenen.
Probleme zeigt die Funktion an ihren eigenen Nodes und jeder Aufruf mit Namen, z. B. „In Grayscale: …“.
Deine offenen Punkte (wie vorgeschlagen)
Property und Color property gibt es in einer Funktion nicht. Sie fehlen in der Palette, ein eingefügter meldet „A function cannot hold Property“.
Time ist erlaubt.
Vertex output (und Output) gibt es in einer Funktion nicht.
Nicht im Behavior-Graph.
Was ich selbst festgelegt habe
Ein Pass darf in einer Funktion stehen. Er wird ein Pass des aufrufenden Shaders, so kann z. B. ein breiter Blur eine Funktion sein. Zweimal aufgerufen sind es zwei Passes.
Streng beim Selbstaufruf: Eine Funktion, in der irgendwo ein Aufruf hängt, der nicht eingesetzt werden kann (sich selbst, weg, nichts gewählt), wird gar nicht eingesetzt. Das gilt auch, wenn dieser Aufruf mit nichts verbunden ist. Die Palette bietet einen solchen Aufruf erst gar nicht an.
Beweis
Gemessen auf melektaus-atx:
Gate → 228 Files, 3510 Tests, CHECK EXIT 0 (+11 Unit-Tests, +2 für das neue Icon)
e2e 28 → ALL PASSED – 100 checks (+3 in 28l-viii)
Grayscale, aus zwei Shadern aufgerufen, zeichnet dasselbe wie dieselbe Rechnung direkt im Graph: Im Unit-Test ist das Fragment beider Shader zeichengleich mit dem direkt gebauten. Im Browser zeigen direkt und per Aufruf beide #606060/#a2a2a2, byte-gleich.
Eine Änderung an der Funktion wirkt ohne Zutun: Ein Multiply 0,5 in der Funktion halbiert das Grau am Sprite auf #303030/#515151, der Shader selbst bleibt unberührt. Im Unit-Test kompilieren beide Shader genau einmal neu.
Ein neuer Eingang an Function input lässt den Aufruf in einem anderen Shader wachsen (color:vec3 → color:vec3, amount:number), Undo nimmt ihn in beiden zurück. Umbenennen und Entfernen nehmen die Kanten am Aufruf mit.
Selbstaufruf direkt und über eine zweite Funktion wird gemeldet („A function cannot call itself“), der Shader kompiliert nicht und hängt nicht. Im Browser zeigt der Funktions-Tab das Problem am Node.
Doppelklick auf den Aufruf öffnet die Funktion (Anzeige „1 input, 1 output“).
Gegenprobe greift: Kennt der Cache die aufgerufenen Funktionen nicht, fällt 1 Unit-Test, und im Browser bleibt das Sprite nach der Änderung bei #606060.
Gefunden und behoben: Die ersten zwei e2e-Läufe waren rot. Der Doppelklick hat die Funktion nur ausgewählt statt geöffnet. Und ein unverbundener Selbstaufruf zeigte kein Problem, weil der Shader-Tab bisher nur Compiler-Probleme anzeigte.
Nicht im Browser geprüft: das Ziehen aus der Asset-Liste, + Input im Inspector per Maus, ein Pass in einer Funktion (nur Unit-Test), Funktionen an Text, Partikeln, Feld und Kamera.
Gebaut in a526e1b, Doku im Wiki unter [Shaders → Shader functions](https://git.nockal.com/meleki/game-maker/wiki/Shaders) (Wiki 9823f41).
## Was es gibt
- **Asset-Typ „Shader function“** (`+` in der Asset-Liste), bearbeitet im Shader-Tab. Statt der Vorschau steht dort „A function shows in the shaders calling it“, die Anzeige rechts zählt Ein- und Ausgänge.
- **`Function input` und `Function output`**, je einer pro Funktion. Die Ports legst du im Inspector an, nur *Number* oder *Color*.
- **Der Aufruf** trägt den Namen der Funktion. Die Palette im Shader-Tab listet alle Funktionen, man kann sie aus der Asset-Liste in den Graph ziehen, ein Doppelklick öffnet die Funktion.
- **Eingesetzt, nicht aufgerufen:** Der Compiler kopiert den Graph der Funktion an die Stelle des Aufrufs. Das kostet genau so viel wie dieselben Nodes direkt im Graph. Bild-Nodes lesen das Bild des Trägers, `Time` ist dieselbe Uhr.
- **Ports wandern mit:** Ein neuer Eingang lässt jeden Aufruf wachsen, Umbenennen nimmt die Kanten mit, Entfernen räumt sie auf, Undo nimmt alles zurück.
- **Änderungen wirken überall:** Jeder Shader, der eine Funktion aufruft, kompiliert neu, auch über mehrere Ebenen.
- **Probleme** zeigt die Funktion an ihren eigenen Nodes und jeder Aufruf mit Namen, z. B. „In Grayscale: …“.
## Deine offenen Punkte (wie vorgeschlagen)
1. `Property` und `Color property` gibt es in einer Funktion nicht. Sie fehlen in der Palette, ein eingefügter meldet „A function cannot hold Property“.
2. `Time` ist erlaubt.
3. `Vertex output` (und `Output`) gibt es in einer Funktion nicht.
4. Nicht im Behavior-Graph.
## Was ich selbst festgelegt habe
- **Ein `Pass` darf in einer Funktion stehen.** Er wird ein Pass des aufrufenden Shaders, so kann z. B. ein breiter Blur eine Funktion sein. Zweimal aufgerufen sind es zwei Passes.
- **Streng beim Selbstaufruf:** Eine Funktion, in der irgendwo ein Aufruf hängt, der nicht eingesetzt werden kann (sich selbst, weg, nichts gewählt), wird gar nicht eingesetzt. Das gilt auch, wenn dieser Aufruf mit nichts verbunden ist. Die Palette bietet einen solchen Aufruf erst gar nicht an.
## Beweis
Gemessen auf `melektaus-atx`:
```
Gate → 228 Files, 3510 Tests, CHECK EXIT 0 (+11 Unit-Tests, +2 für das neue Icon)
e2e 28 → ALL PASSED – 100 checks (+3 in 28l-viii)
```
- **Grayscale, aus zwei Shadern aufgerufen, zeichnet dasselbe wie dieselbe Rechnung direkt im Graph:** Im Unit-Test ist das Fragment beider Shader zeichengleich mit dem direkt gebauten. Im Browser zeigen direkt und per Aufruf beide `#606060`/`#a2a2a2`, byte-gleich.
- **Eine Änderung an der Funktion wirkt ohne Zutun:** Ein `Multiply` 0,5 in der Funktion halbiert das Grau am Sprite auf `#303030`/`#515151`, der Shader selbst bleibt unberührt. Im Unit-Test kompilieren beide Shader genau einmal neu.
- **Ein neuer Eingang an `Function input`** lässt den Aufruf in einem anderen Shader wachsen (`color:vec3` → `color:vec3, amount:number`), Undo nimmt ihn in beiden zurück. Umbenennen und Entfernen nehmen die Kanten am Aufruf mit.
- **Selbstaufruf** direkt und über eine zweite Funktion wird gemeldet („A function cannot call itself“), der Shader kompiliert nicht und hängt nicht. Im Browser zeigt der Funktions-Tab das Problem am Node.
- **Doppelklick** auf den Aufruf öffnet die Funktion (Anzeige „1 input, 1 output“).
- **Gegenprobe greift:** Kennt der Cache die aufgerufenen Funktionen nicht, fällt 1 Unit-Test, und im Browser bleibt das Sprite nach der Änderung bei `#606060`.
- **Gefunden und behoben:** Die ersten zwei e2e-Läufe waren rot. Der Doppelklick hat die Funktion nur ausgewählt statt geöffnet. Und ein unverbundener Selbstaufruf zeigte kein Problem, weil der Shader-Tab bisher nur Compiler-Probleme anzeigte.
- **Nicht im Browser geprüft:** das Ziehen aus der Asset-Liste, `+ Input` im Inspector per Maus, ein `Pass` in einer Funktion (nur Unit-Test), Funktionen an Text, Partikeln, Feld und Kamera.
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.
Folge-Issue aus #299 (Antwort 4 im Kommentar vom 2026-10-03): eigene Shader-Funktionen als Asset, selbst wieder ein Graph, die man in einem Shader als Node verwendet. Laut User „später überlegen“, also erst einmal als Idee festgehalten.
Befund
Sample texture), baut sie in jedem Shader neu und pflegt sie an jeder Stelle.Start- undEnd-Node zu einem Node in einem anderen Graph. Die Ports des Aufrufs werden ausStartundEndabgeleitet, die Palette listet die Behaviors namentlich, ein Doppelklick öffnet den Graph (#18).Zu bauen (Vorschlag, nach dem Muster von #16)
Shader functionmit eigenem Graph im Shader-Tab. Ein eigener Typ statt eines normalen Shaders, weil eine Funktion keinen Träger hat: keinOutputmit Edge und Padding, keine Vorschau an einem Sprite.Function inputdeklariert die Eingänge des Aufrufs, je Eintrag Name und Typ (Number oder Color).Function outputdeklariert die Ausgänge.Texture color,Sample texture,Blur) lesen darin das Bild des Trägers, der den Shader aufruft.Beweis beim Schließen
Function inputlässt den Aufruf-Node in einem anderen Shader wachsen, Undo nimmt ihn in beiden zurück.Offen (mit Vorschlag)
PropertyundColor propertyin einer Funktion: Vorschlag: nicht erlaubt. Werte kommen über die Eingänge herein, der aufrufende Shader hängt seine eigenen Properties daran. Sonst wüsste niemand, wem die Zeile am Sprite gehört.Timein einer Funktion: Vorschlag: erlaubt, es ist dieselbe Zeit wie im Aufrufer.Vertex outputin einer Funktion: Vorschlag: nein, eine Funktion rechnet nur Werte.vorschläge passen
Gebaut in
a526e1b, Doku im Wiki unter Shaders → Shader functions (Wiki 9823f41).Was es gibt
+in der Asset-Liste), bearbeitet im Shader-Tab. Statt der Vorschau steht dort „A function shows in the shaders calling it“, die Anzeige rechts zählt Ein- und Ausgänge.Function inputundFunction output, je einer pro Funktion. Die Ports legst du im Inspector an, nur Number oder Color.Timeist dieselbe Uhr.Deine offenen Punkte (wie vorgeschlagen)
PropertyundColor propertygibt es in einer Funktion nicht. Sie fehlen in der Palette, ein eingefügter meldet „A function cannot hold Property“.Timeist erlaubt.Vertex output(undOutput) gibt es in einer Funktion nicht.Was ich selbst festgelegt habe
Passdarf in einer Funktion stehen. Er wird ein Pass des aufrufenden Shaders, so kann z. B. ein breiter Blur eine Funktion sein. Zweimal aufgerufen sind es zwei Passes.Beweis
Gemessen auf
melektaus-atx:#606060/#a2a2a2, byte-gleich.Multiply0,5 in der Funktion halbiert das Grau am Sprite auf#303030/#515151, der Shader selbst bleibt unberührt. Im Unit-Test kompilieren beide Shader genau einmal neu.Function inputlässt den Aufruf in einem anderen Shader wachsen (color:vec3→color:vec3, amount:number), Undo nimmt ihn in beiden zurück. Umbenennen und Entfernen nehmen die Kanten am Aufruf mit.#606060.+ Inputim Inspector per Maus, einPassin einer Funktion (nur Unit-Test), Funktionen an Text, Partikeln, Feld und Kamera.