pixijs-custom-rendering
pixijs/pixijs
Используйте этот навык при написании пользовательских шейдеров, униформ, фильтров или батчеров в PixiJS v8. Рассматриваются: Shader.from({gl, gpu, resources}), GlProgram/GpuProgram, UniformGroup с типизированными униформами (f32, vec2, mat4x4), режим UBO, текстуры в качестве ресурсов, пользовательские фильтры через Filter.from, конвенции GLSL ES 3.0 (in/out, finalColor, texture()), выборку uBackTexture, pixi.js/unsafe-eval для строгого CSP, пользовательские батчеры через расширения. Срабатывает при: Shader, GlProgram, GpuProgram, UniformGroup, Batcher, Filter, Filter.from, GLSL, WGSL, UBO, uniform, пользовательский шейдер, finalColor, uBackTexture, blendRequired, unsafe-eval.
...Расширить всеПользовательские шейдеры привязывают программы GLSL и WGSL к объектам сцены с помощью метода Shader.from({ gl, gpu, resources }). Переменные uniform хранятся в типизированных группах UniformGroup, текстуры передаются в виде отдельных ресурсов, а один и тот же шейдер может быть предназначен как для WebGL, так и для WebGPU.
Быстрый старт
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;
});
Связанные навыки: pixijs-filters (встроенные фильтры), pixijs-scene-mesh (пользовательская геометрия), pixijs-performance (оптимизация пакетной обработки), pixijs-migration-v8 (миграция API шейдеров из версии v7).
Основные шаблоны
Шейдер с двумя рендерерами (WebGL + WebGPU)
import { Shader, GlProgram, GpuProgram, UniformGroup } from "pixi.js";const glVertex = `...`; // вершина GLSL (укажите `#version 300 es` самостоятельно, если требуется WebGL2/GLSL ES 3.0)
const glFragment = `...`; // фрагмент GLSL
const wgslSource = `...`; //объединенный WGSL
const shader = Shader.from({
gl: { vertex: glVertex, fragment: glFragment },
gpu: {
// имена точек входа могут быть любыми; они должны совпадать с именами функций @vertex / @fragment
// в вашем исходном коде WGSL. 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" },
uMatrix: { value: new Float32Array(16), type: "mat4x4" },
}),
},
});
Если указан только gl, шейдер работает только с WebGL. Если указан только gpu, он работает только с WebGPU. Битовая маска compatibleRenderers устанавливается автоматически.
GlProgram не вставляет автоматически #version 300 es. Если вы сами укажете #version 300 es, PixiJS сохранит его и будет рассматривать шейдер как GLSL ES 3.0; в противном случае он вставит макросы, обеспечивающие совместимость с WebGL1 (#define в varying, #define texture texture2D), и запустит шейдер как GLSL в стиле WebGL1. GlProgram всегда вставляет точность по умолчанию (highp для вершин, mediump для фрагментов) и имя программы. Для GLSL ES 3.0 используйтеin/out вместоattribute/varying, texture() вместо texture2D() и out vec4 вместо gl_FragColor.
Текстуры как ресурсы
Текстуры — это ресурсы, а не униформы. Передавайте источник и стиль текстуры отдельно:
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;
Ресурсы представляют собой плоскую карту «ключ-значение». Ключ должен совпадать с именем униформы или привязки в исходном коде шейдера.
Ресурсы также могут быть простыми объектами (автоматически преобразуемыми в UniformGroup):
const shader = Shader.from({
gl: { vertex: vertSrc, fragment: fragSrc },
resources: {
myUniforms: {
uTime: { value: 0, type: "f32" },
},
},
});
Режим UBO (Uniform Buffer Objects)
Режим UBO объединяет униформы в один буфер GPU. Требуется для WebGPU; опционально (WebGL2+) для WebGL.
import { UniformGroup } from "pixi.js";const ubo = new UniformGroup(
{
uProjection: { value: new Float32Array(16), type: "mat4x4" },
uAlpha: { value: 1.0, type: "f32" },
},
{ ubo: true, isStatic: true },
);// Если isStatic равно true, необходимо вручную вызвать update()
ubo.uniforms.uAlpha = 0.5;
ubo.update();
Правила UBO:
- Поддерживаются только типы на основе
f32иi32(u32не поддерживается). Матрицы могут быть только типа float. - Сэмплеры и текстуры не могут помещаться в UBO.
- Имя UniformGroup в ресурсах должно точно совпадать с именем блока UBO в шейдере.
- Структура и порядок должны точно соответствовать расположению в шейдере.
- Синхронизация UBO использует
новую функцию «Function»под капотом. В средах со строгим CSP (безunsafe-eval) импортируйтеpixi.js/unsafe-evalодин раз при запуске, чтобы включить резервный путь синхронизации; без этого шейдеры, использующие UBO (и, следовательно, WebGPU), вызовут исключение при первом использовании.
Пользовательский фильтр
Filter.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 (GLSL ES 3.0)
in vec2 vTextureCoord;вместоvarying vec2 vTextureCoord;out vec4 finalColor;вместоgl_FragColortexture(uTexture, uv)вместоtexture2D(uTexture, uv)- Вершинный шейдер по умолчанию предоставляет доступ к
uInputSize,uOutputFrame,uOutputTextureи вспомогательным функциямfilterVertexPosition()/filterTextureCoord()
Отбор проб из целевой области рендеринга за фильтром
Установите blendRequired: true и выполните выборку uBackTexture в шейдере фрагментов. PixiJS копирует пиксели назначения в эту униформу перед запуском фильтра:
const blendFilter = Filter.from({
gl: { fragment: blendFragSrc },
resources: { uniforms: { uAmount: { value: 0.5, type: "f32" } } },
blendRequired: true,
});
Включайте blendRequired только при необходимости; это вызывает дополнительную копию на GPU в каждом кадре.
Обновление униформ во время выполнения
// Доступ к UniformGroup через resources
shader.resources.myUniforms.uniforms.uTime = performance.now() / 1000;// Для UBO типа isStatic вызывайте update() после изменения значений
shader.resources.myUniforms.update();
Справочник типов униформ
См. файл references/uniform-types.md, где приведена полная таблица поддерживаемых типов, их эквивалентов в WGSL/GLSL и форматов значений.
Пользовательский батчер (на основе расширений)
Абстрактный класс 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; // количество чисел с плавающей запятой на вершину
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);
Элементы ссылаются на батчер по параметру batcherName. Интерфейс BatchableElement требует следующие параметры: batcherName, texture, blendMode, indexSize, attributeSize, topology и packAsQuad.
Распространённые ошибки
[КРИТИЧЕСКИЙ] Устаревший конструктор Shader.from(vertex, fragment, uniforms)
Неправильно:
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 и ресурсами. Позиционный API был удален.
[КРИТИЧЕСКОЕ] UniformGroup без аннотации типа
Неправильно:
new UniformGroup({ uTime: 1 });
Правильно:
new UniformGroup({ uTime: { value: 1, type: "f32" } });
Каждый униформ требует явного указания пары { value, type }. Опущение типа приводит к ошибке выполнения: «Неопределённый тип униформа не поддерживается».
[HIGH] UBO с неподдерживаемыми типами или неправильной структурой
Режим UBO поддерживает типы на основе f32 и i32 (скалярные и векторные). Тип u32 отсутствует в списке поддерживаемых типов UniformGroup и вызовет исключение. Матрицы допускают только тип float (mat*). Сэмплеры нельзя размещать в UBO.
Имя структуры и порядок полей должны точно соответствовать объявлению UBO в шейдере. Несоответствия приводят к искажению рендеринга без вывода ошибки.
[HIGH] Размещение текстур в UniformGroup
Неправильно:
new UniformGroup({
uTexture: { value: texture, type: "f32" },
});
Правильно:
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uTexture: texture.source,
uSampler: texture.source.style,
myUniforms: new UniformGroup({
uAlpha: { value: 1.0, type: "f32" },
}),
},
});
Текстуры являются ресурсами, а не униформами. Передавайте texture.source (TextureSource) и texture.source.style (TextureStyle) в качестве элементов ресурсов верхнего уровня.
Справочник по API
Custom shaders bind GLSL and WGSL programs to scene objects via Shader.from({ gl, gpu, resources }). Uniforms live in typed UniformGroups, textures are passed as separate resources, and the same shader can target both WebGL and WebGPU.
Quick Start
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: pixijs-filters (built-in filters), pixijs-scene-mesh (custom geometry), pixijs-performance (batch optimization), pixijs-migration-v8 (shader API migration from v7).
Core Patterns
Dual-renderer shader (WebGL + WebGPU)
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 combinedconst 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 gl is provided, the shader works with WebGL only. If only gpu is provided, it works with WebGPU only. The compatibleRenderers bitmask is set automatically.
GlProgram does not auto-inject #version 300 es. If you write #version 300 es yourself, PixiJS preserves it and treats the shader as GLSL ES 3.0; otherwise it injects WebGL1 compat macros (#define in varying, #define texture texture2D) and runs the shader as WebGL1-style GLSL. GlProgram always injects a default precision (highp vertex, mediump fragment) and the program name. For GLSL ES 3.0, use in/out instead of attribute/varying, texture() instead of texture2D(), and an out vec4 instead of gl_FragColor.
Textures as resources
Textures are resources, not uniforms. Pass the texture's source and style separately:
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 UniformGroup):
const shader = Shader.from({
gl: { vertex: vertSrc, fragment: fragSrc },
resources: {
myUniforms: {
uTime: { value: 0, type: "f32" },
},
},
});
UBO mode (Uniform Buffer Objects)
UBO mode packs uniforms into a single GPU buffer. Required for WebGPU; optional (WebGL2+) for WebGL.
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
f32andi32based types are supported (nou32). Matrices are float-only. - 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
new Functionunder the hood. In strict-CSP environments (nounsafe-eval), importpixi.js/unsafe-evalonce at startup to swap in the fallback sync path; without it, UBO-backed shaders (and therefore WebGPU) will throw on first use.
Custom filter
Filter.from({ gl, resources }) is the shorthand. Pass only a fragment shader; PixiJS supplies a default vertex shader that handles output frame positioning.
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 shader conventions (GLSL ES 3.0)
in vec2 vTextureCoord;instead ofvarying vec2 vTextureCoord;out vec4 finalColor;instead ofgl_FragColortexture(uTexture, uv)instead oftexture2D(uTexture, uv)- The default vertex shader exposes
uInputSize,uOutputFrame,uOutputTextureand helpersfilterVertexPosition()/filterTextureCoord()
Sampling the render target behind the filter
Set blendRequired: true and sample uBackTexture in the fragment shader. PixiJS copies the destination pixels into that uniform before running the filter:
const blendFilter = Filter.from({
gl: { fragment: blendFragSrc },
resources: { uniforms: { uAmount: { value: 0.5, type: "f32" } } },
blendRequired: true,
});
Only enable blendRequired when you need it; it forces an extra GPU copy every frame.
Updating uniforms at runtime
// 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();
Uniform type reference
See references/uniform-types.md for the complete table of supported types, their WGSL/GLSL equivalents, and value formats.
Custom Batcher (extension-based)
The Batcher abstract class enables custom batching for specialized rendering. Subclass it and register via extensions:
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 batcherName. The BatchableElement interface requires: batcherName, texture, blendMode, indexSize, attributeSize, topology, and packAsQuad.
Common Mistakes
[CRITICAL] Old Shader.from(vertex, fragment, uniforms) constructor
Wrong:
const shader = Shader.from(vertex, fragment, { uTime: 1 });
Correct:
const shader = Shader.from({
gl: { vertex, fragment },
resources: {
uniforms: new UniformGroup({
uTime: { value: 1, type: "f32" },
}),
},
});
v8 requires an options object with gl/gpu programs and resources. The positional API was removed.
[CRITICAL] UniformGroup without type annotation
Wrong:
new UniformGroup({ uTime: 1 });
Correct:
new UniformGroup({ uTime: { value: 1, type: "f32" } });
Every uniform requires an explicit { value, type } pair. Omitting the type causes a runtime error: "Uniform type undefined is not supported."
[HIGH] UBO with unsupported types or wrong structure
UBO mode supports f32 and i32 based types (scalars and vectors). u32 is not in the supported UniformGroup type list and will throw. Matrices are float-only (mat*<f32>). Samplers cannot be placed in UBOs.
The struct name and field order must exactly match the shader's UBO declaration. Mismatches produce garbled rendering with no error.
[HIGH] Putting textures in UniformGroup
Wrong:
new UniformGroup({
uTexture: { value: texture, type: "f32" },
});
Correct:
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 texture.source (TextureSource) and texture.source.style (TextureStyle) as top-level resource entries.
API Reference
Установить pixijs-custom-rendering
Скачайте файлы навыков и распакуйте их в каталог .claude/skills/.
Скачать ZIPКлонируйте репозиторий и скопируйте файлы навыка в свой проект.
git clone https://github.com/pixijs/pixijs/tree/dev/skills/pixijs-custom-rendering # Copy the skill folder to .claude/skills/ or .codex/skills/
Копировать





Дом
