option
MaisonMaison Skill Autres pixijs-custom-rendering

pixijs-custom-rendering

pixijs/pixijs pixijs/pixijs

Utilisez cette compétence lorsque vous écrivez des shaders, des uniformes, des filtres ou des batchers personnalisés dans PixiJS v8. Couvre Shader.from({gl, gpu, resources}), GlProgram/GpuProgram, UniformGroup avec des uniformes typés (f32, vec2, mat4x4), le mode UBO, les textures en tant que ressources, les filtres personnalisés via `Filter.from`, les conventions GLSL ES 3.0 (in/out, finalColor, texture()), l’échantillonnage `uBackTexture`, `pixi.js/unsafe-eval` pour un CSP strict, ainsi que les batchers personnalisés via des extensions. Déclencheurs : Shader, GlProgram, GpuProgram, UniformGroup, Batcher, Filter, Filter.from, GLSL, WGSL, UBO, uniform, shader personnalisé, finalColor, uBackTexture, blendRequired, unsafe-eval.

...Développer tout
177
Heure mise à jour 11 août 2026

Les shaders personnalisés associent des programmes GLSL et WGSL à des objets de scène via la méthode `Shader.from({ gl, gpu, resources })`. Les uniformes sont stockés dans des `UniformGroups`typés, les textures sont transmises sous forme de ressources distinctes, et un même shader peut cibler à la fois WebGL et WebGPU.

Démarrage rapide

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;
});

Compétences associées : pixijs-filters (filtres intégrés), pixijs-scene-mesh (géométrie personnalisée), pixijs-performance (optimisation par lots), pixijs-migration-v8 (migration de l'API des shaders depuis la v7).

Modèles de base

Shader à double rendu (WebGL + WebGPU)

import { Shader, GlProgram, GpuProgram, UniformGroup } from "pixi.js";const glVertex = `...`; // Vertex GLSL (écrivez vous-même `#version 300 es` si vous souhaitez utiliser WebGL2/GLSL ES 3.0)
const glFragment = `...`; // fragment GLSL
const wgslSource = `...`; // WGSLcombinéconst shader = Shader.from({
  gl: { vertex: glVertex, fragment: glFragment },
 gpu: {
    // Les noms des points d’entrée sont arbitraires ; ils doivent correspondre  aux noms de fonctions @vertex / @fragment
    // de votre source WGSL. PixiJS fournit des exemples utilisant
    // « mainVert » / « mainFrag », mais « main » est tout aussi valable.
   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" },
    }),
  },
});

Si seul « gl » est fourni, le shader fonctionne uniquement avec WebGL. Si seul « gpu » est fourni, il fonctionne uniquement avec WebGPU. Le masque de bits compatibleRenderers est défini automatiquement.

GlProgram n’ injecte pas automatiquement #version 300 es. Si vous écrivez vous-même #version 300 es, PixiJS le conserve et traite le shader comme du GLSL ES 3.0 ; sinon, il injecte des macros de compatibilité WebGL1 (#define dans varying, #define texture texture2D) et exécute le shader en GLSL de style WebGL1. GlProgram injecte toujours une précision par défaut (highp pour les sommets, mediump pour les fragments) ainsi que le nom du programme. Pour GLSL ES 3.0, utilisezin/out à la place deattribute/varying, texture() à la place de texture2D(), et un vec4 en sortie à la place de gl_FragColor.

Les textures en tant que ressources

Les textures sont des ressources, pas des uniformes. Passez séparément la source et le style de la texture :

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" },
    }),
  },
});// Remplacer la texture à l'exécution
shader.resources.uTexture = otherTexture.source;

Les ressources sont une table clé-valeur plate. La clé doit correspondre au nom de l’uniforme ou de la liaison dans le code source du shader.

Les ressources peuvent également être de simples objets (automatiquement encapsulés dans un `UniformGroup`) :

const shader = Shader.from({
  gl: { vertex: vertSrc, fragment: fragSrc },
 resources: {
    myUniforms: {
      uTime: { value: 0, type: "f32" },
    },
  },
});

Mode UBO (Uniform Buffer Objects)

Le mode UBO regroupe les uniformes dans un seul tampon GPU. Obligatoire pour WebGPU ; facultatif (WebGL2+) pour 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 },
);// Il faut appeler update() manuellement lorsque isStatic est vrai
ubo.uniforms.uAlpha = 0.5;
ubo.update();

Règles UBO :

  • Seuls les types basés sur f32 et i32 sont pris en charge (pas de u32). Les matrices sont exclusivement de type float.
  • Les échantillonneurs/textures ne peuvent pas être placés dans un UBO.
  • Le nom de l’UniformGroup dans les ressources doit correspondre exactement au nom du bloc UBO dans le shader.
  • La structure et l'ordre doivent correspondre exactement à la disposition du shader.
  • La synchronisation UBO utilise en arrière-plan la nouvelle fonction `Function`. Dans les environnements CSP stricts (sans `unsafe-eval`), importez `pixi.js/unsafe-eval` une seule fois au démarrage pour basculer vers le chemin de synchronisation de secours ; sans cela, les shaders basés sur UBO (et donc WebGPU) généreront une exception lors de leur première utilisation.

Filtre personnalisé

Filter.from({ gl, resources }) est la syntaxe abrégée. Ne transmettez qu’un shader de fragment ; PixiJS fournit un shader de sommet par défaut qui gère le positionnement de l’image de sortie.

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;

Pour un shader de sommets personnalisé, utilisez new Filter({ glProgram: new GlProgram({ vertex, fragment }), resources }).

