PixiJS 滤镜效果 #

滤镜概述 #

PixiJS 提供了强大的滤镜系统,可以为显示对象添加各种视觉效果。

text
┌─────────────────────────────────────────────────────────────┐
│                    滤镜系统                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   内置滤镜                                                  │
│   ├── BlurFilter(模糊)                                    │
│   ├── ColorMatrixFilter(颜色矩阵)                         │
│   ├── DisplacementFilter(位移)                            │
│   ├── NoiseFilter(噪点)                                   │
│   └── AlphaFilter(透明度)                                 │
│                                                             │
│   扩展滤镜(pixi-filters)                                   │
│   ├── GlowFilter(发光)                                    │
│   ├── OutlineFilter(描边)                                 │
│   ├── DropShadowFilter(投影)                              │
│   ├── TwistFilter(扭曲)                                   │
│   └── 更多特效滤镜                                          │
│                                                             │
│   自定义滤镜                                                │
│   └── 使用 GLSL 着色器                                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

基本使用 #

应用滤镜 #

javascript
import { BlurFilter } from 'pixi.js';

const sprite = PIXI.Sprite.from('image.png');

// 应用单个滤镜
sprite.filters = [new BlurFilter()];

// 应用多个滤镜
sprite.filters = [
  new BlurFilter(),
  new ColorMatrixFilter()
];

移除滤镜 #

javascript
// 移除所有滤镜
sprite.filters = null;

// 移除特定滤镜
sprite.filters = sprite.filters.filter(f => !(f instanceof BlurFilter));

内置滤镜 #

BlurFilter(模糊) #

javascript
import { BlurFilter } from 'pixi.js';

const blurFilter = new BlurFilter();

// 设置模糊强度
blurFilter.blur = 5;        // 统一设置
blurFilter.blurX = 5;       // 水平模糊
blurFilter.blurY = 5;       // 垂直模糊

// 模糊质量
blurFilter.quality = 4;     // 1-10,越高越慢

sprite.filters = [blurFilter];

ColorMatrixFilter(颜色矩阵) #

javascript
import { ColorMatrixFilter } from 'pixi.js';

const colorMatrix = new ColorMatrixFilter();

// 预设效果
colorMatrix.night();         // 夜景
colorMatrix.predator();      // 掠食者视觉
colorMatrix.lsd();           // 迷幻效果
colorMatrix.kodachrome();    // 柯达胶片
colorMatrix.polaroid();      // 拍立得
colorMatrix.technicolor();   // 彩色技术
colorMatrix.browni();        // 棕褐色
colorMatrix.vintage();       // 复古
colorMatrix.colorTone(0.2, 0.88, 0x339900, 0.001);  // 色调
colorMatrix.desaturate();    // 去色
colorMatrix.greyscale(0.5);  // 灰度
colorMatrix.hue(90);         // 色相旋转
colorMatrix.contrast(0.5);   // 对比度
colorMatrix.brightness(0.5); // 亮度
colorMatrix.saturate(0.5);   // 饱和度

sprite.filters = [colorMatrix];

自定义颜色矩阵 #

javascript
const colorMatrix = new ColorMatrixFilter();

// 手动设置矩阵
colorMatrix.matrix = [
  1, 0, 0, 0, 0,   // R
  0, 1, 0, 0, 0,   // G
  0, 0, 1, 0, 0,   // B
  0, 0, 0, 1, 0    // A
];

// 矩阵说明:
// [R', G', B', A', Offset]
// R' = R*r0 + G*r1 + B*r2 + A*r3 + r4
// G' = R*g0 + G*g1 + B*g2 + A*g3 + g4
// B' = R*b0 + G*b1 + B*b2 + A*b3 + b4
// A' = R*a0 + G*a1 + B*a2 + A*a3 + a4

NoiseFilter(噪点) #

javascript
import { NoiseFilter } from 'pixi.js';

const noiseFilter = new NoiseFilter();

// 噪点强度(0-1)
noiseFilter.noise = 0.5;

sprite.filters = [noiseFilter];

DisplacementFilter(位移) #

javascript
import { DisplacementFilter, Sprite } from 'pixi.js';

// 创建位移贴图
const displacementSprite = Sprite.from('displacement-map.png');
displacementSprite.texture.baseTexture.wrapMode = 'repeat';

const displacementFilter = new DisplacementFilter(displacementSprite);

// 位移强度
displacementFilter.scale.x = 50;
displacementFilter.scale.y = 50;

sprite.filters = [displacementFilter];

// 动态效果
app.ticker.add(() => {
  displacementSprite.x += 1;
  displacementSprite.y += 1;
});

AlphaFilter(透明度) #

javascript
import { AlphaFilter } from 'pixi.js';

const alphaFilter = new AlphaFilter();

