pixijs-filters

Par pixijs · pixijs-skills

Utilisez cette skill lors de l'application d'effets visuels aux conteneurs PixiJS v8 via le pipeline de filtres. Couvre les filtres intégrés (AlphaFilter, BlurFilter, ColorMatrixFilter, DisplacementFilter, NoiseFilter), les filtres personnalisés via `Filter.from()` avec GLSL/WGSL, les options (resolution, padding, antialias, blendRequired), l'optimisation filterArea, et le package communautaire pixi-filters. Se déclenche sur : filters, BlurFilter, ColorMatrixFilter, DisplacementFilter, NoiseFilter, Filter.from, GLSL filter, pixi-filters, filterArea.

npx skills add https://github.com/pixijs/pixijs-skills --skill pixijs-filters

Appliquez des effets visuels en assignant un filtre (ou un tableau pour le chaînage) à container.filters. Les filtres intégrés couvrent le flou, la matrice de couleurs, le déplacement, l'alpha et le bruit ; les filtres personnalisés encapsulent un shader de fragment GLSL/WGSL via Filter.from(...).

Démarrage rapide

const sprite = new Sprite(await Assets.load("hero.png"));
app.stage.addChild(sprite);

const blur = new BlurFilter({ strength: 4, quality: 4 });
const colorMatrix = new ColorMatrixFilter();
colorMatrix.brightness(1.2, false);

sprite.filters = [blur, colorMatrix];

const container = new Container();
container.filters = [new BlurFilter({ strength: 2 })];
container.filterArea = new Rectangle(0, 0, 800, 600);
app.stage.addChild(container);

