Start · Sprachen · JavaScript · Referenz · XRWebGLSubImage.colorTextureWidth

XRWebGLSubImage.colorTextureWidth

Eigenschaft

Schreibgeschützte Zahl mit der Breite der Farbtextur (<code>colorTexture</code>) eines <code>XRWebGLSubImage</code> in Pixeln.

seit JavaScript Experimentell: WebXR Layers API (Chromium-basierte Kategorie: webapi

Signatur

XRWebGLSubImage.colorTextureWidth

Beschreibung

Die schreibgeschützte Eigenschaft colorTextureWidth gibt die Breite der WebGL-Farbtextur in Pixeln an, die über XRWebGLSubImage.colorTexture bereitgestellt wird. Diese Textur ist das Ziel, in das die Anwendung für eine bestimmte Composition-Ebene (XRProjectionLayer, XRQuadLayer, XRCylinderLayer usw.) rendert.

Ein XRWebGLSubImage erhält man pro Frame über XRWebGLBinding.getSubImage() (für Nicht-Projektionsebenen) oder XRWebGLBinding.getViewSubImage() (für Projektionsebenen je Ansicht bzw. Auge). Die Breite brauchst du vor allem dann, wenn du eigene Anhänge passend dimensionieren musst, etwa einen Tiefen-Renderbuffer, einen Multisample-Zwischenpuffer oder einen Offscreen-Framebuffer für Post-Processing.

Wichtig: colorTextureWidth beschreibt die gesamte Textur, nicht den Bereich, in den gezeichnet werden soll. Bei Projektionsebenen mit Layout "stereo-left-right" teilen sich beide Augen eine Textur. Die Textur ist dann doppelt so breit wie der Bereich eines Auges. Für gl.viewport() nimmst du deshalb immer subImage.viewport, und colorTextureWidth nur für die Größe von Texturen und Puffern.

Rückgabewert

Typ
number
Beschreibung
Eine nicht-negative Ganzzahl: die Breite der Farbtextur in Pixeln. Der Wert lässt sich nicht ändern.

Beispiele

Texturgröße im Render-Loop einer Projektionsebene auslesen

// Voraussetzung: Session mit requiredFeatures: ['layers'] und ein XR-kompatibler WebGL2-Kontext
const session = await navigator.xr.requestSession('immersive-vr', {
  requiredFeatures: ['layers']
});
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const binding = new XRWebGLBinding(session, gl);
const layer = binding.createProjectionLayer({ textureType: 'texture' });
session.updateRenderState({ layers: [layer] });

const refSpace = await session.requestReferenceSpace('local');
const fb = gl.createFramebuffer();

const onFrame = (time, frame) => {
  session.requestAnimationFrame(onFrame);
  const pose = frame.getViewerPose(refSpace);
  if (!pose) return;

  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
  for (const view of pose.views) {
    const sub = binding.getViewSubImage(layer, view);
    console.log(`Textur: ${sub.colorTextureWidth}×${sub.colorTextureHeight}`);

    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
      gl.TEXTURE_2D, sub.colorTexture, 0);
    const { x, y, width, height } = sub.viewport;
    gl.viewport(x, y, width, height); // Viewport statt Texturgröße verwenden
    // ... Szene für dieses Auge zeichnen
  }
};
session.requestAnimationFrame(onFrame);
Textur: 1832×1920 Textur: 1832×1920

Passenden Tiefen-Renderbuffer anlegen und bei Größenänderung neu erzeugen

let depthRb = null;
let depthSize = { w: 0, h: 0 };

const ensureDepthBuffer = (gl, sub) => {
  const w = sub.colorTextureWidth;
  const h = sub.colorTextureHeight;
  if (depthRb && depthSize.w === w && depthSize.h === h) return depthRb;

  if (depthRb) gl.deleteRenderbuffer(depthRb);
  depthRb = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, depthRb);
  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, w, h);
  depthSize = { w, h };
  console.log(`Tiefenpuffer neu angelegt: ${w}×${h}`);
  return depthRb;
};

// im Frame-Callback:
// const sub = binding.getSubImage(quadLayer, frame);
// const rb = ensureDepthBuffer(gl, sub);
// gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, rb);
Tiefenpuffer neu angelegt: 1024×1024

Stereo-Layout erkennen: Texturbreite mit der Viewport-Breite vergleichen

const describeLayout = (sub) => {
  const ratio = sub.colorTextureWidth / sub.viewport.width;
  return ratio >= 2 ? 'Beide Augen teilen sich eine Textur (links/rechts)'
                    : 'Eigene Textur bzw. Textur-Array-Ebene pro Auge';
};

// const sub = binding.getViewSubImage(layer, pose.views[0]);
// console.log(describeLayout(sub));
Beide Augen teilen sich eine Textur (links/rechts)

// Wichtig · Fallstricke

  • Nicht mit dem Viewport verwechseln: Bei "stereo-left-right" oder "stereo-top-bottom" ist die Textur größer als der Bereich eines Auges. Für gl.viewport() und gl.scissor() immer subImage.viewport nehmen.
  • Die Größe kann sich zwischen Frames ändern, z. B. bei Ebenen mit isStatic/Neuallokation oder bei geänderter Auflösung. Eigene Puffer deshalb pro Frame prüfen und nicht nur einmal beim Start dimensionieren.
  • Bei textureType: "texture-array" gilt die Breite für jede Ebene des Arrays. Die Ebene wählst du über imageIndex.
  • Das XRWebGLSubImage und seine Texturen gelten nur innerhalb des aktuellen requestAnimationFrame-Callbacks. Außerhalb davon den Wert nicht speichern und die Textur nicht verwenden.
  • Kompatibilität: Die WebXR Layers API ist experimentell. Sie ist nur in sicheren Kontexten (HTTPS) verfügbar und läuft vor allem in Chromium-basierten XR-Browsern (z. B. Meta Quest Browser). Die Session muss mit dem Feature "layers" angefordert werden. Firefox und Safari unterstützen sie derzeit nicht. Ein Polyfill gibt es im WebXR Layers Polyfill des Immersive Web Working Group.