Renderizar HTML dentro de un lienzo de WebGPU ofrece todos los beneficios que ofrece HTML en un lienzo de WebGL, como aplicar efectos de sombreador al DOM o integrar HTML interactivo en escenas 3D. Sin embargo, WebGPU ofrece beneficios significativos en comparación con WebGL.
En esta guía, se muestra cómo renderizar HTML en un lienzo de WebGPU. Obtén más información sobre HTML-in-Canvas en la descripción general de la API.
Para renderizar HTML en un lienzo de WebGPU, se deben seguir estos pasos:
- Prepara tu lienzo. Establecer de forma declarativa los atributos correctos para que el navegador sepa que debe renderizar HTML en un lienzo Esta configuración es idéntica en los contextos de 2D, WebGL y WebGPU. Obtén más información para configurar tu lienzo y declarar elementos HTML que se dibujarán de forma independiente.
- Aplica el HTML como una textura:
- Asigna previamente el almacenamiento de texturas de la GPU.
- Sube la instantánea del DOM como una textura.
- Sincroniza el DOM y los píxeles.
Dibuja un elemento HTML como una textura de WebGPU
En WebGPU, los elementos HTML se suben a la GPU como texturas 2D con drawElementImageToTexture().
Asigna previamente el almacenamiento de texturas
WebGPU requiere una asignación de memoria explícita. Antes de copiar píxeles del DOM en una textura, debes reservar la VRAM de la GPU con el método device.createTexture():
const context = canvas.getContext("webgpu");
// Pre-allocate the texture size as needed
// For example: HTML element CSS size × devicePixelRatio
const size = canvas.getElementImageDefaultSize(myElement);
const myElementWidth = Math.ceil(size.width);
const myElementHeight = Math.ceil(size.height);
// Pre-allocate the GPUTexture backing (run once during setup)
const myTexture = device.createTexture({
size: {
width: myElementWidth,
height: myElementHeight,
depthOrArrayLayers: 1, // optional (defaults to 1)
},
format: "rgba8unorm",
usage:
GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.COPY_DST |
GPUTextureUsage.RENDER_ATTACHMENT,
});
Cómo dibujar una imagen de un elemento HTML
En WebGPU, el método drawElementImageToTexture() dibuja la instantánea del elemento HTML. El método toma dos objetos de diccionario: source y destination.
source define el elemento del DOM de origen que se rasterizará y las coordenadas de recorte de subrectángulo opcionales que te permiten copiar solo una parte del elemento en tu textura, en lugar de todo el nodo del DOM:
| Propiedad | Tipo | Descripción |
|---|---|---|
source es obligatorio |
Element o ElementImage |
Es el elemento del DOM de destino (o la instancia de ElementImage capturada previamente) que se dibujará en la textura. |
sourceX opcional (los cuatro o ninguno) |
float | Es el desplazamiento horizontal de la coordenada X (en píxeles de CSS) que define la esquina superior izquierda de la porción del subrectángulo de origen. |
sourceY opcional (los cuatro o ninguno) |
float | Es el desplazamiento vertical de la coordenada Y (en píxeles de CSS) que define la esquina superior izquierda de la porción del subrectángulo de origen. |
sourceWidth opcional (los cuatro o ninguno) |
float | Es el ancho (en píxeles de CSS) del subrectángulo de origen que se recortará y rasterizará. |
sourceHeight opcional (los cuatro o ninguno) |
float | Es la altura (en píxeles de CSS) del subrectángulo de origen que se recortará y rasterizará. |
destination define la textura de GPU de destino que recibe la instantánea del DOM renderizada, junto con los desplazamientos de destino opcionales, los niveles de mip y las dimensiones de copia para colocar los píxeles en una región específica de la textura:
| Propiedad | Tipo | Descripción |
|---|---|---|
texture es obligatorio |
GPUTexture |
Es la textura de WebGPU de destino asignada previamente que recibirá la instantánea de píxeles del DOM renderizada. |
size opcionales |
GPUExtent3D |
Es el ancho y la altura (en píxeles de textura física, por ejemplo, { width, height }) para escalar y rasterizar el elemento dentro de la textura de destino. |
origin opcionales |
GPUOrigin3D |
Es el desplazamiento de destino en 3D (x, y, z) dentro de la textura en la que se escribirán los píxeles rasterizados. La configuración predeterminada es [0, 0, 0]. |
mipLevel opcionales |
GPUIntegerCoordinate |
Es el nivel de mipmap específico de la textura de destino en la que se escribirá. La configuración predeterminada es 0. |
aspect opcionales |
GPUTextureAspect |
Especifica en qué aspecto de la textura se copiará ("all", "stencil-only" o "depth-only"). El valor predeterminado es "all". |
colorSpace opcionales |
PredefinedColorSpace |
Es el espacio de color de destino (por ejemplo, "srgb" o "display-p3") para la conversión de color durante la carga. La configuración predeterminada es "srgb". |
premultipliedAlpha opcionales |
booleano | Indica si el alfa se debe premultiplicar en los canales de color durante la carga. La configuración predeterminada es false. |
Sube el elemento a tu textura dentro del evento paint llamando al método drawElementImageToTexture():
canvas.addEventListener("paint", (event) => {
const sourceDict = {
source: myElement,
// Optional sub-rectangle crop in CSS pixels
// (defaults to full element if omitted):
sourceX: 0,
sourceY: 0,
sourceWidth: myElement.offsetWidth,
sourceHeight: myElement.offsetHeight,
};
const destDict = {
texture: myTexture,
size: { width: myElementWidth, height: myElementHeight },
};
// Upload the latest DOM snapshot into the pre-allocated GPUTexture
device.queue.drawElementImageToTexture(sourceDict, destDict);
});
Sincroniza la geometría
Para alinear las pruebas de posicionamiento del DOM y los anillos de enfoque de accesibilidad con el resultado del lienzo renderizado, construye una transformación DOMMatrix y aplícala con el método updateElementGeometry():
// Construct a transform as needed in CSS pixels
// relative to the canvas, for example:
// 1/8 of the canvas width from the left edge, vertically centered.
// scaleX, scaleY: canvas grid pixels per CSS pixel (from resize observer)
const canvasCssWidth = canvas.width / scaleX;
const canvasCssHeight = canvas.height / scaleY;
const elementCssHeight = canvas.getElementImageDefaultSize(myElement).height / scaleY;
const x = canvasCssWidth / 8;
const y = (canvasCssHeight - elementCssHeight) / 2;
const transform = new DOMMatrix().translate(x, y);
// Synchronize the element's DOM hit-testing and accessibility geometry
canvas.updateElementGeometry(myElement, { canvasTransform: transform });
Próximos pasos
- Comprende los conceptos técnicos básicos de HTML-in-Canvas.
- Obtén información para renderizar HTML en un contexto 2D.
- Obtén información para renderizar HTML en un lienzo de WebGL.
- Obtén más información sobre las estrategias de resguardo.
- Informa un problema en GitHub para compartir tus comentarios.
- Consulta la colección de demostraciones de HTML-in-Canvas de la comunidad.