pixijs-custom-rendering
pixijs/pixijs
Utilize essa habilidade ao escrever shaders, uniformes, filtros ou batchers personalizados no PixiJS v8. Abrange Shader.from({gl, gpu, resources}), GlProgram/GpuProgram, UniformGroup com uniformes tipados (f32, vec2, mat4x4), modo UBO, texturas como recursos, filtro personalizado via Filter.from, convenções GLSL ES 3.0 (in/out, finalColor, texture()), amostragem de uBackTexture, pixi.js/unsafe-eval para CSP estrito, Batcher personalizado via extensões. Aciona em: Shader, GlProgram, GpuProgram, UniformGroup, Batcher, Filter, Filter.from, GLSL, WGSL, UBO, uniform, shader personalizado, finalColor, uBackTexture, blendRequired, unsafe-eval.
...Expandir tudoOs shaders personalizados vinculam programas GLSL e WGSL aos objetos da cena por meio de Shader.from({ gl, gpu, resources }). Os uniformes ficam em UniformGroupstipados, as texturas são passadas como recursos separados, e o mesmo shader pode ser direcionado tanto para WebGL quanto para WebGPU.
Introdução rápida
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]),
índices: 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;
});
Habilidades relacionadas: pixijs-filters (filtros integrados), pixijs-scene-mesh (geometria personalizada), pixijs-performance (otimização em lote), pixijs-migration-v8 (migração da API de shaders da v7).
Padrões principais
Shader com renderizador duplo (WebGL + WebGPU)
import { Shader, GlProgram, GpuProgram, UniformGroup } from "pixi.js";const glVertex = `...`; // vértice GLSL (escreva `#version 300 es` manualmente se desejar WebGL2/GLSL ES 3.0)
const glFragment = `...`; // fragmento GLSL
const wgslSource = `...`; // WGSLcombinado
const shader = Shader.from({
gl: { vertex: glVertex, fragment: glFragment },
gpu: {
// os nomes dos entryPoints são arbitrários; eles devem corresponder aos nomes das funções @vertex / @fragment
// em sua fonte WGSL. O PixiJS fornece exemplos usando
// 'mainVert' / 'mainFrag', mas `main` também é válido.
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" },
}),
},
});
Se apenas `gl` for fornecido, o shader funciona apenas com WebGL. Se apenas `gpu` for fornecido, ele funciona apenas com WebGPU. A máscara de bits `compatibleRenderers` é definida automaticamente.
O `GlProgram ` não injeta automaticamente ` #version 300 es`. Se você mesmo escrever #version 300 es, o PixiJS o preserva e trata o shader como GLSL ES 3.0; caso contrário, ele injeta macros de compatibilidade com WebGL1 (#define em varying, #define texture texture2D) e executa o shader como GLSL no estilo WebGL1. O GlProgram sempre injeta uma precisão padrão (highp para vértices, mediump para fragmentos) e o nome do programa. Para GLSL ES 3.0, usein/out em vez deattribute/varying, texture() em vez de texture2D() e um out vec4 em vez de gl_FragColor.
Texturas como recursos
Texturas são recursos, não uniformes. Passe a fonte e o estilo da textura separadamente:
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" },
}),
},
});// Trocar a textura em tempo de execução
shader.resources.uTexture = otherTexture.source;
Os recursos são um mapa simples de chave-valor. A chave deve corresponder ao nome do uniforme/binding no código-fonte do shader.
Os recursos também podem ser objetos simples (automaticamente encapsulados em UniformGroup):
const shader = Shader.from({
gl: { vertex: vertSrc, fragment: fragSrc },
resources: {
myUniforms: {
uTime: { value: 0, type: "f32" },
},
},
});
Modo UBO (Uniform Buffer Objects)
O modo UBO agrupa uniformes em um único buffer da GPU. Obrigatório para WebGPU; opcional (WebGL2+) para 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 },
);// É necessário chamar update() manualmente quando isStatic for true
ubo.uniforms.uAlpha = 0.5;
ubo.update();
Regras do UBO:
- Apenas tipos baseados em
f32ei32são suportados (nãou32). Matrizes são apenas do tipo float. - Amostradores/texturas não podem ser incluídos em um UBO.
- O nome do UniformGroup nos recursos deve corresponder exatamente ao nome do bloco UBO no shader.
- A estrutura e a ordem devem corresponder exatamente ao layout do shader.
- A sincronização do UBO utiliza
a nova funçãointernamente. Em ambientes CSP estritos (semunsafe-eval), importepixi.js/unsafe-evaluma vez na inicialização para ativar o caminho de sincronização alternativo; sem isso, os shaders baseados em UBO (e, portanto, o WebGPU) apresentarão erros na primeira utilização.
Filtro personalizado
Filter.from({ gl, resources }) é a sintaxe abreviada. Passe apenas um shader de fragmento; o PixiJS fornece um shader de vértice padrão que lida com o posicionamento do quadro de saída.
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;
Para um shader de vértice personalizado, use new Filter({ glProgram: new GlProgram({ vertex, fragment }), resources }).
Convenções de shader de filtro (GLSL ES 3.0)
em vec2 vTextureCoord;em vez devarying vec2 vTextureCoord;out vec4 finalColor;em vez degl_FragColortexture(uTexture, uv)em vez detexture2D(uTexture, uv)- O shader de vértices padrão expõe
uInputSize,uOutputFrame,uOutputTexturee as funções auxiliaresfilterVertexPosition()/filterTextureCoord()
Amostragem do alvo de renderização por trás do filtro
Defina blendRequired: true e amostre uBackTexture no shader de fragmento. O PixiJS copia os pixels de destino para esse uniforme antes de executar o filtro:
const blendFilter = Filter.from({
gl: { fragment: blendFragSrc },
resources: { uniforms: { uAmount: { value: 0.5, type: "f32" } } },
blendRequired: true,
});
Ative blendRequired somente quando for necessário; isso força uma cópia extra na GPU a cada quadro.
Atualizando uniformes em tempo de execução
// Acesse o UniformGroup por meio de resources
shader.resources.myUniforms.uniforms.uTime = performance.now() / 1000;// Para UBOs isStatic, chame update() após alterar os valores
shader.resources.myUniforms.update();
Referência de tipos de uniformes
Consulte references/uniform-types.md para ver a tabela completa dos tipos suportados, seus equivalentes em WGSL/GLSL e formatos de valor.
Batcher personalizado (baseado em extensão)
A classe abstrata `Batcher ` permite o agrupamento personalizado para renderização especializada. Crie uma subclasse dela e registre-a por meio de extensões:
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 por vértice
public geometry: Geometry;
public shader: Shader; constructor(options: BatcherOptions) {
super(options);
// Inicializar geometria e shader
} public packAttributes(
element: BatchableMeshElement,
float32View: Float32Array,
uint32View: Uint32Array,
index: number,
textureId: number,
): void {
// Empacota os atributos dos vértices da malha no buffer de lote
} public packQuadAttributes(
element: BatchableQuadElement,
float32View: Float32Array,
uint32View: Uint32Array,
index: number,
textureId: number,
): void {
// Empacota os atributos dos vértices do quad no buffer de lote
}
}extensions.add(MyBatcher);
Os elementos fazem referência ao batcher por meio de batcherName. A interface BatchableElement requer: batcherName, texture, blendMode, indexSize, attributeSize, topology e packAsQuad.
Erros comuns
[CRÍTICO] Construtor antigo Shader.from(vertex, fragment, uniforms)
Errado:
const shader = Shader.from(vertex, fragment, { uTime: 1 });
Correto:
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uniforms: new UniformGroup({
uTime: { value: 1, type: "f32" },
}),
},
});
O v8 exige um objeto de opções com programasgl/gpu e recursos. A API posicional foi removida.
[CRÍTICO] UniformGroup sem anotação de tipo
Errado:
new UniformGroup({ uTime: 1 });
Correto:
new UniformGroup({ uTime: { value: 1, type: "f32" } });
Todo uniform requer um par explícito { value, type }. A omissão do tipo causa um erro de tempo de execução: “O tipo de uniform indefinido não é suportado.”
[ALTO] UBO com tipos não suportados ou estrutura incorreta
O modo UBO suporta tipos baseados em f32 e i32 (escalares e vetores). u32 não está na lista de tipos suportados pelo UniformGroup e causará uma exceção. Matriz são apenas do tipo float (mat*). Amostradores não podem ser colocados em UBOs.
O nome da estrutura e a ordem dos campos devem corresponder exatamente à declaração do UBO no shader. Incompatibilidades resultam em renderização distorcida, sem exibição de erro.
[ALTO] Colocando texturas no UniformGroup
Errado:
new UniformGroup({
uTexture: { value: texture, type: "f32" },
});
Correto:
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uTexture: texture.source,
uSampler: texture.source.style,
myUniforms: new UniformGroup({
uAlpha: { value: 1.0, type: "f32" },
}),
},
});
Texturas são recursos, não uniformes. Passe texture.source (TextureSource) e texture.source.style (TextureStyle) como entradas de recurso de nível superior.
Referência da API
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
Instalar pixijs-custom-rendering
Baixe e extraia os arquivos de habilidades para o diretório .claude/skills/.
Baixar ZIPClone o repositório e copie os arquivos da habilidade para o seu projeto.
git clone https://github.com/pixijs/pixijs/tree/dev/skills/pixijs-custom-rendering # Copy the skill folder to .claude/skills/ or .codex/skills/
Copiar





Lar
