PixiJS v8 自定义渲染完全指南:Shader、UniformGroup、Filter 与 Batcher 实战
PixiJS v8 自定义渲染完全指南Shader、UniformGroup、Filter 与 Batcher 实战【免费下载链接】pixijsThe HTML5 Creation Engine: Create beautiful digital content with the fastest, most flexible 2D WebGL renderer.项目地址: https://gitcode.com/gh_mirrors/pi/pixijs本指南以 PixiJS v8 自定义渲染能力为主线系统讲解如何通过Shader.from({ gl, gpu, resources })将 GLSL / WGSL 着色器绑定到场景对象如何用带类型标注的UniformGroup管理 uniform、以独立资源方式传入纹理以及如何基于Filter.from快速构建自定义滤镜、基于扩展机制注册自定义Batcher。读完本文你将掌握 WebGL 与 WebGPU 双渲染器共用的着色器编写范式、UBO 模式的使用边界、滤镜的 GLSL ES 3.0 约定以及常见踩坑点的规避方法。本文对应的技能文档位于 skills/pixijs-custom-rendering/SKILL.md配套的完整 uniform 类型表见 references/uniform-types.md所有结论均可对照src/rendering/与src/filters/下的源码验证。快速上手把第一个自定义着色器挂到 Mesh 上自定义渲染的核心 API 是Shader.from。它接收一个 options 对象其中gl声明 WebGL 着色器源码resources声明 uniform 与纹理资源然后与MeshGeometry、Mesh组合即可渲染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; });从源码层面看Shader是渲染管线中连接「着色器」与「几何体」的枢纽见 Shader.tsWebGL 侧持有GlProgramWebGPU 侧持有GpuProgram两者通过同一个资源对象共享 uniform 数据。若只提供其中一方compatibleRenderers位掩码会自动按0b01WebGL/0b10WebGPU设置缺失的一侧渲染器将无法使用该着色器Shader.ts。需要强调的是v8 的Shader.from只接受 options 对象v7 时代的位置参数构造Shader.from(vertex, fragment, uniforms)已被移除详见下文「常见错误」。核心模式双渲染器着色器WebGL WebGPU一份着色器源码同时支持两种渲染器只需同时提供gl与gpu两个程序描述import { Shader, GlProgram, GpuProgram, UniformGroup } from pixi.js; const glVertex ...; // GLSL vertex如需 WebGL2/GLSL ES 3.0可自行编写 #version 300 es const glFragment ...; // GLSL fragment const wgslSource ...; // WGSL 合并源码 const shader Shader.from({ gl: { vertex: glVertex, fragment: glFragment }, gpu: { // entryPoint 名称可任取但必须与 WGSL 源码中的 vertex / fragment 函数名一致。 // PixiJS 自带示例习惯使用 mainVert / mainFrag使用 main 同样合法。 vertex: { entryPoint: mainVert, source: wgslSource }, fragment: { entryPoint: mainFrag, source: wgslSource }, }, resources: { myUniforms: new UniformGroup({ uColor: { value: new Float32Array([1, 0, 0, 1]), type: vec4f32 }, uMatrix: { value: new Float32Array(16), type: mat4x4f32 }, }), }, });要点只传gl着色器仅支持 WebGL只传gpu仅支持 WebGPU两者都传则自动获得双渲染器兼容。resources中 UniformGroup 的键名必须与着色器源码中的 uniform/binding 名称一致——WebGPU 侧是硬性要求WebGL 侧则相对宽松见 Shader.ts。仓库中可参考的完整双渲染器示例mesh_custom_shader_geometry/index.ts同时提供了triangle.vert/triangle.frag/triangle.wgsl三份源码以及 mesh_custom_color_attributes/index.ts。关于 GLSL 版本的关键事实GlProgram不会自动注入#version 300 es。它的预处理流水线依次执行stripVersion→ensurePrecision→addProgramDefines→setProgramName→insertVersion见 GlProgram.ts若你在源码里自行写了#version 300 esPixiJS 会保留它并按 GLSL ES 3.0 处理否则会注入 WebGL1 兼容宏#define in varying、#define texture texture2D按 WebGL1 风格 GLSL 运行无论哪种情况GlProgram都会注入默认精度顶点highp、片元mediump见 GlProgram.ts与程序名。因此编写 GLSL ES 3.0 时请遵循用in/out替代attribute/varying用texture()替代texture2D()用out vec4替代gl_FragColor。另外GlProgram.from会按「顶点 片元源码」建立程序缓存复用相同源码不会重复编译GlProgram.ts这也是为什么官方建议尽可能复用程序对象。纹理是资源不是 uniform纹理不能放进UniformGroup而是作为独立的顶级资源传入纹理的sourceTextureSource与styleTextureStyle要分开传递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 }, }), }, }); // 运行时切换纹理 shader.resources.uTexture otherTexture.source;资源是一个扁平的键值映射键名必须匹配着色器源码中的 uniform/binding 名。渲染时修改shader.resources中的任意资源即可热更新。便捷机制resources中的普通对象会被自动包装为UniformGroup。这一逻辑在Shader构造器中实现——凡是没有source属性、也不是BindResource的值都会走value new UniformGroup(value)Shader.ts。因此下面两种写法等价const shader Shader.from({ gl: { vertex: vertSrc, fragment: fragSrc }, resources: { myUniforms: { uTime: { value: 0, type: f32 }, }, }, });UBO 模式Uniform Buffer ObjectsUBO 模式把一组 uniform 打包进单个 GPU 缓冲区。WebGPU 只能通过 UBO 使用 uniform因此想在 WebGPU 下跑自定义着色器就必须开启它WebGL2 下则是可选优化。import { UniformGroup } from pixi.js; const ubo new UniformGroup( { uProjection: { value: new Float32Array(16), type: mat4x4f32 }, uAlpha: { value: 1.0, type: f32 }, }, { ubo: true, isStatic: true }, ); // isStatic 为 true 时必须手动调用 update() 触发上传 ubo.uniforms.uAlpha 0.5; ubo.update();UBO 规则源码注释见 UniformGroup.ts仅支持f32与i32系类型标量与向量矩阵仅支持浮点mat*f32u32不在UniformGroup的类型表中会直接抛错。采样器/纹理不能放进 UBOGPU 限制。resources 中的键名必须与着色器中的 UBO 块名完全一致。结构字段名与顺序必须与着色器布局完全一致否则渲染结果错乱且不会报错。UBO 同步底层依赖new Function动态生成同步函数。在禁止unsafe-eval的严格 CSP 环境下需要在启动时一次性引入pixi.js/unsafe-eval以切换到回退同步路径否则首次使用 UBO进而 WebGPU时会抛错。该入口导出generateUboSyncPolyfill等回退实现见 src/unsafe-eval/index.ts 与 src/unsafe-eval/ubo/。另外注意UniformGroup的默认选项为ubo: false、isStatic: falseUniformGroup.ts非静态模式下数据每帧自动重传无需手动update()isStatic: true则把上传时机完全交给你适合每帧只更新一次的 UBO以获得最大性能收益。自定义滤镜Filter.fromFilter.from({ gl, resources })是创建自定义滤镜的快捷方式只需提供片元着色器PixiJS 会自动补一个负责输出帧定位的默认顶点着色器。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;需要自定义顶点着色器时改用完整构造new Filter({ glProgram: new GlProgram({ vertex, fragment }), resources, });Filter继承自ShaderFilter.ts因此它天然具备 Shader 的全部资源能力。其默认配置在 Filter.ts 中定义blendMode: normal、resolution: 1、padding: 0、antialias: off、blendRequired: false、clipToViewport: true。其中resolution可设为数字或inherit调低分辨率可显著提升滤镜性能模糊类滤镜常用padding为滤镜扩展的边界像素模糊等会外溢的效果需要它防止裁切antialias支持on | off | inheritinherit会跟随渲染目标的抗锯齿设置。滤镜可作用于任何继承自Container的对象Sprite、Graphics 等。它的底层流程是打断当前批次 → 用getGlobalBounds测量目标 → 从纹理池取纹理 → 把目标渲染到该纹理 → 再以滤镜程序把纹理作为 quad 画回主帧缓冲见 Filter.ts。正因如此对一个容器应用一次滤镜远比给大量对象各挂一个滤镜快得多。滤镜着色器约定GLSL ES 3.0用in vec2 vTextureCoord;替代varying vec2 vTextureCoord;用out vec4 finalColor;替代gl_FragColor用texture(uTexture, uv)替代texture2D(uTexture, uv)默认顶点着色器暴露uInputSize、uOutputFrame、uOutputTexture及辅助函数filterVertexPosition()/filterTextureCoord()Filter构造时会自动为uTexture预留资源槽位addResource(uTexture, 0, 1)见 Filter.ts所以片元着色器里声明uniform sampler2D uTexture;即可取到滤镜输入。采样滤镜背后的渲染目标当滤镜需要感知「背后已经画好的像素」例如实现混合类效果时设置blendRequired: true然后在片元着色器中采样uBackTexture——滤镜系统会先把目标区域的像素拷贝进该 uniform 再运行滤镜const blendFilter Filter.from({ gl: { fragment: blendFragSrc }, resources: { uniforms: { uAmount: { value: 0.5, type: f32 } } }, blendRequired: true, });从实现看开启后Filter会额外执行addResource(uBackTexture, 0, 3)Filter.ts而关闭时该资源槽不存在。只在确实需要时开启blendRequired——它每帧都会强制增加一次额外的 GPU 拷贝对应源码注释 otherwise its an extra gpu copy you dont need!。运行时更新 uniform// 通过 resources 访问 UniformGroup shader.resources.myUniforms.uniforms.uTime performance.now() / 1000; // 对于 isStatic 的 UBO修改值后要手动调用 update() shader.resources.myUniforms.update();注意UniformGroup.update()的实现是递增_dirtyId以标记数据待上传UniformGroup.ts渲染器据此决定是否重传 GPU 缓冲区。Uniform 类型参考UniformGroup中每个 uniform 都必须以{ value, type }形式声明type字符串直接对应 WebGPU 类型。完整类型表见 references/uniform-types.md以下为速查PixiJS 类型WGSL 等价GLSL 等价JS 值f32f32floatnumberi32i32intnumbervec2f32vec2f32vec2Float32Array(2)或[x, y]vec3f32vec3f32vec3Float32Array(3)vec4f32vec4f32vec4Float32Array(4)vec2i32vec2i32ivec2Int32Array(2)vec3i32vec3i32ivec3Int32Array(3)vec4i32vec4i32ivec4Int32Array(4)mat2x2f32mat2x2f32mat2Float32Array(4)mat3x3f32mat3x3f32mat3Float32Array(9)或Matrixmat4x4f32mat4x4f32mat4Float32Array(16)mat3x2f32mat3x2f32mat3x2Float32Array(6)mat4x2f32mat4x2f32mat4x2Float32Array(8)mat2x3f32mat2x3f32mat2x3Float32Array(6)mat4x3f32mat4x3f32mat4x3Float32Array(12)mat2x4f32mat2x4f32mat2x4Float32Array(8)mat3x4f32mat3x4f32mat3x4Float32Array(12)底层支持类型白名单定义在 types.tsUniformGroup构造时会校验每个 type未命中白名单会抛出Uniform type ... is not supported错误UniformGroup.ts。数组 uniform不要用array...语法写进 type 字段改用size属性import { UniformGroup } from pixi.js; // 10 个 vec4 组成的数组 const uniforms new UniformGroup({ uColors: { value: new Float32Array(40), type: vec4f32, size: 10 }, });若在 type 中写arrayvec4f32, 10构造器会直接抛错并提示改用type: vec4f32, size: 10UniformGroup.ts。常见用法示例// 标量 const uniforms new UniformGroup({ uTime: { value: 0, type: f32 }, uIndex: { value: 0, type: i32 }, }); uniforms.uniforms.uTime 1.5; uniforms.uniforms.uIndex 3; // 向量 const uniforms new UniformGroup({ uPosition: { value: new Float32Array([100, 200]), type: vec2f32 }, uDirection: { value: new Float32Array([0, 1, 0]), type: vec3f32 }, uColor: { value: new Float32Array([1, 0, 0, 1]), type: vec4f32 }, uGridSize: { value: new Int32Array([16, 16]), type: vec2i32 }, }); // 矩阵 import { Matrix } from pixi.js; const uniforms new UniformGroup({ uTransform: { value: new Matrix(), type: mat3x3f32 }, uProjection: { value: new Float32Array(16), type: mat4x4f32 }, uRotation: { value: new Float32Array(4), type: mat2x2f32 }, });注意PixiJS 的 2D 仿射变换矩阵Matrix对应mat3x3f323D 投影矩阵请使用裸Float32Array(16)mat4x4f32。另外即便声明了value之外不传值UniformGroup也会按类型自动补默认值getDefaultUniformValue见 UniformGroup.ts。自定义 Batcher扩展机制Batcher抽象类用于实现针对特殊渲染需求的自定义合批。继承它并实现属性打包逻辑再通过扩展机制注册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; // 每个顶点的 float 数 public geometry: Geometry; public shader: Shader; constructor(options: BatcherOptions) { super(options); // 初始化 geometry 和 shader } public packAttributes( element: BatchableMeshElement, float32View: Float32Array, uint32View: Uint32Array, index: number, textureId: number, ): void { // 把 mesh 顶点属性打包进合批缓冲区 } public packQuadAttributes( element: BatchableQuadElement, float32View: Float32Array, uint32View: Uint32Array, index: number, textureId: number, ): void { // 把 quad 顶点属性打包进合批缓冲区 } } extensions.add(MyBatcher);要素说明扩展通过静态extension属性声明type: [ExtensionType.Batcher]与唯一namevertexSize决定每个顶点的浮点数量与你的顶点格式匹配元素通过batcherName引用该合批器要实现BatchableElement接口需提供batcherName、texture、blendMode、indexSize、attributeSize、topology、packAsQuad等字段。仓库中可直接运行的自定义着色器/滤镜示例还包括 filters_custom-shader_glsl/index.ts、mesh_multipass_shader_effects/index.ts 与 text_filters_cartoon/CartoonTextFilter.ts可作为扩展阅读。常见错误[严重] 沿用 v7 的位置参数构造 Shader错误写法const shader Shader.from(vertex, fragment, { uTime: 1 });正确写法const shader Shader.from({ gl: { vertex, fragment }, resources: { uniforms: new UniformGroup({ uTime: { value: 1, type: f32 }, }), }, });v8 要求传入包含gl/gpu程序与resources的 options 对象位置参数 API 已移除。[严重] UniformGroup 缺少类型标注错误写法new UniformGroup({ uTime: 1 });正确写法new UniformGroup({ uTime: { value: 1, type: f32 } });每个 uniform 都必须提供显式的{ value, type }对。省略 type 会在运行时抛出Uniform type undefined is not supported该校验位于 UniformGroup.ts。[高] UBO 使用了不支持的类型或结构不匹配UBO 模式只支持f32/i32系类型标量与向量u32不在支持列表会抛错矩阵仅限浮点mat*f32采样器不能放入 UBO。此外UBO 的块名、字段名与顺序必须与着色器声明完全一致否则渲染结果会错乱且不会报错。[高] 把纹理放进 UniformGroup错误写法new UniformGroup({ uTexture: { value: texture, type: f32 }, });正确写法纹理作为顶级资源传入source与styleuniform 单独放一组const shader Shader.from({ gl: { vertex, fragment }, resources: { uTexture: texture.source, uSampler: texture.source.style, myUniforms: new UniformGroup({ uAlpha: { value: 1.0, type: f32 }, }), }, });纹理是资源而非 uniform顶层资源条目请传texture.sourceTextureSource与texture.source.styleTextureStyle。关联技能与 API 参考相关技能文档pixijs-filters内置滤镜、pixijs-scene-mesh自定义几何体、pixijs-performance合批优化、pixijs-migration-v8从 v7 迁移着色器 API。核心 APIShader、GlProgram、GpuProgram、UniformGroup、Filter、Batcher、BatcherPipe源码入口分别为 Shader.ts、GlProgram.ts、GpuProgram.ts、UniformGroup.ts、Filter.ts 与 Batcher.ts。【免费下载链接】pixijsThe HTML5 Creation Engine: Create beautiful digital content with the fastest, most flexible 2D WebGL renderer.项目地址: https://gitcode.com/gh_mirrors/pi/pixijs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →