PIXI.js混合多自定义滤镜仅最后一个生效的解决方法求助
解决PIXI.js多个自定义滤镜仅最后一个生效的问题
这是自定义PIXI滤镜时非常常见的坑!你猜的完全正确——问题根源就是你的自定义片段着色器没有正确读取前一个滤镜输出的纹理,而是每次都直接获取Sprite的原始纹理,导致前面的滤镜效果被覆盖了。内置滤镜(比如模糊、噪点)因为都遵循了PIXI滤镜链的规范,所以能正常叠加。
问题本质
PIXI的滤镜链工作逻辑是:每个滤镜会把上一个滤镜处理后的纹理作为输入,依次传递下去。但自定义着色器如果没正确处理这个输入,就会跳过前面所有滤镜,直接用原始Sprite纹理渲染,自然只有最后一个滤镜生效。
具体修复步骤
1. 修正自定义片段着色器的输入逻辑
你的每个自定义片段着色器必须包含PIXI滤镜的基础输入声明,并且从uSampler(而不是原始纹理)读取上一个滤镜的输出。
正确的自定义片段着色器模板应该是这样的:
precision mediump float; // 必须声明这个变量,来自顶点着色器的UV坐标 varying vec2 vTextureCoord; // 这个就是滤镜链传递的输入纹理(上一个滤镜的输出) uniform sampler2D uSampler; // 你的自定义uniform参数 uniform float uHueShift; void main() { // 第一步:读取上一个滤镜的输出颜色 vec4 inputColor = texture2D(uSampler, vTextureCoord); // 第二步:在这里写你的滤镜处理逻辑(比如色相旋转) // 示例:替换成你自己的色相旋转代码 vec3 color = inputColor.rgb; // ... 你的色相旋转处理代码 ... // 第三步:输出处理后的颜色,保留Alpha通道 gl_FragColor = vec4(color, inputColor.a); }
注意:绝对不要在着色器里直接引用Sprite的原始纹理(比如
texture2D(sprite.texture, ...)),必须用uSampler作为输入源。
2. 确保顶点着色器正确传递UV坐标
创建PIXI.Filter时,虽然传undefined会使用默认顶点着色器,但显式指定默认顶点着色器更稳妥,确保vTextureCoord能正确传递给片段着色器:
// 获取PIXI的默认顶点着色器源码 const defaultVertex = PIXI.Filter.defaultVertexSrc; sprite.filters = [ new PIXI.Filter(defaultVertex, SHADER_STRINGS["hue-rotate-shader-fs"], { uHueShift: 90 }), new PIXI.Filter(defaultVertex, SHADER_STRINGS["contrast-shader-fs"], { uContrast: 50 }) ];
3. 检查自定义着色器的其他问题
- 确认你的着色器没有覆盖
uSampler这个uniform变量; - 确保处理颜色时保留了Alpha通道(如果需要的话),避免透明效果异常;
验证方法
修改完着色器后,调换滤镜顺序测试:如果色相旋转和对比度滤镜都能生效,就说明修复成功了。
内容的提问来源于stack exchange,提问作者O_Tester




