В стандартной архитектуре Lottie Web рендеринг основан на SVG или Canvas2D, что обеспечивает совместимость и предсказуемое поведение, но ограничивает доступ к аппаратному ускорению графического процессора. WebGL используется не как встроенный рендерер Lottie, а как внешний графический слой, в который анимация интегрируется через текстуры, буферы и промежуточные канвасы.
Ключевая идея применения WebGL в связке с Lottie заключается в том, что Lottie-анимация превращается в последовательность растровых кадров, которые затем используются как текстура внутри WebGL-сцены. Такой подход позволяет сочетать векторную анимационную модель After Effects с GPU-ускоренными эффектами: освещением, постобработкой, шейдерами и сложной композицией.
Lottie Web генерирует кадры анимации на основе JSON-описания,
синхронизируя их через requestAnimationFrame. В момент
рендеринга используется DOM-элемент <canvas>, в
который записывается итоговое изображение сцены.
Дальнейший этап — извлечение пиксельного буфера:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const anim = lottie.loadAnimation({
container: canvas,
renderer: 'canvas',
loop: true,
autoplay: true,
path: 'animation.json'
});
На каждом кадре содержимое canvas используется как источник текстуры для WebGL:
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,
gl.UNSIGNED_BYTE, canvas);
Обновление текстуры выполняется в каждом кадре, синхронно с Lottie-анимацией.
WebGL не способен напрямую интерпретировать SVG или JSON-модель Lottie. Поэтому вводится промежуточный буферный слой:
Этот слой позволяет изолировать две системы: векторную (Lottie) и растрово-графическую (WebGL).
Критический аспект — производительность обновления текстуры. Простейшая схема выглядит так:
function update() {
anim.goToAndStop(performance.now() / 16.67, true);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texSubImage2D(
gl.TEXTURE_2D,
0,
0, 0,
gl.RGBA,
gl.UNSIGNED_BYTE,
canvas
);
renderScene();
requestAnimationFrame(update);
}
update();
При таком подходе важны ограничения:
texSubImage2D создают нагрузку на
GPUЧасто WebGL-уровень реализуется через сценический движок, например Three.js. В этом случае Lottie-канвас становится материалом плоскости:
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.MeshBasicMaterial({
map: texture,
transparent: true
});
const geometry = new THREE.PlaneGeometry(2, 2);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
Обновление текстуры синхронизируется с Lottie:
function animate() {
texture.needsUpdate = true;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Такой подход упрощает интеграцию с 3D-эффектами: параллакс, глубина, световые источники.
WebGL раскрывает возможности, недоступные в Lottie-рендерере:
Фрагментный шейдер может модифицировать Lottie-текстуру:
precision mediump float;
uniform sampler2D u_texture;
varying vec2 v_uv;
void main() {
vec4 color = texture2D(u_texture, v_uv);
color.rgb += vec3(0.1); // простое усиление яркости
gl_FragColor = color;
}
Таким образом Lottie становится входным слоем для GPU-пайплайна.
Lottie управляет анимацией через внутренний таймкод, WebGL — через кадры рендера. Несинхронность приводит к дрожанию или рассинхронизации эффектов.
Используется единый источник времени:
const start = performance.now();
function getFrame() {
const elapsed = performance.now() - start;
return elapsed / 16.67;
}
Этот кадр передается одновременно:
goToAndStop() LottieПолное обновление текстуры на каждом кадре дорого стоит. Используются стратегии:
1. Кэширование кадров
2. Понижение разрешения буфера
3. Dirty regions
При высоконагруженных сценах Lottie-рендеринг переносится в отдельный поток:
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker('lottie-worker.js');
worker.postMessage({
canvas: offscreen,
path: 'animation.json'
}, [offscreen]);
В worker происходит независимый рендер, а основной поток занимается WebGL-композицией.
WebGL позволяет накладывать несколько анимаций как текстуры:
Каждый слой — отдельный canvas-texture, объединённый в шейдере или через blend modes.
Lottie активно использует прозрачность, которая напрямую переносится в WebGL:
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
Это позволяет сохранять векторную природу композиции даже в GPU-слое.
Canvas-first pipeline
Hybrid composition
Full GPU pipeline
Использование WebGL поверх Lottie вводит ряд ограничений:
Эти ограничения компенсируются гибкостью постобработки и возможностью сложной композиции.
При изменении размера контейнера необходимо пересоздавать:
Несоответствие DPR (device pixel ratio) приводит к размытию текстур, поэтому синхронизация обязательна:
canvas.width = width * devicePixelRatio;
canvas.height = height * devicePixelRatio;
gl.viewport(0, 0, canvas.width, canvas.height);
Фильтры Lottie (blur, opacity, transforms) выполняются на CPU. WebGL может дублировать их на GPU, создавая эффект двойного уровня:
Такой подход используется для сложных сцен с большим количеством слоёв, где CPU-фильтры становятся узким местом.