// 设置透明度
alphaFilter.alpha = 0.5;

sprite.filters = [alphaFilter];

pixi-filters 扩展 #

安装 #

bash
npm install pixi-filters

GlowFilter(发光) #

javascript
import { GlowFilter } from 'pixi-filters';

const glowFilter = new GlowFilter({
  distance: 15,        // 发光距离
  outerStrength: 2,    // 外发光强度
  innerStrength: 0,    // 内发光强度
  color: 0x00ff00,     // 发光颜色
  quality: 0.5         // 质量(0-1)
});

sprite.filters = [glowFilter];

OutlineFilter(描边) #

javascript
import { OutlineFilter } from 'pixi-filters';

const outlineFilter = new OutlineFilter({
  thickness: 2,        // 描边宽度
  color: 0xff0000      // 描边颜色
});

sprite.filters = [outlineFilter];

DropShadowFilter(投影) #

javascript
import { DropShadowFilter } from 'pixi-filters';

const shadowFilter = new DropShadowFilter({
  offset: { x: 4, y: 4 },  // 偏移
  color: 0x000000,          // 颜色
  alpha: 0.5,               // 透明度
  blur: 4,                  // 模糊
  quality: 4                // 质量
});

sprite.filters = [shadowFilter];

TwistFilter(扭曲) #

javascript
import { TwistFilter } from 'pixi-filters';

const twistFilter = new TwistFilter({
  offset: { x: 0.5, y: 0.5 },  // 扭曲中心
  radius: 200,                  // 扭曲半径
  angle: 60                     // 扭曲角度
});

sprite.filters = [twistFilter];

BulgePinchFilter(凸起/捏合) #

javascript
import { BulgePinchFilter } from 'pixi-filters';

const bulgeFilter = new BulgePinchFilter({
  center: [0.5, 0.5],  // 中心点(0-1)
  radius: 200,          // 半径
  strength: 0.5         // 强度(正数凸起,负数捏合)
});

sprite.filters = [bulgeFilter];

PixelateFilter(像素化) #

javascript
import { PixelateFilter } from 'pixi-filters';

const pixelateFilter = new PixelateFilter({
  size: 8  // 像素大小
});

sprite.filters = [pixelateFilter];

RadialBlurFilter(径向模糊) #

javascript
import { RadialBlurFilter } from 'pixi-filters';

const radialBlurFilter = new RadialBlurFilter({
  angle: 5,              // 模糊角度
  center: [0.5, 0.5],    // 中心点
  kernelSize: 5,         // 内核大小
  radius: 0.5            // 半径
});

sprite.filters = [radialBlurFilter];

ShockwaveFilter(冲击波) #

javascript
import { ShockwaveFilter } from 'pixi-filters';

const shockwaveFilter = new ShockwaveFilter({
  center: [0.5, 0.5],  // 中心点
  amplitude: 10,        // 振幅
  wavelength: 100,      // 波长
  brightness: 1.5,      // 亮度
  speed: 200,           // 速度
  radius: 200           // 半径
});

sprite.filters = [shockwaveFilter];

滤镜动画 #

动态模糊 #

javascript
const blurFilter = new BlurFilter();
sprite.filters = [blurFilter];

let direction = 1;
let blurAmount = 0;

app.ticker.add(() => {
  blurAmount += 0.1 * direction;
  
  if (blurAmount >= 10) direction = -1;
  if (blurAmount <= 0) direction = 1;
  
  blurFilter.blur = blurAmount;
});

颜色过渡 #

javascript
const colorMatrix = new ColorMatrixFilter();
sprite.filters = [colorMatrix];

let hue = 0;

app.ticker.add(() => {
  hue = (hue + 1) % 360;
  colorMatrix.hue(hue);
});

位移波浪 #

javascript
const displacementSprite = Sprite.from('displacement-map.png');
displacementSprite.texture.baseTexture.wrapMode = 'repeat';

const displacementFilter = new DisplacementFilter(displacementSprite);
sprite.filters = [displacementFilter];

let count = 0;

app.ticker.add(() => {
  count += 0.05;
  
  displacementSprite.x = Math.sin(count) * 20;
  displacementSprite.y = Math.cos(count) * 20;
  
  displacementFilter.scale.x = Math.sin(count) * 30 + 30;
  displacementFilter.scale.y = Math.cos(count) * 30 + 30;
});

发光脉冲 #

javascript
import { GlowFilter } from 'pixi-filters';

const glowFilter = new GlowFilter({
  distance: 15,
  outerStrength: 2,
  color: 0x00ff00
});

sprite.filters = [glowFilter];

let pulse = 0;

app.ticker.add(() => {
  pulse += 0.05;
  glowFilter.outerStrength = 2 + Math.sin(pulse) * 1.5;
});

