Particles: Shader zuweisen #88

Closed
opened 2026-09-14 06:38:57 +02:00 by admin · 1 comment

Wie bei einem Sprite, soll ein Shader zugewiesen werden können. Ich weiß ja nicht wie die Particles gerade gerendert werden. Falls sie als Quad (per Vertex Shader) gerendert werden, dann sollte das kein Problem sein. Wenn nicht, dann erstmal abklären ob das sinnvoll ist bzw. WIE es sinnvoll ist.

Wie bei einem Sprite, soll ein Shader zugewiesen werden können. Ich weiß ja nicht wie die Particles gerade gerendert werden. Falls sie als Quad (per Vertex Shader) gerendert werden, dann sollte das kein Problem sein. Wenn nicht, dann erstmal abklären ob das sinnvoll ist bzw. WIE es sinnvoll ist.
admin added the shaderparticles labels 2026-09-14 06:38:57 +02:00
admin added this to the Development project 2026-09-14 06:38:57 +02:00
admin moved this to Next in Development on 2026-09-14 06:39:01 +02:00
Owner

Geklärt und gebaut — pro Partikel, wie besprochen.

Die Antwort auf die Frage im Issue

Ja, Partikel werden als Quad per Vertex-Shader gerendert, und ParticleContainer.shader ist eine öffentliche, austauschbare Property: GlParticleContainerAdaptor.execute nimmt wörtlich container.shader || pipe.defaultShader.

Der überraschende Teil: es ist billiger als beim Sprite. Bei #77 war gemessen, dass ein beschatteter Sprite seinen Batch verliert — ein Draw-Call pro Sprite. Ein Partikelfeld ist ohnehin schon einer, weil ParticleContainerPipe.addRenderable den Batch von sich aus bricht. Ein Shader daran kostet null zusätzlich: 500 beschattete Partikel sind derselbe eine Call wie 500 einfache.

Das Fragment aus dem Compiler passte unverändert; nur ein zweiter Vertex-Stage kam dazu, weil Pixis Partikel-Vertex GLSL ES 1.00 ist und unserer ES 3.00 — eine Übersetzung, keine Erfindung, wie SPRITE_VERTEX eine ist.

Die eine ehrliche Einschränkung: der Shader sieht das Partikel-Bild, nicht sein Leben. Pixis Partikel-Buffer hat fünf feste Attribute und nimmt kein sechstes, also erreichen Alter, Index und Zufallszahl das Fragment nicht. Das trifft weniger hart als es klingt, weil Farbe, Alpha, Größe und Rotation über das Alter genau das sind, wofür der Partikel-Graph da ist; der Shader ergänzt, was der Graph nicht kann — samplen, UVs verzerren, die Texturgröße lesen.

Kollidierende Namen: eine Quelle ist das einzige Asset, dessen Zeilen aus zwei Graphen kommen. Die eigene Zeile der Quelle gewinnt, der Uniform bleibt auf seinem Default. Auf der Shader-Seite wird nichts verboten — derselbe Uniform an einem Sprite ist legitim, die Kollision existiert nur an diesem einen Träger.

Zwei Funde, die nicht im Issue standen

1. Pixi füllt nur Slots, die man selbst angelegt hat. Der Adaptor schreibt uTexture und seine eigenen uniforms in irgendeinen Shader des Containers — aber Shader.resources ist ein Accessor über die im Konstruktor bekannten Namen. Ein nicht deklarierter Slot wird zur losen JS-Property und nie gebunden. Ohne den leer mitdeklarierten Block bekommt der Vertex keine Transformationsmatrix und die Partikel landen woanders.

2. Der Ladepfad hätte die Werte still weggeworfen. schemaOf in serialize.ts hing an schema !== schemaFor('sprite') — ein Identitätsvergleich, den eine Partikelquelle nie erfüllt. Ihre Shader-Werte wären beim Speichern verschwunden.

Belege

./check.sh CHECK EXIT 0, 935 Tests (931 + 4 neue)
e2e Modul 31 ALL PASSED – 39 Checks (35 + 4 neue), E2E EXIT 0
Gemessen #ffffff bei level 1, #404040 bei 0.25 — exakt, nicht innerhalb einer Toleranz

Fünf Gegenproben, jede beißt an ihrer Stelle:

Verbogen Ergebnis
Kollisionsfilter entfernt 2 Unit-Tests
Ladepfad kennt die Quelle nicht 1 Unit-Test, isoliert
Kein Shader erreicht das Feld 2 FAILED: Partikel bleiben #3cc85a
Uniform wird nicht gelesen 1 FAILED, isoliert: #ffffff statt #404040
Pixis Resource-Slot weggelassen 2 FAILED: #363940 — Partikel ohne Matrix

Eine Sonde war dabei falsch, nicht das Bild: inspectorField("Shader") fand den Tab-Knopf (left: 621) statt der Inspector-Zeile (left: 1068) — grün, aber über etwas anderes. Jetzt prüft der Check die Spalte gegen eine bekannte Zeile mit.

