HTML در بوم WebGL

پرداز HTML در بوم WebGL به شما امکان می‌دهد از زیردرخت‌های DOM زنده به‌عنوان بافت‌های GPU پویا استفاده کنید، جلوه‌های سایه‌زن را روی DOM زنده اعمال کنید، و HTML تعاملی را در صحنه‌های سه‌بعدی ادغام کنید.

این راهنما نشان می‌دهد که چگونه HTML را در بوم WebGL رندر کنید. در نمای کلی API درباره HTML-in-Canvas بیشتر بدانید.

برای ارائه HTML در بوم WebGL، مراحل زیر لازم است:

  1. بوم نقاشی‌تان را آماده کنید. شاخصه‌های مناسب را به‌صورت اعلانی تنظیم کنید تا مرورگر بداند که باید HTML را در بوم رندر کند. این راه‌اندازی در بافت‌های 2D،‏ WebGL، و WebGPU یکسان است. با نحوه راه‌اندازی بوم و نحوه اعلام عناصر HTML برای ترسیم مستقل آشنا شوید.
  2. HTML را به‌عنوان بافت اعمال کنید:
    1. فضای ذخیره‌سازی بافت GPU را ازقبل اختصاص دهید.
    2. عکس آنی DOM را به‌عنوان بافت بارگذاری کنید.
  3. مدل شیءگرای سند و پیکسل‌ها را همگام‌سازی کنید.

رسم عنصر HTML به‌عنوان بافت WebGL

در WebGL، عناصر HTML بااستفاده از texElementSubImage2D() به‌عنوان بافت‌های دوبعدی در GPU بارگذاری می‌شوند.

پیش‌اختصاص دادن فضای ذخیره‌سازی بافت

برخلاف بوم دوبعدی که حافظه پشتیبان را به‌طور خودکار مدیریت می‌کند، بافت 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;
}

برای اینکه بافت با اندازه چیدمان طبیعی عنصر اچ‌تی‌ام‌ال مطابقت داشته باشد، از 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 به‌عنوان بافت

مرحله بعدی بارگذاری عنصر HTML در بافت شما در حلقه رندر یا شنونده paint است.

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

  // ...
};

همگام‌سازی هندسه

برخلاف بافت‌های دوبعدی، مرورگر نمی‌تواند به‌طور خودکار استنباط کند که بافت در کجای صفحه در بافت سه‌بعدی ظاهر می‌شود. باید آزمایش برخورد DOM و چارگوش‌های محدودکننده دسترس‌پذیری را به‌صورت دستی با توری سه‌بعدی‌تان تراز کنید.

برای انجام این کار، یک 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,
  });
});

مراحل بعدی