自定义滤镜 #

创建自定义滤镜 #

javascript
import { Filter } from 'pixi.js';

const fragmentShader = `
  varying vec2 vTextureCoord;
  uniform sampler2D uSampler;
  uniform float uTime;
  
  void main(void) {
    vec2 uv = vTextureCoord;
    
    // 波浪效果
    uv.x += sin(uv.y * 10.0 + uTime) * 0.01;
    uv.y += cos(uv.x * 10.0 + uTime) * 0.01;
    
    gl_FragColor = texture2D(uSampler, uv);
  }
`;

const customFilter = new Filter(null, fragmentShader, {
  uTime: { type: 'f32', value: 0 }
});

sprite.filters = [customFilter];

// 更新 uniform
app.ticker.add((ticker) => {
  customFilter.uniforms.uTime += ticker.deltaTime * 0.1;
});

传递参数 #

javascript
const fragmentShader = `
  varying vec2 vTextureCoord;
  uniform sampler2D uSampler;
  uniform vec3 uColor;
  uniform float uIntensity;
  
  void main(void) {
    vec4 color = texture2D(uSampler, vTextureCoord);
    
    // 混合颜色
    color.rgb = mix(color.rgb, uColor, uIntensity);
    
    gl_FragColor = color;
  }
`;

const colorTintFilter = new Filter(null, fragmentShader, {
  uColor: { type: 'vec3<f32>', value: [1, 0, 0] },  // 红色
  uIntensity: { type: 'f32', value: 0.5 }
});

sprite.filters = [colorTintFilter];

// 动态更新颜色
colorTintFilter.uniforms.uColor = [0, 1, 0];  // 改为绿色
colorTintFilter.uniforms.uIntensity = 0.8;

顶点着色器 #

javascript
const vertexShader = `
  attribute vec2 aVertexPosition;
  attribute vec2 aTextureCoord;
  
  uniform mat3 projectionMatrix;
  uniform float uTime;
  
  varying vec2 vTextureCoord;
  
  void main(void) {
    vTextureCoord = aTextureCoord;
    
    vec2 position = aVertexPosition;
    
    // 波浪变形
    position.y += sin(position.x * 0.05 + uTime) * 10.0;
    
    gl_Position = vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);
  }
`;

const fragmentShader = `
  varying vec2 vTextureCoord;
  uniform sampler2D uSampler;
  
  void main(void) {
    gl_FragColor = texture2D(uSampler, vTextureCoord);
  }
`;

const waveFilter = new Filter(vertexShader, fragmentShader, {
  uTime: { type: 'f32', value: 0 }
});

实战示例 #

按钮悬停效果 #

javascript
import { GlowFilter } from 'pixi-filters';

class GlowButton extends Container {
  constructor(text, width, height) {
    super();
    
    this.background = new Graphics();
    this.background.roundRect(0, 0, width, height, 8);
    this.background.fill({ color: 0x3366cc });
    
    this.label = new Text({
      text,
      style: { fontFamily: 'Arial', fontSize: 18, fill: 0xffffff }
    });
    this.label.anchor.set(0.5);
    this.label.x = width / 2;
    this.label.y = height / 2;
    
    this.addChild(this.background, this.label);
    
    this.eventMode = 'static';
    this.cursor = 'pointer';
    
    this.glowFilter = new GlowFilter({
      distance: 10,
      outerStrength: 0,
      color: 0xffffff
    });
    
    this.on('pointerover', () => this.onOver());
    this.on('pointerout', () => this.onOut());
  }
  
  onOver() {
    this.filters = [this.glowFilter];
    
    gsap.to(this.glowFilter, {
      outerStrength: 2,
      duration: 0.3
    });
  }
  
  onOut() {
    gsap.to(this.glowFilter, {
      outerStrength: 0,
      duration: 0.3,
      onComplete: () => {
        this.filters = null;
      }
    });
  }
}

场景切换效果 #

javascript
class SceneTransition {
  constructor(app) {
    this.app = app;
    this.container = new Container();
    this.container.sortableChildren = true;
    
    this.overlay = new Graphics();
    this.overlay.rect(0, 0, app.screen.width, app.screen.height);
    this.overlay.fill({ color: 0x000000 });
    this.overlay.alpha = 0;
    this.overlay.zIndex = 1000;
    
    this.container.addChild(this.overlay);
    app.stage.addChild(this.container);
  }
  
  async fadeOut(duration = 0.5) {
    return new Promise((resolve) => {
      gsap.to(this.overlay, {
        alpha: 1,
        duration,
        onComplete: resolve
      });
    });
  }
  
  async fadeIn(duration = 0.5) {
    return new Promise((resolve) => {
      gsap.to(this.overlay, {
        alpha: 0,
        duration,
        onComplete: resolve
      });
    });
  }
  
