在 WebGPU 畫布中算繪 HTML,可享有 WebGL 畫布中 HTML 的所有優點,例如將著色器效果套用至 DOM,或將互動式 HTML 整合至 3D 場景。不過,WebGPU 的優勢遠勝 WebGL。
本指南說明如何將 HTML 轉譯為 WebGPU 畫布。如要進一步瞭解 Canvas 中的 HTML,請參閱 API 總覽。
在 WebGPU 畫布中轉譯 HTML 需要執行下列步驟:
- 準備畫布。以宣告方式設定正確的屬性,讓瀏覽器知道應將 HTML 轉譯為畫布。這項設定在 2D、WebGL 和 WebGPU 環境中都相同。瞭解如何設定畫布,以及如何宣告要獨立繪製的 HTML 元素。
- 將 HTML 套用為紋理:
- 預先分配 GPU 紋理儲存空間。
- 將 DOM 快照上傳為紋理。
- 同步處理 DOM 和像素。
將 HTML 元素繪製為 WebGPU 紋理
在 WebGPU 中,HTML 元素會使用 drawElementImageToTexture() 上傳至 GPU 做為 2D 紋理。
預先分配紋理儲存空間
WebGPU 需要明確的記憶體配置。將 DOM 像素複製到紋理前,必須使用 device.createTexture() 方法保留 GPU VRAM:
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 元素圖片
在 WebGPU 中,drawElementImageToTexture() 方法會繪製 HTML 元素的快照。這個方法會採用兩個字典物件:source 和 destination。
source 定義要光柵化的來源 DOM 元素,以及選用的子矩形裁剪座標,讓您只將元素的一部分複製到紋理,而不是整個 DOM 節點:
| 屬性 | 類型 | 說明 |
|---|---|---|
必須填寫「source」 |
Element 或 ElementImage |
要繪製到紋理中的目標 DOM 元素 (或預先擷取的 ElementImage 執行個體)。 |
sourceX 選填 (四個都填或都不填) |
浮點數 | 水平 X 座標偏移 (以 CSS 像素為單位),定義來源子矩形切片的左上角。 |
sourceY 選填 (四個都填或都不填) |
浮點數 | 垂直 Y 座標偏移 (以 CSS 像素為單位),定義來源子矩形切片的左上角。 |
sourceWidth 選填 (四個都填或都不填) |
浮點數 | 要裁剪及光柵化的來源子矩形寬度 (以 CSS 像素為單位)。 |
sourceHeight 選填 (四個都填或都不填) |
浮點數 | 要裁剪及光柵化的來源子矩形高度 (以 CSS 像素為單位)。 |
destination 定義接收算繪 DOM 快照的目標 GPU 紋理,以及選用的目的地偏移、Mip 層級和複製維度,將像素放入紋理的特定區域:
| 屬性 | 類型 | 說明 |
|---|---|---|
必須填寫「texture」 |
GPUTexture |
預先分配的目的地 WebGPU 紋理,會接收轉譯的 DOM 像素快照。 |
size 個選答題 |
GPUExtent3D |
在目標紋理中縮放及光柵化元素的寬度和高度 (以實體紋理像素為單位,例如 { width, height })。 |
origin 個選答題 |
GPUOrigin3D |
紋理內 3D 目的地偏移 (x、y、z),光柵化像素會寫入此處。預設值為 [0, 0, 0]。 |
mipLevel 個選答題 |
GPUIntegerCoordinate |
要寫入的目的地紋理特定 mipmap 層級。預設值為 0。 |
aspect 個選答題 |
GPUTextureAspect |
指定要複製到哪個紋理層面 ("all"、"stencil-only" 或 "depth-only")。預設值為 "all"。 |
colorSpace 個選答題 |
PredefinedColorSpace |
上傳時用於色彩轉換的目的地色域 (例如 "srgb"、"display-p3")。預設值為 "srgb"。 |
premultipliedAlpha 個選答題 |
布林值 | 上傳期間是否應將 Alpha 預乘至色彩通道。預設值為 false。 |
呼叫 drawElementImageToTexture() 方法,將元素上傳至 paint 事件中的紋理:
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);
});
同步處理幾何圖形
如要讓 DOM 點擊測試和無障礙焦點環與轉譯的畫布輸出內容對齊,請建構 DOMMatrix 轉換,並使用 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 });
後續步驟
- 瞭解 HTML-in-Canvas 的核心技術概念。
- 瞭解如何在 2D 情境中算繪 HTML。
- 瞭解如何在 WebGL Canvas 中算繪 HTML。
- 瞭解備用策略。
- 歡迎在 GitHub 回報問題,分享您的意見。
- 請參閱社群提供的 HTML-in-Canvas 示範集合。