Отрисовка HTML на холсте WebGL позволяет использовать активные поддеревья DOM в качестве динамических текстур графического процессора, применять эффекты шейдеров к активной DOM и интегрировать интерактивный HTML в 3D-сцены.
В этом руководстве рассказывается, как отрисовать HTML на холсте WebGL. Подробнее об HTML-in-Canvas рассказывается в обзоре API.
Чтобы отобразить HTML на холсте WebGL, выполните следующие действия:
- Подготовьте холст. Задайте нужные атрибуты, чтобы браузер знал, что HTML-код нужно отрисовать в элементе canvas. Эта настройка одинакова для контекстов 2D, WebGL и WebGPU. Узнайте, как настроить холст и как объявить элементы HTML, которые будут отрисовываться независимо.
- Примените HTML-код в качестве текстуры:
- Предварительно выделяйте хранилище текстур графического процессора.
- Загрузите снимок DOM в качестве текстуры.
- Синхронизируйте DOM и пиксели.
Как нарисовать элемент HTML в качестве текстуры WebGL
В WebGL элементы HTML загружаются в графический процессор как 2D-текстуры с помощью texElementSubImage2D().
Предварительно выделяйте хранилище для текстур
В отличие от 2D-холста, который управляет резервной памятью автоматически, контекст WebGL требует явного управления памятью.
Перед загрузкой пикселей DOM необходимо предварительно выделить память графического процессора. Это позволяет браузеру быстро обновлять фрагменты изображений, не запуская ресурсоемкое перераспределение памяти графического процессора.
Предварительно выделите буфер с выбранными параметрами размера и srcData, заданным как null, следующим образом:
// Only allocate texture backing once
if (!textureBufferAllocated) {
// Pre-allocate texture backing with pre-determined size.
gl.texImage2D(
/* target */ gl.TEXTURE_2D,
/* level */ 0,
/* internalformat */ gl.RGBA8,
/* width */ myElementWidth,
/* height */ myElementHeight,
/* border */ 0,
/* format */ gl.RGBA,
/* type */ gl.UNSIGNED_BYTE,
/* srcData */ null
);
textureBufferAllocated = true;
}
Чтобы текстура соответствовала естественному размеру макета элемента HTML, используйте canvas.getElementImageDefaultSize() для получения его размера по умолчанию в пикселях сетки холста:
const { width, height } = canvas.getElementImageDefaultSize(myElement);
// Pre-allocate texture backing. Only do this once, or whenever the element
// changes size.
gl.texImage2D(
/* target */ gl.TEXTURE_2D,
/* level */ 0,
/* internalformat */ gl.RGBA8,
/* width */ Math.ceil(width),
/* height */ Math.ceil(height),
/* border */ 0,
/* format */ gl.RGBA,
/* type */ gl.UNSIGNED_BYTE,
/* srcData */ null
);
Загрузите снимок DOM в качестве текстуры.
Затем загрузите элемент HTML в текстуру в цикле рендеринга или прослушивателе paint.
canvas.onpaint = () => {
// 1. Pre-allocate texture backing first
// ...
// 2. Upload HTML snapshot into the WebGL texture
gl.texElementSubImage2D(
/* target */ gl.TEXTURE_2D,
/* level */ 0,
/* xoffset */ 0,
/* yoffset */ 0,
/* element */ myElement // or an ElementImage from `captureElementImage()`
);
// ...
};
Синхронизировать геометрию
В отличие от 2D-контекстов, браузер не может автоматически определить, где текстура появляется на экране в 3D-контексте. Вам нужно вручную выровнять проверку нажатия DOM и граничные рамки специальных возможностей с 3D-сеткой.
Для этого создайте объект DOMMatrix, который сопоставляет рамку элемента с расположением пикселей на холсте, а затем примените его с помощью updateElementGeometry():
canvas.addEventListener("paint", () => {
// 1. Upload fresh DOM snapshot to GPU texture
gl.bindTexture(gl.TEXTURE_2D, myTexture);
gl.texElementSubImage2D(gl.TEXTURE_2D, 0, 0, 0, myElement);
// 2. Draw your 3D scene
draw3DScene();
// 3. Construct the CSS-pixel transform mapping the element's
// border box to its drawn position on the canvas as needed
// (for example: scale and translate)
const canvasTransform = new DOMMatrix();
// scale X
canvasTransform.a = canvas.clientWidth / myElement.offsetWidth;
// scale Y
canvasTransform.d = canvas.clientHeight / myElement.offsetHeight;
// translate X (CSS px)
canvasTransform.e = 50;
// translate Y (CSS px)
canvasTransform.f = 100;
// 4. Update DOM position, accessibility focus rings, and pointer hit-testing
canvas.updateElementGeometry(myElement, {
canvasTransform: canvasTransform,
});
});
Дальнейшие действия
- Изучите основные технические концепции HTML-in-Canvas.
- Подробнее о том, как отрисовывать HTML в контексте 2D…
- Подробнее о том, как отрисовывать HTML на холсте WebGPU…
- Подробнее о резервных стратегиях…
- Чтобы поделиться отзывом, создайте проблему на GitHub.
- Посмотрите коллекцию демонстраций HTML-in-Canvas от сообщества.