Das Rendern von HTML in einem WebGPU-Canvas bietet alle Vorteile von HTML in einem WebGL-Canvas, z. B. das Anwenden von Shader-Effekten auf das DOM oder das Einbinden von interaktivem HTML in 3D-Szenen. WebGPU bietet jedoch erhebliche Vorteile gegenüber WebGL.
In diesem Leitfaden wird gezeigt, wie HTML in einem WebGPU-Canvas gerendert wird. Weitere Informationen zu HTML-in-Canvas in der API-Übersicht
Zum Rendern von HTML in einem WebGPU-Canvas sind die folgenden Schritte erforderlich:
- Arbeitsfläche vorbereiten Legen Sie die richtigen Attribute deklarativ fest, damit der Browser weiß, dass er HTML in einem Canvas rendern soll. Diese Einrichtung ist für 2D-, WebGL- und WebGPU-Kontexte identisch. Informationen zum Einrichten des Canvas und zum Deklarieren von HTML-Elementen, die unabhängig voneinander gezeichnet werden sollen
- Wenden Sie den HTML-Code als Textur an:
- GPU-Texturspeicher vorab zuweisen.
- Laden Sie den DOM-Snapshot als Textur hoch.
- Synchronisieren Sie das DOM und die Pixel.
HTML-Element als WebGPU-Textur zeichnen
In WebGPU werden HTML-Elemente mit drawElementImageToTexture() als 2D-Texturen auf die GPU hochgeladen.
Texturspeicher vorab zuweisen
WebGPU erfordert eine explizite Arbeitsspeicherzuweisung. Bevor Sie DOM-Pixel in eine Textur kopieren, müssen Sie mit der Methode device.createTexture() GPU-VRAM reservieren:
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,
});
HTML-Elementbild zeichnen
In WebGPU wird mit der Methode drawElementImageToTexture() der Snapshot des HTML-Elements gezeichnet. Die Methode verwendet zwei Wörterbuchobjekte: source und destination.
source definiert das zu rasternde DOM-Quellelement und optionale Koordinaten für das Zuschneiden eines Teilrechtecks, mit denen Sie nur einen Teil des Elements in Ihre Textur kopieren können, anstatt den gesamten DOM-Knoten:
| Attribut | Typ | Beschreibung |
|---|---|---|
source erforderlich |
Element oder ElementImage |
Das Ziel-DOM-Element (oder die zuvor erfasste ElementImage-Instanz), das in die Textur gezeichnet werden soll. |
sourceX optional (alle vier oder keine) |
float | Der horizontale X-Koordinaten-Offset (in CSS-Pixeln), der die linke obere Ecke des Quell-Unterrechteck-Schnitts definiert. |
sourceY optional (alle vier oder keine) |
float | Der vertikale Y-Koordinaten-Offset (in CSS-Pixeln), der die linke obere Ecke des Quell-Unter-Rechteck-Schnitts definiert. |
sourceWidth optional (alle vier oder keine) |
float | Die Breite (in CSS-Pixeln) des Quell-Teilrechtecks, das zugeschnitten und gerastert werden soll. |
sourceHeight optional (alle vier oder keine) |
float | Die Höhe (in CSS-Pixeln) des Quell-Teilrechtecks, das zugeschnitten und gerastert werden soll. |
destination definiert die Ziel-GPU-Textur, die den gerenderten DOM-Snapshot empfängt, sowie optionale Ziel-Offsets, Mip-Level und Kopierdimensionen, um die Pixel in einem bestimmten Bereich der Textur zu platzieren:
| Attribut | Typ | Beschreibung |
|---|---|---|
texture erforderlich |
GPUTexture |
Die vorab zugewiesene WebGPU-Zieltextur, die den gerenderten DOM-Pixel-Snapshot empfängt. |
size optional |
GPUExtent3D |
Die Breite und Höhe (in physischen Texturpixeln, z. B. { width, height }), um das Element innerhalb der Zieltextur zu skalieren und zu rastern. |
origin optional |
GPUOrigin3D |
Der 3D-Zielversatz (x, y, z) innerhalb der Textur, in die die gerasterten Pixel geschrieben werden. Die Standardeinstellung ist [0, 0, 0]. |
mipLevel optional |
GPUIntegerCoordinate |
Die spezifische Mipmap-Ebene der Zieltextur, in die geschrieben werden soll. Die Standardeinstellung ist 0. |
aspect optional |
GPUTextureAspect |
Gibt an, in welchen Texturaspekt kopiert werden soll ("all", "stencil-only" oder "depth-only"). Der Standardwert ist "all". |
colorSpace optional |
PredefinedColorSpace |
Der Zielfarbraum (z. B. "srgb", "display-p3") für die Farbkonvertierung beim Upload. Die Standardeinstellung ist "srgb". |
premultipliedAlpha optional |
boolean | Gibt an, ob Alpha beim Upload in die Farbkanäle vormultipliziert werden soll. Die Standardeinstellung ist false. |
Laden Sie das Element im paint-Ereignis in Ihre Textur hoch, indem Sie die Methode drawElementImageToTexture() aufrufen:
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);
});
Geometrie synchronisieren
Wenn Sie die DOM-Trefferprüfung und die Fokusringe für Bedienungshilfen an der gerenderten Canvas-Ausgabe ausrichten möchten, erstellen Sie eine DOMMatrix-Transformation und wenden Sie sie mit der Methode updateElementGeometry() an:
// 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 });