การแสดงผล HTML ภายใน Canvas ของ WebGPU มอบประโยชน์ทั้งหมดที่ HTML ใน Canvas ของ WebGL มี เช่น การใช้เอฟเฟกต์ตัวปรับเฉดสีกับ DOM หรือการผสานรวม HTML แบบอินเทอร์แอกทีฟเข้ากับฉาก 3 มิติ อย่างไรก็ตาม WebGPU มีข้อดีที่สำคัญเมื่อเทียบกับ WebGL
คู่มือนี้แสดงวิธีแสดงผล HTML ใน Canvas ของ WebGPU ดูข้อมูลเพิ่มเติมเกี่ยวกับ HTML-in-Canvas ในภาพรวม API
การแสดงผล HTML ใน Canvas ของ WebGPU ต้องทำตามขั้นตอนต่อไปนี้
- เตรียมผืนผ้าใบ ตั้งค่าแอตทริบิวต์ที่ถูกต้องอย่างชัดเจนเพื่อให้เบราว์เซอร์ทราบว่าควรแสดงผล HTML เป็น Canvas การตั้งค่านี้เหมือนกันในบริบท 2D, WebGL และ WebGPU ดูวิธีตั้งค่า Canvas และวิธีประกาศองค์ประกอบ HTML ที่จะวาดแยกกัน
- ใช้ HTML เป็นพื้นผิวโดยทำดังนี้
- จัดสรรพื้นที่เก็บข้อมูลพื้นผิว GPU ล่วงหน้า
- อัปโหลดภาพรวม DOM เป็นพื้นผิว
- ซิงค์ DOM และพิกเซล
วาดองค์ประกอบ HTML เป็นพื้นผิว WebGPU
ใน WebGPU ระบบจะอัปโหลดองค์ประกอบ HTML ไปยัง GPU เป็นพื้นผิว 2 มิติโดยใช้ drawElementImageToTexture()
จัดสรรพื้นที่เก็บข้อมูลพื้นผิวล่วงหน้า
WebGPU ต้องมีการจัดสรรหน่วยความจำอย่างชัดเจน ก่อนคัดลอกพิกเซล DOM ลงในพื้นผิว คุณต้องจอง GPU VRAM โดยใช้เมธอด 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,
});
วาดรูปภาพองค์ประกอบ HTML
ใน WebGPU เมธอด drawElementImageToTexture() จะวาดภาพรวมขององค์ประกอบ HTML เมธอดนี้ใช้ออบเจ็กต์พจนานุกรม 2 รายการ ได้แก่ source และ destination
source กำหนดองค์ประกอบ DOM ต้นทางที่จะแรสเตอร์และพิกัดการตัดสี่เหลี่ยมผืนผ้าย่อยที่ไม่บังคับ ซึ่งช่วยให้คุณคัดลอกเฉพาะบางส่วนขององค์ประกอบลงในพื้นผิวแทนที่จะเป็นโหนด DOM ทั้งหมดได้ ดังนี้
| พร็อพเพอร์ตี้ | ประเภท | คำอธิบาย |
|---|---|---|
ต้องมี source |
Element หรือ ElementImage |
องค์ประกอบ DOM เป้าหมาย (หรืออินสแตนซ์ ElementImage ที่บันทึกไว้ล่วงหน้า) เพื่อวาดลงในพื้นผิว |
sourceX ไม่บังคับ (ทั้ง 4 รายการหรือไม่มีเลย) |
จำนวนลอยตัว | ออฟเซ็ตพิกัด X แนวนอน (เป็นพิกเซล CSS) ที่กำหนดมุมซ้ายบนของส่วนสี่เหลี่ยมผืนผ้าย่อยต้นทาง |
sourceY ไม่บังคับ (ทั้ง 4 รายการหรือไม่มีเลย) |
จำนวนลอยตัว | ออฟเซ็ตพิกัด Y แนวตั้ง (เป็นพิกเซล CSS) ที่กำหนดมุมซ้ายบนของส่วนสี่เหลี่ยมผืนผ้าย่อยต้นทาง |
sourceWidth ไม่บังคับ (ทั้ง 4 รายการหรือไม่มีเลย) |
จำนวนลอยตัว | ความกว้าง (เป็นพิกเซล CSS) ของสี่เหลี่ยมผืนผ้าย่อยต้นทางที่จะครอบตัดและแรสเตอร์ |
sourceHeight ไม่บังคับ (ทั้ง 4 รายการหรือไม่มีเลย) |
จำนวนลอยตัว | ความสูง (เป็นพิกเซล CSS) ของสี่เหลี่ยมผืนผ้าย่อยต้นทางที่จะครอบตัดและแรสเตอร์ |
destination กำหนดพื้นผิว GPU เป้าหมายที่ได้รับภาพรวม DOM ที่แสดงผล พร้อมด้วยออฟเซ็ตปลายทาง ระดับ MIP และมิติข้อมูลการคัดลอกที่ไม่บังคับ เพื่อวางพิกเซลลงในบริเวณที่เฉพาะเจาะจงของพื้นผิว ดังนี้
| พร็อพเพอร์ตี้ | ประเภท | คำอธิบาย |
|---|---|---|
ต้องมี texture |
GPUTexture |
พื้นผิว WebGPU ปลายทางที่จัดสรรไว้ล่วงหน้าซึ่งจะได้รับภาพรวมพิกเซล DOM ที่แสดงผล |
ระบุหรือไม่ก็ได้ size รายการ |
GPUExtent3D |
ความกว้างและความสูง (เป็นพิกเซลพื้นผิวจริง เช่น { width, height }) เพื่อปรับขนาดและแรสเตอร์องค์ประกอบภายในพื้นผิวปลายทาง |
ระบุหรือไม่ก็ได้ origin รายการ |
GPUOrigin3D |
ออฟเซ็ตปลายทาง 3 มิติ (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 รายการ |
บูลีน | เลือกว่าควรคูณอัลฟ่าล่วงหน้าลงในช่องสีระหว่างการอัปโหลดหรือไม่ ค่าเริ่มต้นคือ false |
อัปโหลดองค์ประกอบลงในพื้นผิวภายในเหตุการณ์ paint โดยเรียกใช้เมธอด 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);
});
ซิงค์เรขาคณิต
หากต้องการจัดแนวการทดสอบตัวชี้ DOM และวงแหวนโฟกัสการช่วยเหลือพิเศษให้สอดคล้องกับเอาต์พุต Canvas ที่แสดงผล ให้สร้างการเปลี่ยนรูปแบบ 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
- ดูวิธีแสดงผล HTML ในบริบท 2 มิติ
- ดูวิธีแสดงผล HTML ใน WebGL Canvas
- ดูข้อมูลเกี่ยวกับกลยุทธ์สำรอง
- แจ้งปัญหาใน GitHub เพื่อแชร์ความคิดเห็น
- ดูคอลเล็กชันเดโม HTML-in-Canvas โดยชุมชน