PixiJS предоставляет мощный механизм для работы с фильтрами через WebGL и GLSL. Создание собственного фильтра позволяет управлять визуальными эффектами на уровне пикселей, расширяя стандартный набор возможностей библиотеки.
Фильтр в PixiJS представляет собой объект класса
PIXI.Filter, который включает два основных компонента:
Простейший фильтр можно создать с помощью:
const vertexSrc = `
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat3 projectionMatrix;
varying vec2 vTextureCoord;
void main(void) {
vTextureCoord = aTextureCoord;
gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
}
`;
const fragmentSrc = `
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vTextureCoord);
}
`;
const customFilter = new PIXI.Filter(vertexSrc, fragmentSrc);
sprite.filters = [customFilter];
Здесь vTextureCoord передаёт координаты
текстуры от вершинного к фрагментному шейдеру, а uSampler
обеспечивает доступ к текстуре спрайта.
Для динамического управления эффектом используются uniform-переменные. Они задаются при создании фильтра и могут изменяться в процессе работы приложения:
const fragmentSrc = `
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform float intensity;
void main(void) {
vec4 color = texture2D(uSampler, vTextureCoord);
color.rgb *= intensity;
gl_FragColor = color;
}
`;
const customFilter = new PIXI.Filter(null, fragmentSrc, { intensity: 1.0 });
customFilter.uniforms.intensity = 1.5;
sprite.filters = [customFilter];
Uniform-переменные позволяют анимировать фильтры или создавать интерактивные эффекты.
Фильтры могут работать не только с базовой текстурой спрайта, но и с дополнительными текстурами для создания сложных эффектов:
const fragmentSrc = `
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform sampler2D maskTexture;
void main(void) {
vec4 color = texture2D(uSampler, vTextureCoord);
vec4 mask = texture2D(maskTexture, vTextureCoord);
gl_FragColor = vec4(color.rgb * mask.a, color.a);
}
`;
const maskTexture = PIXI.Texture.from('mask.png');
const customFilter = new PIXI.Filter(null, fragmentSrc, { maskTexture });
sprite.filters = [customFilter];
Использование дополнительных текстур позволяет реализовать маскирование, динамическое наложение эффектов и генерацию сложной графики.
GLSL поддерживает широкий набор функций для работы с цветом, координатами и векторами:
Применение этих функций позволяет создавать эффекты размытия, свечения, искажения и динамические текстуры.
Создание эффекта волны или «текущей воды» реализуется с помощью смещения координат:
const fragmentSrc = `
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform float time;
void main(void) {
vec2 uv = vTextureCoord;
uv.y += 0.05 * sin(uv.x * 10.0 + time);
gl_FragColor = texture2D(uSampler, uv);
}
`;
const customFilter = new PIXI.Filter(null, fragmentSrc, { time: 0 });
app.ticker.add(delta => {
customFilter.uniforms.time += delta * 0.1;
});
sprite.filters = [customFilter];
Здесь координата uv.y изменяется синусоидально во
времени, создавая реалистичное движение.
Для эффективной работы с большим количеством объектов:
Фильтры могут реагировать на пользовательский ввод или время, что позволяет создавать интерактивные эффекты:
window.addEventListener('mousemove', e => {
customFilter.uniforms.offsetX = e.clientX / window.innerWidth;
});
app.ticker.add(delta => {
customFilter.uniforms.time += delta * 0.05;
});
Такое управление открывает возможности для динамичных эффектов на игровом поле, интерфейсах и визуализациях данных.
Можно создавать классы-наследники от PIXI.Filter,
инкапсулируя шейдер и параметры:
class WaveFilter extends PIXI.Filter {
constructor() {
const fragmentSrc = `
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform float time;
void main(void) {
vec2 uv = vTextureCoord;
uv.y += 0.05 * sin(uv.x * 10.0 + time);
gl_FragColor = texture2D(uSampler, uv);
}
`;
super(null, fragmentSrc, { time: 0 });
}
update(delta) {
this.uniforms.time += delta * 0.1;
}
}
const waveFilter = new WaveFilter();
sprite.filters = [waveFilter];
app.ticker.add(delta => waveFilter.update(delta));
Наследование упрощает повторное использование фильтров и делает код более читаемым.
Создание фильтров на GLSL в PixiJS предоставляет полный контроль над визуальными эффектами, позволяя создавать уникальные графические решения и динамичные анимации.