pixijs-custom-rendering
pixijs/pixijs
Verwenden Sie diese Funktion beim Schreiben benutzerdefinierter Shader, Uniforms, Filter oder Batcher in PixiJS v8. Behandelt Shader.from({gl, gpu, resources}), GlProgram/GpuProgram, UniformGroup mit typisierten Uniforms (f32, vec2, mat4x4), den UBO-Modus, Texturen als Ressourcen, benutzerdefinierte Filter über `Filter.from`, GLSL-ES-3.0-Konventionen (in/out, finalColor, texture()), `uBackTexture`-Sampling, `pixi.js/unsafe-eval` für strikte CSP sowie benutzerdefinierte Batcher über Erweiterungen. Löst bei folgenden Elementen aus: Shader, GlProgram, GpuProgram, UniformGroup, Batcher, Filter, Filter.from, GLSL, WGSL, UBO, Uniform, benutzerdefinierter Shader, finalColor, uBackTexture, blendRequired, unsafe-eval.
...Alle erweiternBenutzerdefinierte Shader binden GLSL- und WGSL-Programme über `Shader.from({ gl, gpu, resources })` an Szenenobjekte. Uniforms werden in typisierten `UniformGroups`gespeichert, Texturen werden als separate Ressourcen übergeben, und derselbe Shader kann sowohl für WebGL als auch für WebGPU verwendet werden.
Schnellstart
const uniforms = new UniformGroup({
uTime: { value: 0, type: "f32" },
});const shader = Shader.from({
gl: { vertex: vertexSrc, fragment: fragmentSrc },
resources: { uniforms },
});const geometry = new MeshGeometry({
positions: new Float32Array([0, 0, 100, 0, 100, 100, 0, 100]),
uvs: new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]),
indices: new Uint32Array([0, 1, 2, 0, 2, 3]),
});const mesh = new Mesh({ geometry, shader });
app.stage.addChild(mesh);app.ticker.add(() => {
shader.resources.uniforms.uniforms.uTime = performance.now() / 1000;
});
Verwandte Funktionen: pixijs-filters (integrierte Filter), pixijs-scene-mesh (benutzerdefinierte Geometrie), pixijs-performance (Batch-Optimierung), pixijs-migration-v8 (Migration der Shader-API von v7).
Kernmuster
Shader mit zwei Renderern (WebGL + WebGPU)
import { Shader, GlProgram, GpuProgram, UniformGroup } from "pixi.js";const glVertex = `...`; // GLSL-Vertex (füge selbst `#version 300 es` ein, wenn du WebGL2/GLSL ES 3.0 verwenden möchtest)
const glFragment = `...`; // GLSL-Fragment
const wgslSource = `...`; //WGSL-Kombinationconst shader = Shader.from({
gl: { vertex: glVertex, fragment: glFragment },
gpu: {
// Die Namen der Einstiegspunkte sind beliebig; sie müssen mit den @vertex- bzw. @fragment-
// Funktionsnamen in Ihrer WGSL-Quelle übereinstimmen . PixiJS liefert Beispiele mit
// „mainVert“ / „mainFrag“, aber „main“ ist ebenso gültig.
vertex: { entryPoint: "mainVert", source: wgslSource },
fragment: { entryPoint: "mainFrag", source: wgslSource },
},
resources: {
myUniforms: new UniformGroup({
uColor: { value: new Float32Array([1, 0, 0, 1]), type: "vec4" },
uMatrix: { value: new Float32Array(16), type: "mat4x4" },
}),
},
});
Wenn nur „gl“ angegeben wird, funktioniert der Shader nur mit WebGL. Wenn nur „gpu“ angegeben wird, funktioniert er nur mit WebGPU. Die Bitmaske „compatibleRenderers“ wird automatisch gesetzt.
„GlProgram“ fügt „#version 300 es“ nicht automatisch ein. Wenn Sie #version 300 es selbst schreiben, behält PixiJS dies bei und behandelt den Shader als GLSL ES 3.0; andernfalls fügt es WebGL1-Kompatibilitätsmakros ein (#define in varying, #define texture texture2D) und führt den Shader als GLSL im WebGL1-Stil aus. GlProgram fügt immer eine Standardpräzision (highp für Vertex, mediump für Fragment) sowie den Programmnamen ein. Für GLSL ES 3.0 verwenden Sie„in/out“ anstelle von„attribute/varying“, „texture()“ anstelle von „texture2D()“ und ein „out vec4“ anstelle von „gl_FragColor“.
Texturen als Ressourcen
Texturen sind Ressourcen, keine Uniforms. Übergeben Sie die Quelle und den Stil der Textur separat:
import { Shader, UniformGroup, Texture, Assets } from "pixi.js";const texture = await Assets.load("myImage.png");const shader = Shader.from({
gl: { vertex: vertSrc, fragment: fragSrc },
resources: {
uTexture: texture.source,
uSampler: texture.source.style,
myUniforms: new UniformGroup({
uAlpha: { value: 1.0, type: "f32" },
}),
},
});// Textur zur Laufzeit austauschen
shader.resources.uTexture = otherTexture.source;
Ressourcen sind eine flache Schlüssel-Wert-Zuordnung. Der Schlüssel muss mit dem Namen des Uniforms bzw. der Bindung in der Shader-Quelle übereinstimmen.
Ressourcen können auch einfache Objekte sein (die automatisch in eine `UniformGroup` verpackt werden):
const shader = Shader.from({
gl: { vertex: vertSrc, fragment: fragSrc },
resources: {
myUniforms: {
uTime: { value: 0, type: "f32" },
},
},
});
UBO-Modus (Uniform Buffer Objects)
Der UBO-Modus bündelt Uniforms in einem einzigen GPU-Puffer. Erforderlich für WebGPU; optional (WebGL2+) für WebGL.
import { UniformGroup } from "pixi.js";const ubo = new UniformGroup(
{
uProjection: { value: new Float32Array(16), type: "mat4x4" },
uAlpha: { value: 1.0, type: "f32" },
},
{ ubo: true, isStatic: true },
);// Bei „isStatic“ = true muss „update()“ manuell aufgerufen werden
ubo.uniforms.uAlpha = 0.5;
ubo.update();
UBO-Regeln:
- Es werden nur auf
f32undi32basierende Typen unterstützt (keinu32). Matrizen sind ausschließlich vom Typ „float“. - Sampler/Texturen können nicht in einem UBO enthalten sein.
- Der Name der „UniformGroup“ in den Ressourcen muss exakt mit dem Namen des UBO-Blocks im Shader übereinstimmen.
- Struktur und Reihenfolge müssen genau mit dem Shader-Layout übereinstimmen.
- Die UBO-Synchronisation nutzt intern
die neue „Function“-Funktion. In strengen CSP-Umgebungen (ohne„unsafe-eval“) muss„pixi.js/unsafe-eval“einmalig beim Start importiert werden, um auf den Fallback-Synchronisationspfad umzuschalten; andernfalls lösen UBO-gestützte Shader (und damit WebGPU) bei der ersten Verwendung einen Fehler aus.
Benutzerdefinierter Filter
Filter.from({ gl, resources }) ist die Kurzschreibweise. Übergeben Sie nur einen Fragment-Shader; PixiJS stellt einen Standard-Vertex-Shader bereit, der die Positionierung des Ausgabeframes übernimmt.
import { Filter } from "pixi.js";const filter = Filter.from({
gl: {
fragment: `
in vec2 vTextureCoord;
out vec4 finalColor;
uniform sampler2D uTexture;
uniform float uStrength; void main(void) {
vec4 color = texture(uTexture, vTextureCoord);
finalColor = mix(color, vec4(1.0 - color.rgb, color.a), uStrength);
}
`,
},
resources: {
filterUniforms: {
uStrength: { value: 0.5, type: "f32" },
},
},
});filter.resources.filterUniforms.uniforms.uStrength = 1.0;
Für einen benutzerdefinierten Vertex-Shader verwenden Sie new Filter({ glProgram: new GlProgram({ vertex, fragment }), resources }).
Filter-Shader-Konventionen (GLSL ES 3.0)
in vec2 vTextureCoord;anstelle vonvarying vec2 vTextureCoord;out vec4 finalColor;anstelle vongl_FragColortexture(uTexture, uv)anstelle vontexture2D(uTexture, uv)- Der Standard-Vertex-Shader stellt
uInputSize,uOutputFrame,uOutputTexturesowie die HilfsfunktionenfilterVertexPosition()undfilterTextureCoord()bereit
Abtasten des Renderziels hinter dem Filter
Setze `blendRequired: true ` und sample ` uBackTexture ` im Fragment-Shader. PixiJS kopiert die Zielpixel in dieses Uniform, bevor der Filter ausgeführt wird:
const blendFilter = Filter.from({
gl: { fragment: blendFragSrc },
resources: { uniforms: { uAmount: { value: 0.5, type: "f32" } } },
blendRequired: true,
});
Aktivieren Sie `blendRequired` nur, wenn Sie es benötigen; es erzwingt in jedem Frame eine zusätzliche GPU-Kopie.
Uniforms zur Laufzeit aktualisieren
// Zugriff auf die „UniformGroup“ über „resources“
shader.resources.myUniforms.uniforms.uTime = performance.now() / 1000;// Bei „isStatic“-UBOs rufen Sie nach einer Wertänderung „update()“ auf
shader.resources.myUniforms.update();
Referenz zu Uniform-Typen
Eine vollständige Tabelle der unterstützten Typen, ihrer WGSL-/GLSL-Entsprechungen und Wertformate finden Sie in „references/uniform-types.md “.
Benutzerdefinierter Batcher (erweiterungsbasiert)
Die abstrakte Klasse `Batcher` ermöglicht benutzerdefiniertes Batching für spezielle Rendering-Anwendungen. Erstellen Sie eine Unterklasse davon und registrieren Sie diese über Erweiterungen:
import { Batcher, extensions, ExtensionType } from "pixi.js";
import type {
BatcherOptions,
BatchableMeshElement,
BatchableQuadElement,
Geometry,
Shader,
} from "pixi.js";class MyBatcher extends Batcher {
public static extension = {
type: [ExtensionType.Batcher],
name: "my-batcher",
}; public name = "my-batcher";
protected vertexSize = 6; // Floats pro Scheitelpunkt
public geometry: Geometry;
public shader: Shader; constructor(options: BatcherOptions) {
super(options);
// Geometrie und Shader initialisieren
} public packAttributes(
element: BatchableMeshElement,
float32View: Float32Array,
uint32View: Uint32Array,
index: number,
textureId: number,
): void {
// Mesh-Vertex-Attribute in den Batch-Puffer packen
} public packQuadAttributes(
element: BatchableQuadElement,
float32View: Float32Array,
uint32View: Uint32Array,
index: number,
textureId: number,
): void {
// Quad-Vertex-Attribute in den Batch-Puffer packen
}
}extensions.add(MyBatcher);
Elemente verweisen über `batcherName` auf den Batcher. Die Schnittstelle `BatchableElement` erfordert folgende Parameter: `batcherName`, `texture`, `blendMode`, `indexSize`, `attributeSize`, `topology` und `packAsQuad`.
Häufige Fehler
[KRITISCH] Veralteter Konstruktor `Shader.from(vertex, fragment, uniforms)`
Falsch:
const shader = Shader.from(vertex, fragment, { uTime: 1 });
Richtig:
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uniforms: new UniformGroup({
uTime: { value: 1, type: "f32" },
}),
},
});
v8 erfordert ein Options-Objekt mitgl/gpu -Programmen und Ressourcen. Die Positions-API wurde entfernt.
[KRITISCH] „UniformGroup“ ohne Typangabe
Falsch:
new UniformGroup({ uTime: 1 });
Richtig:
new UniformGroup({ uTime: { value: 1, type: "f32" } });
Jede Uniform erfordert ein explizites { value, type } -Paar. Das Weglassen des Typs führt zu einem Laufzeitfehler: „Der Uniform-Typ ‚undefined‘ wird nicht unterstützt.“
[HIGH] UBO mit nicht unterstützten Typen oder falscher Struktur
Der UBO-Modus unterstützt auf f32 und i32 basierende Typen (Skalaren und Vektoren). u32 ist nicht in der Liste der unterstützten UniformGroup-Typen enthalten und löst einen Fehler aus. Matrizen sind ausschließlich vom Typ „float“ (mat*). Sampler können nicht in UBOs platziert werden.
Der Struktur-Name und die Feldreihenfolge müssen exakt mit der UBO-Deklaration des Shaders übereinstimmen. Abweichungen führen zu einer verzerrten Darstellung ohne Fehlermeldung.
[HIGH] Einfügen von Texturen in eine UniformGroup
Falsch:
new UniformGroup({
uTexture: { value: texture, type: "f32" },
});
Richtig:
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uTexture: texture.source,
uSampler: texture.source.style,
myUniforms: new UniformGroup({
uAlpha: { value: 1.0, type: "f32" },
}),
},
});
Texturen sind Ressourcen, keine Uniforms. Übergeben Sie `texture.source ` (TextureSource) und `texture.source.style ` (TextureStyle) als Ressourceneinträge auf oberster Ebene.
API-Referenz
Custom shaders bind GLSL and WGSL programs to scene objects via Shader.from({ gl, gpu, resources }). Uniforms live in typed UniformGroups, textures are passed as separate resources, and the same shader can target both WebGL and WebGPU.
Quick Start
const uniforms = new UniformGroup({
uTime: { value: 0, type: "f32" },
});const shader = Shader.from({
gl: { vertex: vertexSrc, fragment: fragmentSrc },
resources: { uniforms },
});const geometry = new MeshGeometry({
positions: new Float32Array([0, 0, 100, 0, 100, 100, 0, 100]),
uvs: new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]),
indices: new Uint32Array([0, 1, 2, 0, 2, 3]),
});const mesh = new Mesh({ geometry, shader });
app.stage.addChild(mesh);app.ticker.add(() => {
shader.resources.uniforms.uniforms.uTime = performance.now() / 1000;
});
Related skills: pixijs-filters (built-in filters), pixijs-scene-mesh (custom geometry), pixijs-performance (batch optimization), pixijs-migration-v8 (shader API migration from v7).
Core Patterns
Dual-renderer shader (WebGL + WebGPU)
import { Shader, GlProgram, GpuProgram, UniformGroup } from "pixi.js";const glVertex = `...`; // GLSL vertex (write `#version 300 es` yourself if you want WebGL2/GLSL ES 3.0)
const glFragment = `...`; // GLSL fragment
const wgslSource = `...`; // WGSL combinedconst shader = Shader.from({
gl: { vertex: glVertex, fragment: glFragment },
gpu: {
// entryPoint names are arbitrary; they must match the @vertex / @fragment
// function names in your WGSL source. PixiJS ships examples using
// 'mainVert' / 'mainFrag' but `main` is equally valid.
vertex: { entryPoint: "mainVert", source: wgslSource },
fragment: { entryPoint: "mainFrag", source: wgslSource },
},
resources: {
myUniforms: new UniformGroup({
uColor: { value: new Float32Array([1, 0, 0, 1]), type: "vec4<f32>" },
uMatrix: { value: new Float32Array(16), type: "mat4x4<f32>" },
}),
},
});
If only gl is provided, the shader works with WebGL only. If only gpu is provided, it works with WebGPU only. The compatibleRenderers bitmask is set automatically.
GlProgram does not auto-inject #version 300 es. If you write #version 300 es yourself, PixiJS preserves it and treats the shader as GLSL ES 3.0; otherwise it injects WebGL1 compat macros (#define in varying, #define texture texture2D) and runs the shader as WebGL1-style GLSL. GlProgram always injects a default precision (highp vertex, mediump fragment) and the program name. For GLSL ES 3.0, use in/out instead of attribute/varying, texture() instead of texture2D(), and an out vec4 instead of gl_FragColor.
Textures as resources
Textures are resources, not uniforms. Pass the texture's source and style separately:
import { Shader, UniformGroup, Texture, Assets } from "pixi.js";const texture = await Assets.load("myImage.png");const shader = Shader.from({
gl: { vertex: vertSrc, fragment: fragSrc },
resources: {
uTexture: texture.source,
uSampler: texture.source.style,
myUniforms: new UniformGroup({
uAlpha: { value: 1.0, type: "f32" },
}),
},
});// Swap texture at runtime
shader.resources.uTexture = otherTexture.source;
Resources are a flat key-value map. The key must match the uniform/binding name in the shader source.
Resources can also be plain objects (auto-wrapped into UniformGroup):
const shader = Shader.from({
gl: { vertex: vertSrc, fragment: fragSrc },
resources: {
myUniforms: {
uTime: { value: 0, type: "f32" },
},
},
});
UBO mode (Uniform Buffer Objects)
UBO mode packs uniforms into a single GPU buffer. Required for WebGPU; optional (WebGL2+) for WebGL.
import { UniformGroup } from "pixi.js";const ubo = new UniformGroup(
{
uProjection: { value: new Float32Array(16), type: "mat4x4<f32>" },
uAlpha: { value: 1.0, type: "f32" },
},
{ ubo: true, isStatic: true },
);// Must call update() manually when isStatic is true
ubo.uniforms.uAlpha = 0.5;
ubo.update();
UBO rules:
- Only
f32andi32based types are supported (nou32). Matrices are float-only. - Samplers/textures cannot go in a UBO.
- The UniformGroup name in resources must exactly match the UBO block name in the shader.
- Structure and order must exactly match the shader layout.
- UBO sync uses
new Functionunder the hood. In strict-CSP environments (nounsafe-eval), importpixi.js/unsafe-evalonce at startup to swap in the fallback sync path; without it, UBO-backed shaders (and therefore WebGPU) will throw on first use.
Custom filter
Filter.from({ gl, resources }) is the shorthand. Pass only a fragment shader; PixiJS supplies a default vertex shader that handles output frame positioning.
import { Filter } from "pixi.js";const filter = Filter.from({
gl: {
fragment: `
in vec2 vTextureCoord;
out vec4 finalColor;
uniform sampler2D uTexture;
uniform float uStrength; void main(void) {
vec4 color = texture(uTexture, vTextureCoord);
finalColor = mix(color, vec4(1.0 - color.rgb, color.a), uStrength);
}
`,
},
resources: {
filterUniforms: {
uStrength: { value: 0.5, type: "f32" },
},
},
});filter.resources.filterUniforms.uniforms.uStrength = 1.0;
For a custom vertex shader, use new Filter({ glProgram: new GlProgram({ vertex, fragment }), resources }).
Filter shader conventions (GLSL ES 3.0)
in vec2 vTextureCoord;instead ofvarying vec2 vTextureCoord;out vec4 finalColor;instead ofgl_FragColortexture(uTexture, uv)instead oftexture2D(uTexture, uv)- The default vertex shader exposes
uInputSize,uOutputFrame,uOutputTextureand helpersfilterVertexPosition()/filterTextureCoord()
Sampling the render target behind the filter
Set blendRequired: true and sample uBackTexture in the fragment shader. PixiJS copies the destination pixels into that uniform before running the filter:
const blendFilter = Filter.from({
gl: { fragment: blendFragSrc },
resources: { uniforms: { uAmount: { value: 0.5, type: "f32" } } },
blendRequired: true,
});
Only enable blendRequired when you need it; it forces an extra GPU copy every frame.
Updating uniforms at runtime
// Access the UniformGroup via resources
shader.resources.myUniforms.uniforms.uTime = performance.now() / 1000;// For isStatic UBOs, call update() after changing values
shader.resources.myUniforms.update();
Uniform type reference
See references/uniform-types.md for the complete table of supported types, their WGSL/GLSL equivalents, and value formats.
Custom Batcher (extension-based)
The Batcher abstract class enables custom batching for specialized rendering. Subclass it and register via extensions:
import { Batcher, extensions, ExtensionType } from "pixi.js";
import type {
BatcherOptions,
BatchableMeshElement,
BatchableQuadElement,
Geometry,
Shader,
} from "pixi.js";class MyBatcher extends Batcher {
public static extension = {
type: [ExtensionType.Batcher],
name: "my-batcher",
}; public name = "my-batcher";
protected vertexSize = 6; // floats per vertex
public geometry: Geometry;
public shader: Shader; constructor(options: BatcherOptions) {
super(options);
// Initialize geometry and shader
} public packAttributes(
element: BatchableMeshElement,
float32View: Float32Array,
uint32View: Uint32Array,
index: number,
textureId: number,
): void {
// Pack mesh vertex attributes into the batch buffer
} public packQuadAttributes(
element: BatchableQuadElement,
float32View: Float32Array,
uint32View: Uint32Array,
index: number,
textureId: number,
): void {
// Pack quad vertex attributes into the batch buffer
}
}extensions.add(MyBatcher);
Elements reference the batcher by batcherName. The BatchableElement interface requires: batcherName, texture, blendMode, indexSize, attributeSize, topology, and packAsQuad.
Common Mistakes
[CRITICAL] Old Shader.from(vertex, fragment, uniforms) constructor
Wrong:
const shader = Shader.from(vertex, fragment, { uTime: 1 });
Correct:
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uniforms: new UniformGroup({
uTime: { value: 1, type: "f32" },
}),
},
});
v8 requires an options object with gl/gpu programs and resources. The positional API was removed.
[CRITICAL] UniformGroup without type annotation
Wrong:
new UniformGroup({ uTime: 1 });
Correct:
new UniformGroup({ uTime: { value: 1, type: "f32" } });
Every uniform requires an explicit { value, type } pair. Omitting the type causes a runtime error: "Uniform type undefined is not supported."
[HIGH] UBO with unsupported types or wrong structure
UBO mode supports f32 and i32 based types (scalars and vectors). u32 is not in the supported UniformGroup type list and will throw. Matrices are float-only (mat*<f32>). Samplers cannot be placed in UBOs.
The struct name and field order must exactly match the shader's UBO declaration. Mismatches produce garbled rendering with no error.
[HIGH] Putting textures in UniformGroup
Wrong:
new UniformGroup({
uTexture: { value: texture, type: "f32" },
});
Correct:
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uTexture: texture.source,
uSampler: texture.source.style,
myUniforms: new UniformGroup({
uAlpha: { value: 1.0, type: "f32" },
}),
},
});
Textures are resources, not uniforms. Pass texture.source (TextureSource) and texture.source.style (TextureStyle) as top-level resource entries.
API Reference
pixijs-custom-rendering installieren
Laden Sie die Skill-Dateien herunter und entpacken Sie sie in Ihr Verzeichnis „.claude/skills/“.
ZIP herunterladenKlonen Sie das Repository und kopieren Sie die Skill-Dateien in Ihr Projekt.
git clone https://github.com/pixijs/pixijs/tree/dev/skills/pixijs-custom-rendering # Copy the skill folder to .claude/skills/ or .codex/skills/
Kopieren





Heim