Compétences associées : pixijs-custom-rendering (internes des shaders, types d'uniforms), pixijs-blend-modes (composition avec filtres), pixijs-performance (réglage des filtres, filterArea).

Modèles de base

Filtres intégrés

import {
  AlphaFilter,
  BlurFilter,
  ColorMatrixFilter,
  DisplacementFilter,
  NoiseFilter,
  Assets,
  Sprite,
} from "pixi.js";

// Alpha (transparence uniforme sans hiérarchie par enfant)
const alpha = new AlphaFilter({ alpha: 0.5 });

// Blur — strength/quality sont uniformes ; strengthX/strengthY divisent les axes ;
// kernelSize doit être impair (5, 7, 9, ... 15) ; repeatEdgePixels évite les bords transparents
const blur = new BlurFilter({
  strength: 4,
  quality: 4,
  kernelSize: 5,
  repeatEdgePixels: false,
});

// Matrice de couleurs — brightness est l'un des nombreux présets. Autres : tint, hue,
// contrast, saturate, desaturate, greyscale/grayscale, blackAndWhite,
// negative, sepia, technicolor, polaroid, kodachrome, browni, vintage,
// colorTone, night, predator, lsd, reset. Accès direct via
// `colorMatrix.matrix` (tableau de 20 éléments) et `colorMatrix.alpha` (mélange
// entre original et transformé).
const colorMatrix = new ColorMatrixFilter();
colorMatrix.brightness(1.5, false);
colorMatrix.contrast(0.5, true); // multiply s'empile sur la matrice existante
colorMatrix.alpha = 0.7; // mélange à 70% de force

// Déplacement — scale est un nombre ou PointData
const displacementTexture = await Assets.load("displacement_map.png");
const displacementSprite = new Sprite(displacementTexture);
const displacement = new DisplacementFilter({
  sprite: displacementSprite,
  scale: { x: 20, y: 10 },
});

// Bruit — seed est un nombre arbitraire qui détermine le motif du bruit ; la même seed reproduit le même motif
const noise = new NoiseFilter({ noise: 0.5, seed: Math.random() });

sprite.filters = [blur, colorMatrix];

Filtre personnalisé avec Filter.from()

Le moyen le plus simple de créer un filtre personnalisé. Seul un shader de fragment est nécessaire ; PixiJS fournit un vertex shader par défaut.

import { Filter } from "pixi.js";

const filter = Filter.from({
  gl: {
    fragment: `
            in vec2 vTextureCoord;
            out vec4 finalColor;
            uniform sampler2D uTexture;
            uniform float uTime;

            void main() {
                vec2 uv = vTextureCoord;
                uv.x += sin(uv.y * 10.0 + uTime) * 0.02;
                finalColor = texture(uTexture, uv);
            }
        `,
  },
  resources: {
    timeUniforms: {
      uTime: { value: 0, type: "f32" },
    },
  },
});

sprite.filters = filter;

app.ticker.add((ticker) => {
  filter.resources.timeUniforms.uniforms.uTime += 0.04 * ticker.deltaTime;
});

Pour plus de contrôle, construisez les objets GlProgram/GpuProgram directement :

import { Filter, GlProgram } from "pixi.js";

const glProgram = GlProgram.from({ fragment: fragmentSrc, vertex: vertexSrc });

const filter = new Filter({
  glProgram,
  resources: {
    timeUniforms: {
      uTime: { value: 0, type: "f32" },
    },
  },
});

Points clés :

  • Utilisez out vec4 finalColor dans les shaders de fragment, pas gl_FragColor (GLSL ES 3.0).
  • Utilisez texture() pour l'échantillonnage, pas texture2D.
  • glProgram pour WebGL, gpuProgram pour WebGPU. Omettre l'un passe ce renderer.
  • Les textures vont dans resources, pas dans les uniforms. Le système de filtre fournit automatiquement uTexture (l'entrée).
  • Accédez aux valeurs d'uniforms via filter.resources.{groupName}.uniforms.{name}.

Options de filtre

import { Filter, GlProgram, Rectangle } from "pixi.js";

const filter = new Filter({
  glProgram: GlProgram.from({ fragment }),
  resources: {},
  resolution: 0.5, // défaut 1. Plus bas = plus rapide, plus flou
  padding: 10, // défaut 0. Pixels supplémentaires pour les effets qui étendent les limites
  antialias: "off", // défaut 'off'. 'on' | 'off' | 'inherit'
  blendMode: "normal", // défaut 'normal'
  blendRequired: false, // défaut false. true si le shader échantillonne uBackTexture
  clipToViewport: true, // défaut true
});

// Optimisation : définissez les limites connues pour éviter les mesures à chaque frame
container.filterArea = new Rectangle(0, 0, 800, 600);

// Basculez sans reconstruire le tableau de filtres
filter.enabled = false;

// Partagez une instance de filtre sur plusieurs objets d'affichage
sprite1.filters = [filter];
sprite2.filters = [filter];

Filtres communautaires (pixi-filters)

import { AdjustmentFilter } from "pixi-filters/adjustment";
import { GlowFilter } from "pixi-filters/glow";

sprite.filters = [
  new AdjustmentFilter({ brightness: 1.2, contrast: 1.1 }),
  new GlowFilter({ distance: 15, outerStrength: 2 }),
];

Pour v8, les filtres communautaires utilisent les imports pixi-filters/{name}, non les anciens packages @pixi/filter-*.

Modes de mélange avancés

Les modes de mélange avancés (color-burn, overlay, hard-light, etc.) sont alimentés par le système de filtre et doivent être importés avant utilisation. Ils nécessitent également useBackBuffer: true sur WebGL ; consultez la compétence pixijs-blend-modes pour la liste complète.

import "pixi.js/advanced-blend-modes";

await app.init({ useBackBuffer: true });
sprite.blendMode = "color-burn";

Erreurs courantes

[CRITIQUE] Utilisation de l'ancien constructeur Filter (vertex, fragment, uniforms)

Incorrect :

import { Filter } from "pixi.js";

const filter = new Filter(vertex, fragment, { uTime: 0 });

Correct :

import { Filter, GlProgram } from "pixi.js";

const filter = new Filter({
  glProgram: GlProgram.from({ fragment, vertex }),
  resources: {
    timeUniforms: { uTime: { value: 0, type: "f32" } },
  },
});

v8 utilise un objet options. Les shaders doivent être encapsulés dans GlProgram.from() ou GpuProgram.from(). Les uniforms sont groupés dans resources avec des types explicites. Les textures sont des ressources, pas des uniforms.

[HAUTE] Utilisation des packages @pixi/filter-* pour v8

Incorrect :

import { AdjustmentFilter } from "@pixi/filter-adjustment";

Correct :

import { AdjustmentFilter } from "pixi-filters/adjustment";

Les packages @pixi/filter-* sont v7 uniquement. Pour v8, le package de filtres communautaires s'est restructuré en pixi-filters/{name}.

[HAUTE] Utilisation de trop de filtres sans conteneurisation

Chaque application de filtre requiert un changement de framebuffer, une mesure des limites et une passe de rendu en texture. Un filtre sur un conteneur parent est beaucoup moins cher que le même filtre sur chaque enfant.

Incorrect :

for (const child of container.children) {
  child.filters = [new BlurFilter({ strength: 4 })];
}

Correct :

container.filters = [new BlurFilter({ strength: 4 })];

[HAUTE] Utilisation d'un filtre blendRequired sans useBackBuffer sur WebGL

Les filtres personnalisés et la plupart des filtres communautaires avancés qui définissent blendRequired: true échantillonnent le back buffer. Sur WebGL, cela ne fonctionne que si le renderer a été initialisé avec useBackBuffer: true ; sinon PixiJS enregistre un avertissement et le filtre bascule silencieusement :

await app.init({ useBackBuffer: true });

WebGPU active le back buffer sans condition, cela n'affecte donc que WebGL.

[MOYEN] Ne pas définir filterArea pour les conteneurs de taille connue

Sans filterArea, PixiJS mesure les limites du conteneur à chaque frame via getGlobalBounds(), ce qui traverse récursivement tous les enfants. Pour les conteneurs avec des dimensions connues, définissez filterArea pour éviter ce coût :

import { Rectangle } from "pixi.js";

container.filterArea = new Rectangle(0, 0, 800, 600);
container.filters = [someFilter];

Référence API

Skills similaires