WebGL tuvalinde HTML

HTML'yi WebGL tuvalinde oluşturmak, canlı DOM alt ağaçlarını dinamik GPU dokuları olarak kullanmanıza, canlı DOM'a gölgelendirici efektleri uygulamanıza ve etkileşimli HTML'yi 3D sahnelere entegre etmenize olanak tanır.

Bu kılavuzda, HTML'nin WebGL tuvalinde nasıl oluşturulacağı gösterilmektedir. API'ye genel bakış bölümünde Canvas'ta HTML hakkında daha fazla bilgi edinebilirsiniz.

HTML'yi WebGL tuvalinde oluşturmak için aşağıdaki adımları uygulamanız gerekir:

  1. Tuvalinizi hazırlayın. Tarayıcının HTML'yi bir tuvalde oluşturması gerektiğini bildirmek için doğru özellikleri bildirimli olarak ayarlayın. Bu kurulum 2D, WebGL ve WebGPU bağlamlarında aynıdır. Tuvalinizi nasıl ayarlayacağınızı ve HTML öğelerini bağımsız olarak çizilecek şekilde nasıl tanımlayacağınızı öğrenin.
  2. HTML'yi doku olarak uygulama:
    1. GPU doku depolama alanını önceden tahsis etme
    2. DOM anlık görüntüsünü doku olarak yükleyin.
  3. DOM'u ve pikselleri senkronize edin.

HTML öğesini WebGL dokusu olarak çizme

WebGL'de HTML öğeleri, texElementSubImage2D() kullanılarak GPU'ya 2D dokular olarak yüklenir.

Doku depolama alanını önceden tahsis etme

Yedekleme belleğini otomatik olarak yöneten 2D tuvalin aksine, WebGL bağlamı açık bellek yönetimi gerektirir.

DOM piksellerini yüklemeden önce GPU belleğini önceden tahsis etmeniz gerekir. Bu sayede tarayıcı, maliyetli GPU bellek yeniden tahsislerini tetiklemeden hızlı alt resim güncellemeleri yapabilir.

Seçilen boyut parametreleriyle arabelleği önceden tahsis edin ve srcData değerini aşağıdaki gibi null olarak ayarlayın:

// 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;
}

Dokunun HTML öğesinin doğal düzen boyutuyla eşleşmesi için canvas.getElementImageDefaultSize() kullanarak tuval ızgara pikselleri cinsinden varsayılan boyutunu alın:

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 anlık görüntüsünü doku olarak yükleme

Sonraki adım, HTML öğesini oluşturma döngünüz veya paint dinleyiciniz içindeki dokunuza yüklemektir.

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()`
  );

  // ...
};

Geometriyi senkronize etme

2D bağlamların aksine, tarayıcı, dokunun 3D bağlamda ekranda nerede göründüğünü otomatik olarak tahmin edemez. DOM isabet testini ve erişilebilirlik sınırlayıcı kutularını 3D ağınızla manuel olarak hizalamanız gerekir.

Bunun için öğenin kenarlık kutusunu oluşturulan tuval piksel konumuna eşleyen bir DOMMatrix oluşturun, ardından updateElementGeometry() kullanarak uygulayın:

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,
  });
});

Sonraki adımlar