前端开发
在 PixiJS v8 中编写自定义着色器、Uniform…
当需要在 PixiJS v8 中编写自定义 shader、uniform、filter、batcher 或底层绘制代码时,用这套做法同时兼容 WebGL 与 WebGPU。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 PixiJS v8 中编写自定义着色通用
解决思路
- 用 `Shader.from({ gl, gpu, resources })` 把 GLSL 与 WGSL 程序绑定到场景对象;uniform 放在带类型的 `UniformGroup` 中,纹理作为独立资源传入,同一个 shader 可同时面向 WebGL 和 WebGPU。
- 双渲染器写法:`Shader.from({ gl: { vertex, fragment }, gpu: { vertex: { entryPoint, source }, fragment: { entryPoint, source } }, resources })`;entryPoint 名称可任意,但必须与 WGSL 源码中 `@vertex` / `@fragment` 函数名一致。只提供 `gl` 则仅支持 WebGL,只提供 `gpu` 则仅支持 WebGPU,`compatibleRenderers` 位掩码会自动设置。
- `GlProgram` 不会自动注入 `#version 300 es`:自己写 `#version 300 es` 时 PixiJS 会保留并按 GLSL ES 3.0 处理;否则注入 WebGL1 兼容宏(`#define in varying`、`#define texture texture2D`)并按 WebGL1 风格 GLSL 运行。`GlProgram` 始终注入默认精度(顶点 `highp`、片元 `mediump`)和程序名。GLSL ES 3.0 中用 `in`/`out` 替代 `attribute`/`varying`,用 `texture()` 替代 `texture2D()`,用 `out vec4` 替代 `gl_FragColor`。
- 纹理作为资源而非 uniform:把 `texture.source`(TextureSource)和 `texture.source.style`(TextureStyle)作为顶层资源条目传入,键名必须与 shader 中的 uniform/binding 名一致;运行时可通过 `shader.resources.uTexture = otherTexture.source` 换纹理。资源也可以是普通对象,会被自动包装成 `UniformGroup`。
- UBO 模式:`new UniformGroup({...}, { ubo: true, isStatic: true })` 把 uniform 打包进单个 GPU 缓冲;WebGPU 必需,WebGL2+ 可选。仅支持 `f32` 与 `i32` 基础类型(不支持 `u32`),矩阵只能是 float;采样器/纹理不能放进 UBO;resources 中的 UniformGroup 名必须与 shader 中 UBO 块名完全一致,结构与顺序也必须与 shader 布局完全匹配。`isStatic: true` 时修改值后必须手动调用 `ubo.update()`。UBO 同步底层使用 `new Function`,严格 CSP(无 `unsafe-eval`)环境需在启动时导入一次 `pixi.js/unsafe-eval` 以切换到回退同步路径,否则 UBO 着色器(以及 WebGPU)首次使用即抛错。
- 自定义过滤器用 `Filter.from({ gl, resources })` 简写,只传片元着色器,PixiJS 提供处理输出帧定位的默认顶点着色器;需要自定义顶点着色器时用 `new Filter({ glProgram: new GlProgram({ vertex, fragment }), resources })`。过滤器 GLSL ES 3.0 约定:`in vec2 vTextureCoord;`、`out vec4 finalColor;`、`texture(uTexture, uv)`;默认顶点着色器暴露 `uInputSize`、`uOutputFrame`、`uOutputTexture` 及辅助函数 `filterVertexPosition()` / `filterTextureCoord()`。
- 需要采样过滤器背后的渲染目标时,设置 `blendRequired: true` 并在片元着色器中采样 `uBackTexture`,PixiJS 会在运行过滤器前把目标像素拷贝进该 uniform;仅在需要时启用,它每帧会强制一次额外 GPU 拷贝。
- 运行时更新 uniform:通过 `shader.resources.myUniforms.uniforms.uTime = ...` 修改;对 `isStatic` 的 UBO,修改后调用 `shader.resources.myUniforms.update()`。
- 高级 GPU 特性(见 references/advanced-gpu.md):用 `buffer.update(sizeInBytes, offsetInBytes)` 只上传变化的字节区间;用 `geometry.vertexCount`(替代已废弃的 `getSize()`)与 `geometry.indexCount` 绘制共享索引缓冲的前缀,配合 `state.clockwiseFrontFace` 与 `cullMode` 控制绕序与剔除;WGSL override constants 用 `Shader.from({ gpu, resources, overrides: { STEPS: 8 } })`,每组不同取值编译各自管线;自定义 bind group 布局先用 `generateGpuLayoutGroups(extractStructAndGroups(source))` 生成默认布局再修改,作为 `gpuLayout` 传入;WebGPU 深度采样用 `new TextureView(depth, { aspect: "depth-only" })` 作为资源绑定,同时目标的深度附件为 `depthReadOnly`;渲染捆绑用 `encoder.beginBundle()` / `endBundle()` 录制一次,在 `isBundleValid()` 成立时用 `executeBundle()` 重放;临时纹理用 `TexturePool.getOptimalTexture({ width, height, resolution, antialias })` 获取并用 `returnTexture()` 归还。
- 自定义 Batcher:继承抽象类 `Batcher`,通过扩展注册(`static extension = { type: [ExtensionType.Batcher], name: "my-batcher" }`,再 `extensions.add(MyBatcher)`),设置 `vertexSize`(每顶点浮点数)、`geometry`、`shader`,并实现 `packAttributes(element, float32View, uint32View, index, textureId)` 与 `packQuadAttributes(...)` 打包顶点属性;元素通过 `batcherName` 引用该 batcher,`BatchableElement` 接口要求 `batcherName`、`texture`、`blendMode`、`indexSize`、`attributeSize`、`topology`、`packAsQuad`。
- 自定义 `InstructionPipe` 若按 `InstructionSet` 缓存状态(如 `BatcherPipe` 缓存 batcher),应实现 `destroyInstructionSet(instructionSet)`,在所属渲染组销毁时释放缓存的 GPU 对象,避免泄漏。
- 避免旧式 `Shader.from(vertex, fragment, uniforms)` 位置参数构造:v8 要求带 `gl`/`gpu` 程序与 `resources` 的选项对象,位置参数 API 已移除。
- 每个 uniform 必须显式写 `{ value, type }` 对,例如 `new UniformGroup({ uTime: { value: 1, type: "f32" } })`;省略 type 会运行时抛错 “Uniform type undefined is not supported.”。
- 不要把纹理放进 `UniformGroup`;纹理是资源,应把 `texture.source` 与 `texture.source.style` 作为顶层资源条目传入。
- 重放渲染捆绑前先检查 `encoder.isBundleValid(bundle)`,无效则重新录制;捆绑固化了录制时所在 pass 的附件、绕序与设备,在不同渲染目标下重放会导致整帧 WebGPU 校验失败或静默内外翻转,设备丢失后重放会被直接拒绝。
- 不要读取 `geometry.getSize()`(自 8.20.0 起废弃并打印警告),改用 `geometry.vertexCount`,它带缓存且仅在缓冲或属性变化时重算。
适用边界 · 注意事项
- 不使用 PixiJS v8(例如仍停留在 v7 或更早版本)时,本经验的 Shader.from 选项对象、UniformGroup 类型标注、UBO 等 API 不适用。
- 不需要自定义着色器/过滤器/批处理器,仅使用内置过滤器或普通场景图时,无需引入这些底层做法。
- 运行环境为严格 CSP 且无法导入 `pixi.js/unsafe-eval` 时,应避免使用 UBO 模式与 WebGPU,否则首次使用即抛错。