Nicht gebaut

Der Feld-Filter (feldweiter Glow über die Quad-Kanten hinaus) — das wäre ein Pass über eine große Fläche und damit das Gegenteil von gratis. Eigenes Issue, falls gewünscht.

Commit d5e67cd, Wiki 0af2886 (Particles, Shaders, Architecture, Development).

Geklärt und gebaut — **pro Partikel**, wie besprochen. ## Die Antwort auf die Frage im Issue Ja, Partikel werden als Quad per Vertex-Shader gerendert, und `ParticleContainer.shader` ist eine öffentliche, austauschbare Property: `GlParticleContainerAdaptor.execute` nimmt wörtlich `container.shader || pipe.defaultShader`. **Der überraschende Teil: es ist billiger als beim Sprite.** Bei #77 war gemessen, dass ein beschatteter Sprite seinen Batch verliert — ein Draw-Call pro Sprite. Ein Partikelfeld ist ohnehin schon einer, weil `ParticleContainerPipe.addRenderable` den Batch von sich aus bricht. Ein Shader daran kostet **null zusätzlich**: 500 beschattete Partikel sind derselbe eine Call wie 500 einfache. Das Fragment aus dem Compiler passte unverändert; nur ein zweiter Vertex-Stage kam dazu, weil Pixis Partikel-Vertex GLSL ES 1.00 ist und unserer ES 3.00 — eine Übersetzung, keine Erfindung, wie `SPRITE_VERTEX` eine ist. **Die eine ehrliche Einschränkung:** der Shader sieht das Partikel-*Bild*, nicht sein *Leben*. Pixis Partikel-Buffer hat fünf feste Attribute und nimmt kein sechstes, also erreichen Alter, Index und Zufallszahl das Fragment nicht. Das trifft weniger hart als es klingt, weil Farbe, Alpha, Größe und Rotation über das Alter genau das sind, wofür der Partikel-Graph da ist; der Shader ergänzt, was der Graph nicht kann — samplen, UVs verzerren, die Texturgröße lesen. **Kollidierende Namen:** eine Quelle ist das einzige Asset, dessen Zeilen aus *zwei* Graphen kommen. Die eigene Zeile der Quelle gewinnt, der Uniform bleibt auf seinem Default. Auf der Shader-Seite wird nichts verboten — derselbe Uniform an einem Sprite ist legitim, die Kollision existiert nur an diesem einen Träger. ## Zwei Funde, die nicht im Issue standen **1. Pixi füllt nur Slots, die man selbst angelegt hat.** Der Adaptor schreibt `uTexture` und seine eigenen `uniforms` in *irgendeinen* Shader des Containers — aber `Shader.resources` ist ein Accessor über die im Konstruktor bekannten Namen. Ein nicht deklarierter Slot wird zur losen JS-Property und **nie gebunden**. Ohne den leer mitdeklarierten Block bekommt der Vertex keine Transformationsmatrix und die Partikel landen woanders. **2. Der Ladepfad hätte die Werte still weggeworfen.** `schemaOf` in `serialize.ts` hing an `schema !== schemaFor('sprite')` — ein Identitätsvergleich, den eine Partikelquelle nie erfüllt. Ihre Shader-Werte wären beim Speichern verschwunden. ## Belege | | | |---|---| | `./check.sh` | `CHECK EXIT 0`, **935 Tests** (931 + 4 neue) | | e2e Modul 31 | **ALL PASSED – 39 Checks** (35 + 4 neue), `E2E EXIT 0` | | Gemessen | `#ffffff` bei level 1, `#404040` bei 0.25 — exakt, nicht innerhalb einer Toleranz | **Fünf Gegenproben, jede beißt an ihrer Stelle:** | Verbogen | Ergebnis | |---|---| | Kollisionsfilter entfernt | 2 Unit-Tests | | Ladepfad kennt die Quelle nicht | 1 Unit-Test, isoliert | | Kein Shader erreicht das Feld | **2 FAILED**: Partikel bleiben `#3cc85a` | | Uniform wird nicht gelesen | **1 FAILED**, isoliert: `#ffffff` statt `#404040` | | Pixis Resource-Slot weggelassen | **2 FAILED**: `#363940` — Partikel ohne Matrix | Eine Sonde war dabei falsch, nicht das Bild: `inspectorField("Shader")` fand den **Tab-Knopf** (`left: 621`) statt der Inspector-Zeile (`left: 1068`) — grün, aber über etwas anderes. Jetzt prüft der Check die Spalte gegen eine bekannte Zeile mit. ## Nicht gebaut Der **Feld-Filter** (feldweiter Glow über die Quad-Kanten hinaus) — das wäre ein Pass über eine große Fläche und damit das Gegenteil von gratis. Eigenes Issue, falls gewünscht. Commit d5e67cd, Wiki 0af2886 (*Particles*, *Shaders*, *Architecture*, *Development*).
admin moved this to Done in Development on 2026-09-14 11:08:41 +02:00
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#88