WebGL 캔버스에서 HTML을 렌더링하면 실시간 DOM 하위 트리를 동적 GPU 텍스처로 사용하고, 실시간 DOM에 셰이더 효과를 적용하고, 대화형 HTML을 3D 장면에 통합할 수 있습니다.
이 가이드에서는 HTML을 WebGL 캔버스로 렌더링하는 방법을 보여줍니다. API 개요에서 HTML-in-Canvas에 대해 자세히 알아보세요.
WebGL 캔버스에서 HTML을 렌더링하려면 다음 단계를 따르세요.
- 캔버스를 준비합니다. 브라우저가 HTML을 캔버스에 렌더링해야 한다는 것을 알 수 있도록 올바른 속성을 선언적으로 설정합니다. 이 설정은 2D, WebGL, WebGPU 컨텍스트에서 동일합니다. 캔버스를 설정하는 방법과 독립적으로 그려질 HTML 요소를 선언하는 방법을 알아보세요.
- HTML을 텍스처로 적용합니다.
- GPU 텍스처 스토리지를 미리 할당합니다.
- DOM 스냅샷을 텍스처로 업로드합니다.
- DOM과 픽셀을 동기화합니다.
HTML 요소를 WebGL 텍스처로 그리기
WebGL에서 HTML 요소는 texElementSubImage2D()를 사용하여 2D 텍스처로 GPU에 업로드됩니다.
텍스처 저장소 사전 할당
백업 메모리를 자동으로 관리하는 2D 캔버스와 달리 WebGL 컨텍스트에는 명시적인 메모리 관리가 필요합니다.
DOM 픽셀을 업로드하기 전에 GPU 메모리를 미리 할당해야 합니다. 이렇게 하면 브라우저가 비용이 많이 드는 GPU 메모리 재할당을 트리거하지 않고도 빠른 하위 이미지 업데이트를 수행할 수 있습니다.
선택한 크기 매개변수와 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 스냅샷을 텍스처로 업로드
다음 단계는 렌더링 루프 또는 paint 리스너 내에서 HTML 요소를 텍스처에 업로드하는 것입니다.
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의 핵심 기술 개념을 이해합니다.
- 2D 컨텍스트에서 HTML을 렌더링하는 방법을 알아보세요.
- WebGPU Canvas에서 HTML을 렌더링하는 방법을 알아보세요.
- 대체 전략 알아보기
- GitHub에서 문제를 제출하여 의견을 공유하세요.
- 커뮤니티의 HTML-in-Canvas 데모 모음을 확인하세요.