pixijs-custom-rendering
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCustom shaders bind GLSL and WGSL programs to scene objects via . Uniforms live in typed s, textures are passed as separate resources, and the same shader can target both WebGL and WebGPU.
Shader.from({ gl, gpu, resources })UniformGroup自定义着色器通过将GLSL和WGSL程序绑定到场景对象。Uniforms存储在带类型的中,纹理作为独立资源传递,同一个着色器可同时适配WebGL和WebGPU。
Shader.from({ gl, gpu, resources })UniformGroupQuick Start
快速开始
ts
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;
});Related skills: (built-in filters), (custom geometry), (batch optimization), (shader API migration from v7).
pixijs-filterspixijs-scene-meshpixijs-performancepixijs-migration-v8ts
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;
});相关技能: (内置滤镜)、(自定义几何体)、(批处理优化)、(从v7迁移着色器API)。
pixijs-filterspixijs-scene-meshpixijs-performancepixijs-migration-v8Core Patterns
核心模式
Dual-renderer shader (WebGL + WebGPU)
双渲染器着色器(WebGL + WebGPU)
ts
import { Shader, GlProgram, GpuProgram, UniformGroup } from "pixi.js";
const glVertex = `...`; // GLSL vertex (write `#version 300 es` yourself if you want WebGL2/GLSL ES 3.0)
const glFragment = `...`; // GLSL fragment
const wgslSource = `...`; // WGSL combined
const shader = Shader.from({
gl: { vertex: glVertex, fragment: glFragment },
gpu: {
// entryPoint names are arbitrary; they must match the @vertex / @fragment
// function names in your WGSL source. PixiJS ships examples using
// 'mainVert' / 'mainFrag' but `main` is equally valid.
vertex: { entryPoint: "mainVert", source: wgslSource },
fragment: { entryPoint: "mainFrag", source: wgslSource },
},
resources: {
myUniforms: new UniformGroup({
uColor: { value: new Float32Array([1, 0, 0, 1]), type: "vec4<f32>" },
uMatrix: { value: new Float32Array(16), type: "mat4x4<f32>" },
}),
},
});If only is provided, the shader works with WebGL only. If only is provided, it works with WebGPU only. The bitmask is set automatically.
glgpucompatibleRenderersGlProgram#version 300 es#version 300 es#define in varying#define texture texture2DGlProgramhighpmediumpinoutattributevaryingtexture()texture2D()out vec4gl_FragColorts
import { Shader, GlProgram, GpuProgram, UniformGroup } from "pixi.js";
const glVertex = `...`; // GLSL顶点着色器(如果需要WebGL2/GLSL ES 3.0,请自行编写`#version 300 es`)
const glFragment = `...`; // GLSL片段着色器
const wgslSource = `...`; // WGSL组合代码
const shader = Shader.from({
gl: { vertex: glVertex, fragment: glFragment },
gpu: {
// 入口点名称可自定义;必须与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: "vec4<f32>" },
uMatrix: { value: new Float32Array(16), type: "mat4x4<f32>" },
}),
},
});如果仅提供,则着色器仅适用于WebGL;如果仅提供,则仅适用于WebGPU。位掩码会自动设置。
glgpucompatibleRenderersGlProgram#version 300 es#version 300 es#define in varying#define texture texture2DGlProgramhighpmediumpinoutattributevaryingtexture()texture2D()out vec4gl_FragColorTextures as resources
作为资源的纹理
Textures are resources, not uniforms. Pass the texture's and separately:
sourcestylets
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" },
}),
},
});
// Swap texture at runtime
shader.resources.uTexture = otherTexture.source;Resources are a flat key-value map. The key must match the uniform/binding name in the shader source.
Resources can also be plain objects (auto-wrapped into ):
UniformGroupts
const shader = Shader.from({
gl: { vertex: vertSrc, fragment: fragSrc },
resources: {
myUniforms: {
uTime: { value: 0, type: "f32" },
},
},
});纹理是资源,而非uniforms。需单独传递纹理的和:
sourcestylets
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名称匹配。
资源也可以是普通对象(会自动包装为):
UniformGroupts
const shader = Shader.from({
gl: { vertex: vertSrc, fragment: fragSrc },
resources: {
myUniforms: {
uTime: { value: 0, type: "f32" },
},
},
});UBO mode (Uniform Buffer Objects)
UBO模式(Uniform Buffer Objects)
UBO mode packs uniforms into a single GPU buffer. Required for WebGPU; optional (WebGL2+) for WebGL.
ts
import { UniformGroup } from "pixi.js";
const ubo = new UniformGroup(
{
uProjection: { value: new Float32Array(16), type: "mat4x4<f32>" },
uAlpha: { value: 1.0, type: "f32" },
},
{ ubo: true, isStatic: true },
);
// Must call update() manually when isStatic is true
ubo.uniforms.uAlpha = 0.5;
ubo.update();UBO rules:
- Only and
f32based types are supported (noi32). Matrices are float-only.u32 - Samplers/textures cannot go in a UBO.
- The UniformGroup name in resources must exactly match the UBO block name in the shader.
- Structure and order must exactly match the shader layout.
- UBO sync uses under the hood. In strict-CSP environments (no
new Function), importunsafe-evalonce at startup to swap in the fallback sync path; without it, UBO-backed shaders (and therefore WebGPU) will throw on first use.pixi.js/unsafe-eval
UBO模式将uniforms打包到单个GPU缓冲区中。WebGPU必须使用该模式;WebGL为可选(需WebGL2+)。
ts
import { UniformGroup } from "pixi.js";
const ubo = new UniformGroup(
{
uProjection: { value: new Float32Array(16), type: "mat4x4<f32>" },
uAlpha: { value: 1.0, type: "f32" },
},
{ ubo: true, isStatic: true },
);
// 当isStatic为true时,必须手动调用update()
ubo.uniforms.uAlpha = 0.5;
ubo.update();UBO规则:
- 仅支持基于和
f32的类型(不支持i32)。矩阵仅支持浮点类型。u32 - 采样器/纹理不能放入UBO。
- 资源中的UniformGroup名称必须与着色器中的UBO块名称完全匹配。
- 结构和顺序必须与着色器布局完全匹配。
- UBO同步底层使用。在严格CSP环境(禁用
new Function)中,需在启动时导入unsafe-eval一次,以切换到回退同步路径;否则基于UBO的着色器(以及WebGPU)在首次使用时会抛出错误。pixi.js/unsafe-eval
Custom filter
自定义滤镜
Filter.from({ gl, resources })ts
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;For a custom vertex shader, use .
new Filter({ glProgram: new GlProgram({ vertex, fragment }), resources })Filter.from({ gl, resources })ts
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 shader conventions (GLSL ES 3.0)
滤镜着色器规范(GLSL ES 3.0)
- instead of
in vec2 vTextureCoord;varying vec2 vTextureCoord; - instead of
out vec4 finalColor;gl_FragColor - instead of
texture(uTexture, uv)texture2D(uTexture, uv) - The default vertex shader exposes ,
uInputSize,uOutputFrameand helpersuOutputTexture/filterVertexPosition()filterTextureCoord()
- 使用替代
in vec2 vTextureCoord;varying vec2 vTextureCoord; - 使用替代
out vec4 finalColor;gl_FragColor - 使用替代
texture(uTexture, uv)texture2D(uTexture, uv) - 默认顶点着色器暴露、
uInputSize、uOutputFrame以及辅助函数uOutputTexture/filterVertexPosition()filterTextureCoord()
Sampling the render target behind the filter
采样滤镜后方的渲染目标
Set and sample in the fragment shader. PixiJS copies the destination pixels into that uniform before running the filter:
blendRequired: trueuBackTexturets
const blendFilter = Filter.from({
gl: { fragment: blendFragSrc },
resources: { uniforms: { uAmount: { value: 0.5, type: "f32" } } },
blendRequired: true,
});Only enable when you need it; it forces an extra GPU copy every frame.
blendRequired设置,并在片段着色器中采样。PixiJS会在运行滤镜前将目标像素复制到该uniform中:
blendRequired: trueuBackTexturets
const blendFilter = Filter.from({
gl: { fragment: blendFragSrc },
resources: { uniforms: { uAmount: { value: 0.5, type: "f32" } } },
blendRequired: true,
});仅在需要时启用;它会强制每帧进行一次额外的GPU复制。
blendRequiredUpdating uniforms at runtime
运行时更新uniforms
ts
// Access the UniformGroup via resources
shader.resources.myUniforms.uniforms.uTime = performance.now() / 1000;
// For isStatic UBOs, call update() after changing values
shader.resources.myUniforms.update();ts
// 通过resources访问UniformGroup
shader.resources.myUniforms.uniforms.uTime = performance.now() / 1000;
// 对于isStatic的UBO,修改值后需调用update()
shader.resources.myUniforms.update();Uniform type reference
Uniform类型参考
See references/uniform-types.md for the complete table of supported types, their WGSL/GLSL equivalents, and value formats.
完整的支持类型表、对应的WGSL/GLSL等价类型以及值格式,请查看references/uniform-types.md。
Custom Batcher (extension-based)
自定义批处理器(基于扩展)
The abstract class enables custom batching for specialized rendering. Subclass it and register via extensions:
Batcherts
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; // floats per vertex
public geometry: Geometry;
public shader: Shader;
constructor(options: BatcherOptions) {
super(options);
// Initialize geometry and shader
}
public packAttributes(
element: BatchableMeshElement,
float32View: Float32Array,
uint32View: Uint32Array,
index: number,
textureId: number,
): void {
// Pack mesh vertex attributes into the batch buffer
}
public packQuadAttributes(
element: BatchableQuadElement,
float32View: Float32Array,
uint32View: Uint32Array,
index: number,
textureId: number,
): void {
// Pack quad vertex attributes into the batch buffer
}
}
extensions.add(MyBatcher);Elements reference the batcher by . The interface requires: , , , , , , and .
batcherNameBatchableElementbatcherNametextureblendModeindexSizeattributeSizetopologypackAsQuadBatcherts
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; // 每个顶点的浮点数量
public geometry: Geometry;
public shader: Shader;
constructor(options: BatcherOptions) {
super(options);
// 初始化几何体和着色器
}
public packAttributes(
element: BatchableMeshElement,
float32View: Float32Array,
uint32View: Uint32Array,
index: number,
textureId: number,
): void {
// 将网格顶点属性打包到批处理缓冲区
}
public packQuadAttributes(
element: BatchableQuadElement,
float32View: Float32Array,
uint32View: Uint32Array,
index: number,
textureId: number,
): void {
// 将四边形顶点属性打包到批处理缓冲区
}
}
extensions.add(MyBatcher);元素通过关联批处理器。接口要求:、、、、、和。
batcherNameBatchableElementbatcherNametextureblendModeindexSizeattributeSizetopologypackAsQuadCommon Mistakes
常见错误
[CRITICAL] Old Shader.from(vertex, fragment, uniforms) constructor
[严重] 旧版Shader.from(vertex, fragment, uniforms)构造函数
Wrong:
ts
const shader = Shader.from(vertex, fragment, { uTime: 1 });Correct:
ts
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uniforms: new UniformGroup({
uTime: { value: 1, type: "f32" },
}),
},
});v8 requires an options object with / programs and . The positional API was removed.
glgpuresources错误写法:
ts
const shader = Shader.from(vertex, fragment, { uTime: 1 });正确写法:
ts
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uniforms: new UniformGroup({
uTime: { value: 1, type: "f32" },
}),
},
});v8要求传入包含/程序和的选项对象,位置参数API已被移除。
glgpuresources[CRITICAL] UniformGroup without type annotation
[严重] 无类型注解的UniformGroup
Wrong:
ts
new UniformGroup({ uTime: 1 });Correct:
ts
new UniformGroup({ uTime: { value: 1, type: "f32" } });Every uniform requires an explicit pair. Omitting the type causes a runtime error: "Uniform type undefined is not supported."
{ value, type }错误写法:
ts
new UniformGroup({ uTime: 1 });正确写法:
ts
new UniformGroup({ uTime: { value: 1, type: "f32" } });每个uniform都需要显式的对。省略类型会导致运行时错误:"Uniform type undefined is not supported."
{ value, type }[HIGH] UBO with unsupported types or wrong structure
[高风险] 使用不支持类型或结构错误的UBO
UBO mode supports and based types (scalars and vectors). is not in the supported type list and will throw. Matrices are float-only (). Samplers cannot be placed in UBOs.
f32i32u32UniformGroupmat*<f32>The struct name and field order must exactly match the shader's UBO declaration. Mismatches produce garbled rendering with no error.
UBO模式支持基于和的类型(标量和向量)。不在支持类型列表中,会抛出错误。矩阵仅支持浮点类型()。采样器不能放入UBO。
f32i32u32UniformGroupmat*<f32>结构体名称和字段顺序必须与着色器中的UBO声明完全匹配。不匹配会导致渲染混乱且无错误提示。
[HIGH] Putting textures in UniformGroup
[高风险] 将纹理放入UniformGroup
Wrong:
ts
new UniformGroup({
uTexture: { value: texture, type: "f32" },
});Correct:
ts
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uTexture: texture.source,
uSampler: texture.source.style,
myUniforms: new UniformGroup({
uAlpha: { value: 1.0, type: "f32" },
}),
},
});Textures are resources, not uniforms. Pass (TextureSource) and (TextureStyle) as top-level resource entries.
texture.sourcetexture.source.style错误写法:
ts
new UniformGroup({
uTexture: { value: texture, type: "f32" },
});正确写法:
ts
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uTexture: texture.source,
uSampler: texture.source.style,
myUniforms: new UniformGroup({
uAlpha: { value: 1.0, type: "f32" },
}),
},
});纹理是资源,而非uniforms。需将(TextureSource)和(TextureStyle)作为顶级资源项传递。
texture.sourcetexture.source.style