Conventions relatives aux shaders de filtre (GLSL ES 3.0)
  • in vec2 vTextureCoord; au lieu de varying vec2 vTextureCoord;
  • out vec4 finalColor; au lieu de gl_FragColor
  • texture(uTexture, uv) au lieu de texture2D(uTexture, uv)
  • Le shader de sommets par défaut expose les paramètres uInputSize, uOutputFrame, uOutputTexture ainsi que les fonctions d'aide filterVertexPosition() / filterTextureCoord()
Échantillonnage de la cible de rendu derrière le filtre

Définissez blendRequired : true et échantillonnez uBackTexture dans le shader de fragment. PixiJS copie les pixels de destination dans cet uniforme avant d’exécuter le filtre :

const blendFilter = Filter.from({
  gl: { fragment: blendFragSrc },
  resources: { uniforms: { uAmount: { value: 0.5, type: "f32" } } },
  blendRequired: true,
});

N’activez blendRequired que lorsque cela est nécessaire ; cela force une copie supplémentaire sur le GPU à chaque image.

Mise à jour des uniformes à l’exécution

// Accéder à l’UniformGroup via resources
shader.resources.myUniforms.uniforms.uTime = performance.now() / 1000;// Pour les UBO de type isStatic, appeler update() après avoir modifié les valeurs
shader.resources.myUniforms.update();

Référence des types d’uniformes

Consultez le fichier references/uniform-types.md pour obtenir le tableau complet des types pris en charge, leurs équivalents WGSL/GLSL et les formats de valeurs.

Batcher personnalisé (basé sur des extensions)

La classe abstraite ` Batcher ` permet un regroupement personnalisé pour un rendu spécialisé. Créez une sous-classe et enregistrez-la via les 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; // nombre de flottants par sommet
  public geometry: Geometry;
  public shader: Shader;  constructor(options: BatcherOptions) {
    super(options);
    // Initialisation de la géométrie et du shader
  }  public packAttributes(
    element: BatchableMeshElement,
    float32View: Float32Array,
    uint32View: Uint32Array,
    index: number,
    textureId: number,
  ): void {
   // Empaqueter les attributs des sommets du maillage dans le tampon de lot
  }  public packQuadAttributes(
    element: BatchableQuadElement,
    float32View: Float32Array,
    uint32View: Uint32Array,
    index: number,
    textureId: number,
  ): void {
   // Empaqueter les attributs des sommets du quad dans le tampon de lot
  }
}extensions.add(MyBatcher);

Les éléments font référence au batcher via batcherName. L’interface BatchableElement requiert : batcherName, texture, blendMode, indexSize, attributeSize, topology et packAsQuad.

Erreurs courantes

[CRITIQUE] Ancien constructeur Shader.from(vertex, fragment, uniforms)

Incorrect :

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 nécessite un objet d'options avec les programmesgl/gpu et les ressources. L'API positionnelle a été supprimée.

[CRITIQUE] UniformGroup sans annotation de type

Incorrect :

new UniformGroup({ uTime: 1 });

Correct :

new UniformGroup({ uTime: { value: 1, type: "f32" } });

Chaque uniforme nécessite une paire { valeur, type } explicite. L'omission du type provoque une erreur d'exécution : « Le type d'uniforme non défini n'est pas pris en charge. »

[HIGH] UBO avec des types non pris en charge ou une structure incorrecte

Le mode UBO prend en charge les types basés sur f32 et i32 (scalaires et vecteurs). Le type u32 ne figure pas dans la liste des types UniformGroup pris en charge et provoquera une exception. Les matrices sont exclusivement de type float (mat*). Les échantillonneurs ne peuvent pas être placés dans des UBO.

Le nom de la structure et l’ordre des champs doivent correspondre exactement à la déclaration UBO du shader. Toute divergence entraîne un rendu déformé sans message d’erreur.

[HIGH] Placement de textures dans un UniformGroup

Incorrect :

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" },
    }),
  },
});

Les textures sont des ressources, pas des uniformes. Transmettez texture.source (TextureSource) et texture.source.style (TextureStyle) en tant qu’entrées de ressources de niveau supérieur.

Référence de l'API

Voir sur GitHub

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 f32 and i32 based types are supported (no u32). 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 Function under the hood. In strict-CSP environments (no unsafe-eval), import pixi.js/unsafe-eval once 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 of varying vec2 vTextureCoord;
  • out vec4 finalColor; instead of gl_FragColor
  • texture(uTexture, uv) instead of texture2D(uTexture, uv)
  • The default vertex shader exposes uInputSize, uOutputFrame, uOutputTexture and helpers filterVertexPosition() / 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

Tous les fichiers

2 fichiers

Installer pixijs-custom-rendering

Téléchargez et décompressez les fichiers de compétences dans votre répertoire .claude/skills/.

Télécharger le ZIP

Clonez le dépôt et copiez les fichiers de compétence dans votre projet.

git clone https://github.com/pixijs/pixijs/tree/dev/skills/pixijs-custom-rendering # Copy the skill folder to .claude/skills/ or .codex/skills/

Copier Copier
Configuration rapide: Copiez le dossier de la compétence dans .claude/skills/ ; Claude la détectera automatiquement et l'utilisera.
Dépôt pixijs/pixijs

Compétences similaires

v4-new-features
Heure mise à jour 4 août 2026
pixijs-application
Heure mise à jour 4 août 2026
multica-creating-agents
Heure mise à jour 12 août 2026
agent-project-board-sync
Heure mise à jour 3 août 2026
OR