完全指南:內(nèi)置濾鏡、高級混合模式與自定義著色器)
PixiJS 過濾器Filters完全指南內(nèi)置濾鏡、高級混合模式與自定義著色器【免費(fèi)下載鏈接】pixijsThe HTML5 Creation Engine: Create beautiful digital content with the fastest, most flexible 2D WebGL renderer.項(xiàng)目地址: https://gitcode.com/gh_mirrors/pi/pixijs過濾器Filters是 PixiJS 后處理體系的核心它們能對任意顯示對象及其子樹施加模糊、顏色調(diào)整、噪點(diǎn)、置換扭曲乃至完全自定義的著色器效果。本文以 filters.md 為骨架結(jié)合 src/filters 目錄下的真實(shí)源碼與 examples 中的示例系統(tǒng)講解五種內(nèi)置過濾器、21 種高級混合模式、兩種自定義過濾器寫法以及渲染管線的底層原理。讀完本文你將能夠在自己的 PixiJS 應(yīng)用中直接套用所有示例代碼并寫出可同時(shí)運(yùn)行于 WebGL 與 WebGPU 的 GLSL/WGSL 過濾器。過濾器是什么對顯示對象施加后處理在 PixiJS 中過濾器Filter是對顯示對象渲染結(jié)果的一次后處理先把對象渲染到離屏紋理再用過濾器的著色器程序把該紋理處理一遍后畫回主幀緩沖。任何繼承自Container的對象Sprite、Graphics、Text 等都可以通過filters屬性掛載過濾器。import { Assets, Sprite, BlurFilter, NoiseFilter } from pixi.js; const texture await Assets.load(photo.png); const sprite new Sprite(texture); // 單個(gè)過濾器 sprite.filters new BlurFilter({ strength: 8 }); // 多個(gè)過濾器按順序依次應(yīng)用 sprite.filters [ new BlurFilter({ strength: 8 }), new NoiseFilter({ noise: 0.5 }), ];[!NOTE]過濾器順序很重要。它們按數(shù)組順序依次執(zhí)行每個(gè)過濾器處理的是上一個(gè)過濾器的輸出結(jié)果因此順序不同最終效果也不同。在源碼層面Filter 類 繼承自Shader并維護(hù)一份Filter.defaultOptions作為所有過濾器的默認(rèn)配置blendMode: normal、resolution: 1、padding: 0、antialias: off、blendRequired: false、clipToViewport: true。構(gòu)造過濾器時(shí)傳入的選項(xiàng)會與默認(rèn)值合并。內(nèi)置過濾器一覽PixiJS 內(nèi)置了五個(gè)開箱即用的過濾器全部位于 src/filters/defaults 目錄過濾器用途AlphaFilter施加統(tǒng)一的透明度BlurFilter高斯模糊ColorMatrixFilter通過 5x4 矩陣做顏色變換DisplacementFilter使用置換貼圖紋理扭曲圖像NoiseFilter添加隨機(jī)噪點(diǎn)營造顆粒質(zhì)感AlphaFilter透明度import { AlphaFilter } from pixi.js; sprite.filters new AlphaFilter({ alpha: 0.5 });alpha取值范圍 0完全透明到 1完全不透明。從源碼看AlphaFilter 的defaultOptions.alpha為1濾鏡運(yùn)行時(shí)會把它寫入名為uAlpha的 uniform并且暴露了可讀寫的alpha屬性供運(yùn)行時(shí)動(dòng)態(tài)修改。值得注意的使用建議寫在源碼注釋中當(dāng)需要對整個(gè)顯示對象樹施加統(tǒng)一透明度時(shí)優(yōu)先使用AlphaFilter而非Container.alpha。因?yàn)镃ontainer.alpha是逐元素逐層相乘的多個(gè)半透明子元素疊加時(shí)會出現(xiàn)視覺上的重疊加深而AlphaFilter是在整棵樹渲染完成后統(tǒng)一施加 alpha表現(xiàn)更符合直覺。同時(shí)它還能免費(fèi)獲得所有過濾器共有的能力——例如為濾鏡指定blendMode讓整棵樹與背景混合、或在容器上設(shè)置filterArea做裁剪。BlurFilter高斯模糊import { BlurFilter } from pixi.js; sprite.filters new BlurFilter({ strength: 8, // 模糊強(qiáng)度默認(rèn) 8 quality: 4, // 模糊趟數(shù)默認(rèn) 4 kernelSize: 5, // 內(nèi)核尺寸默認(rèn) 5 });也可以只對單軸模糊用strengthX/strengthY分別控制水平與垂直方向的強(qiáng)度適合制作運(yùn)動(dòng)模糊或方向性光暈。從實(shí)現(xiàn)看BlurFilter 內(nèi)部并不直接做二維模糊而是組合了兩個(gè)單方向的 BlurFilterPass水平一趟 垂直一趟利用高斯模糊的可分離性把 O(n2) 的卷積拆成兩次 O(n) 卷積大幅降低開銷。apply方法中兩個(gè)方向都非零時(shí)會從TexturePool申請一張同尺寸臨時(shí)紋理先水平模糊到臨時(shí)紋理再垂直模糊到輸出最后歸還紋理。關(guān)于各參數(shù)的源碼細(xì)節(jié)strength同時(shí)設(shè)置 X/Y 強(qiáng)度讀取時(shí)若strengthX ! strengthY會拋出異常見 BlurFilter.ts#L289-L297。舊版 API 的blur/blurX/blurY屬性自 8.3.0 起已廢棄請改用strength系列。kernelSize決定卷積核精度可選值限定為5、7、9、11、13、15奇數(shù)數(shù)值越大精度越高、開銷也越大見 BlurFilter.ts#L76-L79。quality對應(yīng)模糊趟數(shù)越高越平滑但越慢。repeatEdgePixels置為true時(shí)會對邊緣像素做 clamp鉗制采樣避免模糊把透明邊緣卷進(jìn)來此時(shí)padding自動(dòng)歸零見 BlurFilter.ts#L261-L271。legacy選項(xiàng)默認(rèn)false用于恢復(fù) v8 之前的舊模糊趟行為強(qiáng)度按趟數(shù)均勻分?jǐn)偠莾?yōu)化的折半方案并會禁用 WebGPU 的按趟 UBO 批處理一般無需開啟。倉庫示例 examples/filters_blur.ts 展示了真實(shí)用法創(chuàng)建兩個(gè)BlurFilter實(shí)例分別掛到兩個(gè)精靈上然后在app.ticker中用Math.cos/Math.sin驅(qū)動(dòng)模糊強(qiáng)度做呼吸式動(dòng)畫const blurFilter1 new BlurFilter(); const blurFilter2 new BlurFilter(); littleDudes.filters [blurFilter1]; littleRobot.filters [blurFilter2]; app.ticker.add(() { count 0.005; blurFilter1.blur 20 * Math.cos(count); // 注意8.3 起建議改為 strength blurFilter2.blur 20 * Math.sin(count); });ColorMatrixFilter顏色變換import { ColorMatrixFilter } from pixi.js; const colorMatrix new ColorMatrixFilter(); colorMatrix.brightness(0.5, false); colorMatrix.contrast(0.8, false); colorMatrix.saturate(1.2, true); // true 與當(dāng)前矩陣相乘累積效果 sprite.filters colorMatrix;ColorMatrixFilter用一張5x4 矩陣20 個(gè)元素對每個(gè)像素的 RGBA 做線性變換類型定義見 ColorMatrixFilter.ts#L19。所有便捷方法的第二個(gè)參數(shù)multiply控制合并方式false表示用新矩陣替換當(dāng)前矩陣true表示新矩陣與當(dāng)前矩陣相乘從而把多次顏色調(diào)整累積起來內(nèi)部由_multiply實(shí)現(xiàn) 4 行 x 5 列的手寫矩陣乘法見 ColorMatrixFilter.ts#L141-L172。可用預(yù)設(shè)方法均帶multiply參數(shù)brightness、contrast、saturate、desaturate、greyscale別名grayscale、blackAndWhite、hue、negative、sepia、technicolor、polaroid、toBGR、kodachrome、browni、vintage、colorTone、night、predator、lsd、reset。此外還有tint(color, multiply)方法接受任意 ColorSource如0xff0000或green適合做整體染色。所有顏色調(diào)整都可以在運(yùn)行時(shí)連續(xù)調(diào)用、動(dòng)態(tài)切換例如實(shí)現(xiàn)晝夜過渡白天 → 夜晚濾鏡。DisplacementFilter置換貼圖import { Sprite, DisplacementFilter } from pixi.js; const displacementSprite Sprite.from(displacement-map.png); sprite.filters new DisplacementFilter({ sprite: displacementSprite, scale: 20, });DisplacementFilter用一張 Sprite 的紋理作為置換貼圖貼圖中每個(gè)像素的紅色通道決定水平位移量綠色通道決定垂直位移量。scale既可以是單個(gè)數(shù)字均勻縮放也可以傳入{ x, y }形式的PointData分別控制兩個(gè)方向見 DisplacementFilter.ts#L50-L63默認(rèn)值20。源碼中有幾個(gè)值得注意的實(shí)現(xiàn)細(xì)節(jié)DisplacementFilter.ts構(gòu)造時(shí)傳入的sprite會被自動(dòng)設(shè)為renderable falseL174-L176即貼圖精靈本身不會被渲染出來只作為數(shù)據(jù)源因此你完全可以把它加到舞臺上并移動(dòng)/旋轉(zhuǎn)它來驅(qū)動(dòng)動(dòng)畫效果每次apply時(shí)通過filterManager.calculateSpriteMatrix計(jì)算貼圖矩陣并從sprite.worldTransform提取旋轉(zhuǎn)分量寫入uRotationL186-L216保證貼圖跟隨精靈的變換縮放值通過filter.scale.x/filter.scale.y可隨時(shí)讀寫。典型的應(yīng)用場景包括水波漣漪、熱浪扭曲、動(dòng)態(tài)過渡轉(zhuǎn)場。倉庫示例 examples/filters_displacement.ts 與 examples/filters_displacement_interactive.ts 可作參考對應(yīng)貼圖資源位于 examples/assets/pixi-filters 和 examples/assets/pond。NoiseFilter噪點(diǎn)import { NoiseFilter } from pixi.js; sprite.filters new NoiseFilter({ noise: 0.5, // 噪點(diǎn)強(qiáng)度默認(rèn) 0.5 seed: Math.random(), // 隨機(jī)種子默認(rèn) Math.random() });noise控制噪點(diǎn)強(qiáng)度0.1 細(xì)微顆粒、0.5 中等、1.0 最強(qiáng)seed決定噪點(diǎn)圖案——相同 seed 產(chǎn)生完全一致的噪點(diǎn)圖案適合做可復(fù)現(xiàn)的膠片顆?;蜢o態(tài)雪花效果。兩者在運(yùn)行時(shí)均可通過filter.noise、filter.seed屬性動(dòng)態(tài)調(diào)整見 NoiseFilter.ts#L165-L202。高級混合模式除了五種過濾器PixiJS 還通過獨(dú)立導(dǎo)入提供高級混合模式。與過濾器不同它們不是直接應(yīng)用的后處理濾鏡而是注冊到容器上的混合模式blendMode由渲染管線在混合階段生效import pixi.js/advanced-blend-modes; sprite.blendMode color-burn;導(dǎo)入后即可使用以下 21 種混合模式字符串 → 實(shí)現(xiàn)類混合模式字符串類colorColorBlendcolor-burnColorBurnBlendcolor-dodgeColorDodgeBlenddarkenDarkenBlenddifferenceDifferenceBlenddivideDivideBlendexclusionExclusionBlendhard-lightHardLightBlendhard-mixHardMixBlendlightenLightenBlendlinear-burnLinearBurnBlendlinear-dodgeLinearDodgeBlendlinear-lightLinearLightBlendluminosityLuminosityBlendnegationNegationBlendoverlayOverlayBlendpin-lightPinLightBlendsaturationSaturationBlendsoft-lightSoftLightBlendsubtractSubtractBlendvivid-lightVividLightBlend從源碼看導(dǎo)入pixi.js/advanced-blend-modes實(shí)際執(zhí)行的是 init.ts把上述 21 個(gè)混合類通過extensions.add(...)注冊進(jìn)擴(kuò)展系統(tǒng)隨后渲染器就能識別對應(yīng)的混合模式字符串。高 DPI 渲染器上的分辨率問題高級混合模式需要采樣當(dāng)前渲染目標(biāo)來把源像素與目標(biāo)像素背景做混合。與其他過濾器一樣它們創(chuàng)建時(shí)使用Filter.defaultOptions其默認(rèn)resolution為1為了性能。如果你的渲染器使用了非1的分辨率例如高 DPI 屏且高級混合模式出現(xiàn)被裁剪、被縮放、或只部分生效的現(xiàn)象請?jiān)趧?chuàng)建使用高級混合模式的過濾器或顯示對象之前選擇繼承渲染目標(biāo)分辨率import { Filter } from pixi.js; import pixi.js/advanced-blend-modes; Filter.defaultOptions.resolution inherit; sprite.blendMode overlay;inherit使過濾器按當(dāng)前渲染目標(biāo)的分辨率渲染能提升這類對分辨率敏感的混合效果的真實(shí)度代價(jià)是相比默認(rèn)值1會增加顯存占用與運(yùn)行時(shí)開銷。自定義過濾器內(nèi)置過濾器不夠用時(shí)可以用 GLSL 著色器編寫自己的過濾器。PixiJS v8 采用GLSL ES 3.0 風(fēng)格用in/out代替attribute/varying用texture()代替texture2D。使用Filter.from()推薦快速上手最簡方式通常只需提供片元著色器頂點(diǎn)著色器由 PixiJS 提供默認(rèn)實(shí)現(xiàn)負(fù)責(zé)頂點(diǎn)位置計(jì)算傳undefined或省略即可使用默認(rèn)頂點(diǎn)著色器。下面的例子用片元著色器做一個(gè)反色效果const simpleFilter Filter.from({ gl: { fragment: in vec2 vTextureCoord; out vec4 finalColor; uniform sampler2D uTexture; void main(void) { vec4 color texture(uTexture, vTextureCoord); finalColor vec4(1.0 - color.rgb, color.a); // 反色 } , }, resources: {}, });從實(shí)現(xiàn)看Filter.from會調(diào)用GlProgram.from/GpuProgram.from把著色器源碼編譯成程序再包一層Filter見 Filter.ts#L261-L283。若需要同時(shí)完全控制頂點(diǎn)與片元著色器可以寫一個(gè)水波濾鏡——片元著色器按正弦波橫向偏移采樣坐標(biāo)uTime隨時(shí)間遞增形成波動(dòng)動(dòng)畫import { Filter } from pixi.js; const waveFilter Filter.from({ gl: { vertex: in vec2 aPosition; out vec2 vTextureCoord; uniform vec4 uInputSize; uniform vec4 uOutputFrame; uniform vec4 uOutputTexture; vec4 filterVertexPosition(void) { vec2 position aPosition * uOutputFrame.zw uOutputFrame.xy; position.x position.x * (2.0 / uOutputTexture.x) - 1.0; position.y position.y * (2.0 * uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z; return vec4(position, 0.0, 1.0); } vec2 filterTextureCoord(void) { return aPosition * (uOutputFrame.zw * uInputSize.zw); } void main(void) { gl_Position filterVertexPosition(); vTextureCoord filterTextureCoord(); } , fragment: in vec2 vTextureCoord; out vec4 finalColor; uniform sampler2D uTexture; uniform float uWaveAmplitude; uniform float uWaveFrequency; uniform float uTime; void main(void) { vec2 coord vTextureCoord; coord.x sin(coord.y * uWaveFrequency uTime) * uWaveAmplitude; finalColor texture(uTexture, coord); } , }, resources: { waveUniforms: { uWaveAmplitude: { value: 0.05, type: f32 }, uWaveFrequency: { value: 10.0, type: f32 }, uTime: { value: 0.0, type: f32 }, }, }, }); sprite.filters [waveFilter]; app.ticker.add((ticker) { waveFilter.resources.waveUniforms.uniforms.uTime 0.1 * ticker.deltaTime; });這段代碼中resources里的 uniform 會在渲染時(shí)自動(dòng)綁定無需手動(dòng)上傳。注意gl_Position filterVertexPosition()與vTextureCoord filterTextureCoord()是默認(rèn)頂點(diǎn)著色器的標(biāo)準(zhǔn)套路對應(yīng)文檔中的著色器約定一節(jié)。使用new Filter()配合預(yù)編譯程序需要更高控制力時(shí)可以自己構(gòu)造GlProgram/GpuProgram再傳入Filter構(gòu)造函數(shù)import { Filter, GlProgram } from pixi.js; const glProgram new GlProgram({ vertex: vertexSrc, fragment: fragmentSrc }); const filter new Filter({ glProgram, resources: { timeUniforms: { uTime: { value: 0.0, type: f32 }, }, }, });著色器編寫約定片元著色器使用out vec4 finalColor;輸出顏色不是gl_FragColor采樣紋理使用texture()不是texture2D默認(rèn)頂點(diǎn)著色器提供filterVertexPosition()與filterTextureCoord()輔助函數(shù)處理輸出幀定位自定義頂點(diǎn)著色器時(shí)可直接復(fù)用resources中聲明的 uniform 可通過filter.resources.組名.uniforms.uniform名在 JS 側(cè)讀寫如動(dòng)畫循環(huán)里更新uTime。[!NOTE] 為了同時(shí)支持 WebGL 與 WebGPU 雙渲染器請同時(shí)提供glProgramGLSL與gpuProgramWGSL。僅提供一個(gè)時(shí)過濾器在缺少對應(yīng)程序的那個(gè)渲染器上會被跳過、按原樣渲染。倉庫中內(nèi)置過濾器均為雙實(shí)現(xiàn)例如 BlurFilterPass 同時(shí)通過generateBlurGlProgramGLSL與generateBlurProgramWGSL生成兩個(gè)程序。更多示例見 examples/mesh_multipass_shader_effects 與 examples/filters_custom-shader_glsl后者含 custom.frag / custom.vert 可對照。過濾器基礎(chǔ)選項(xiàng)所有過濾器無論內(nèi)置還是自定義都接受以下基礎(chǔ)選項(xiàng)定義于 FilterOptions 接口選項(xiàng)類型默認(rèn)值說明blendModestringnormal過濾器輸出使用的混合模式resolutionnumber \| inherit1渲染分辨率越低性能越好、質(zhì)量越低paddingnumber0過濾器區(qū)域外擴(kuò)的像素?cái)?shù)模糊等會向外擴(kuò)散的效果需要 padding 防止裁切antialiasFilterAntialias \| booleanoff抗鋸齒模式on/off/inherit布爾值會被轉(zhuǎn)換為 on/off見 Filter.ts#L200-L208blendRequiredbooleanfalse是否需要在著色器中讀取背景像素開啟后著色器需聲明uBackTextureuniformclipToViewportbooleantrue是否將過濾器紋理裁剪到視口范圍內(nèi)其中antialias的三種取值語義on強(qiáng)制抗鋸齒、off默認(rèn)關(guān)閉、inherit跟隨渲染目標(biāo)設(shè)置。resolution的inherit見上文高 DPI 場景。渲染管線視角過濾器底層做了什么為了寫出高性能的過濾器代碼理解底層流程很有必要。Filter 類的源碼注釋 完整描述了掛載過濾器后渲染器實(shí)際執(zhí)行的步驟打斷當(dāng)前批次break the current batch用getGlobalBounds遞歸遍歷所有子對象測量目標(biāo)的大小從紋理池獲取2 的冪或屏幕尺寸的紋理把目標(biāo)對象渲染到該紋理離屏渲染再用過濾器的著色器程序把該紋理作為 quad渲染回主幀緩沖。某些過濾器如模糊需要多趟處理性能開銷會進(jìn)一步放大。注釋中還特別強(qiáng)調(diào)了兩點(diǎn)經(jīng)驗(yàn)瓶頸通常不是著色器本身的復(fù)雜度而是頻繁的幀緩沖與著色器切換一個(gè)過濾器作用于一個(gè)含大量對象的容器遠(yuǎn)快于大量對象各自掛過濾器。性能優(yōu)化實(shí)踐限制過濾區(qū)域默認(rèn)每幀 PixiJS 都根據(jù)對象邊界計(jì)算過濾區(qū)域。手動(dòng)設(shè)置sprite.filterArea為固定Rectangle可跳過該計(jì)算并縮小處理范圍。共享過濾器實(shí)例同一個(gè)過濾器實(shí)例可以掛到多個(gè)對象上避免重復(fù)創(chuàng)建與重復(fù)上傳資源。用不到就移除sprite.filters null可完全跳過過濾處理。調(diào)節(jié)質(zhì)量降低BlurFilter的quality可減少趟數(shù)、顯著提速。優(yōu)先使用圖集/烘焙對靜態(tài)效果應(yīng)把效果烘焙進(jìn)紋理而不是運(yùn)行時(shí)用過濾器。import { Rectangle, BlurFilter } from pixi.js; // 把過濾處理限制在 200x200 區(qū)域內(nèi) sprite.filterArea new Rectangle(0, 0, 200, 200); // 在多個(gè)精靈之間共享同一個(gè)模糊實(shí)例 const sharedBlur new BlurFilter({ strength: 4 }); sprite1.filters [sharedBlur]; sprite2.filters [sharedBlur];相關(guān)源碼與延伸閱讀想繼續(xù)深入可在當(dāng)前倉庫中查看以下入口Filter 基類與 FilterOptions過濾器選項(xiàng)、Filter.from、默認(rèn)行為FilterSystem過濾器的渲染調(diào)度系統(tǒng)五個(gè)內(nèi)置過濾器Alpha、Blur、ColorMatrix、Displacement、Noise 各自的實(shí)現(xiàn)與默認(rèn)值高級混合模式21 種混合模式的類實(shí)現(xiàn)與注冊邏輯 init.tsBlurFilter 相關(guān)測試、ColorMatrixFilter 測試驗(yàn)證各參數(shù)行為與渲染結(jié)果可運(yùn)行示例examples/filters_blur.ts、examples/filters_color-matrix.ts、examples/filters_displacement.ts、examples/filters_displacement_interactive.ts、examples/filters_custom-shader_glsl【免費(fèi)下載鏈接】pixijsThe HTML5 Creation Engine: Create beautiful digital content with the fastest, most flexible 2D WebGL renderer.項(xiàng)目地址: https://gitcode.com/gh_mirrors/pi/pixijs創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考