  async transition(newScene, duration = 0.5) {
    await this.fadeOut(duration);
    // 切换场景
    await this.fadeIn(duration);
  }
}

水波纹效果 #

javascript
import { ShockwaveFilter } from 'pixi-filters';

class WaterRipple {
  constructor(app) {
    this.app = app;
    this.filters = [];
    
    app.stage.eventMode = 'static';
    app.stage.hitArea = app.screen;
    
    app.stage.on('pointerdown', (event) => {
      this.createRipple(event.global.x, event.global.y);
    });
  }
  
  createRipple(x, y) {
    const filter = new ShockwaveFilter({
      center: [x / this.app.screen.width, y / this.app.screen.height],
      amplitude: 10,
      wavelength: 50,
      brightness: 1,
      speed: 500,
      radius: -1
    });
    
    this.filters.push(filter);
    this.app.stage.filters = this.filters;
    
    // 动画完成后移除
    gsap.to(filter, {
      amplitude: 0,
      duration: 2,
      onComplete: () => {
        const index = this.filters.indexOf(filter);
        if (index > -1) {
          this.filters.splice(index, 1);
        }
        
        if (this.filters.length === 0) {
          this.app.stage.filters = null;
        }
      }
    });
  }
}

热扭曲效果 #

javascript
class HeatDistortion {
  constructor(sprite) {
    this.sprite = sprite;
    
    const displacementSprite = Sprite.from('noise.png');
    displacementSprite.texture.baseTexture.wrapMode = 'repeat';
    
    this.displacementFilter = new DisplacementFilter(displacementSprite);
    this.displacementSprite = displacementSprite;
    
    sprite.filters = [this.displacementFilter];
    
    this.time = 0;
  }
  
  update(delta) {
    this.time += delta * 0.02;
    
    this.displacementSprite.x = Math.sin(this.time) * 100;
    this.displacementSprite.y = Math.cos(this.time * 0.8) * 100;
    
    this.displacementFilter.scale.x = 5 + Math.sin(this.time * 2) * 2;
    this.displacementFilter.scale.y = 5 + Math.cos(this.time * 2) * 2;
  }
}

性能优化 #

滤镜性能影响 #

text
┌─────────────────────────────────────────────────────────────┐
│                    滤镜性能影响                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   性能消耗排序(从低到高)                                   │
│                                                             │
│   1. AlphaFilter        - 极低                              │
│   2. ColorMatrixFilter  - 低                                │
│   3. NoiseFilter        - 低                                │
│   4. BlurFilter         - 中(取决于质量和大小)            │
│   5. DisplacementFilter - 中                                │
│   6. GlowFilter         - 高                                │
│   7. OutlineFilter      - 高                                │
│   8. 自定义滤镜         - 取决于着色器复杂度                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

优化建议 #

javascript
// 1. 减少滤镜数量
// 不推荐
sprite.filters = [
  new BlurFilter(),
  new GlowFilter(),
  new ColorMatrixFilter(),
  new NoiseFilter()
];

// 推荐:合并效果
const colorMatrix = new ColorMatrixFilter();
colorMatrix.brightness(0.2);
sprite.filters = [colorMatrix];

// 2. 使用滤镜区域
const blurFilter = new BlurFilter();
blurFilter.blur = 5;
blurFilter.padding = 10;  // 减少计算区域

// 3. 缓存静态滤镜效果
sprite.filters = [new BlurFilter()];
sprite.cacheAsBitmap = true;

// 4. 按需启用滤镜
if (sprite.visible && sprite.alpha > 0) {
  sprite.filters = [blurFilter];
} else {
  sprite.filters = null;
}

滤镜池 #

javascript
class FilterPool {
  constructor() {
    this.pools = new Map();
  }
  
  get(FilterClass, options = {}) {
    const key = FilterClass.name + JSON.stringify(options);
    
    if (!this.pools.has(key)) {
      this.pools.set(key, []);
    }
    
    const pool = this.pools.get(key);
    
    if (pool.length > 0) {
      return pool.pop();
    }
    
    return new FilterClass(options);
  }
  
  release(filter) {
    const key = filter.constructor.name;
    
    if (!this.pools.has(key)) {
      this.pools.set(key, []);
    }
    
    this.pools.get(key).push(filter);
  }
}

const filterPool = new FilterPool();

// 使用
const blurFilter = filterPool.get(BlurFilter, { blur: 5 });
sprite.filters = [blurFilter];

// 释放
filterPool.release(blurFilter);
sprite.filters = null;

下一步 #

掌握了滤镜效果后,接下来学习 高级主题,了解性能优化、最佳实践等高级内容!

最后更新:2026-03-29