Start · Sprachen · JavaScript · Referenz · XRWebGLSubImage.colorTextureHeight

XRWebGLSubImage.colorTextureHeight

Eigenschaft

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

seit JavaScript WebXR Layers API (experimentell, u. a. Meta Quest Kategorie: webapi

Signatur

XRWebGLSubImage.colorTextureHeight

Beschreibung

Die schreibgeschützte Eigenschaft colorTextureHeight der Schnittstelle XRWebGLSubImage gibt an, wie hoch die WebGL-Textur in colorTexture in Pixeln ist. Ein XRWebGLSubImage erhält man pro Frame über XRWebGLBinding.getSubImage() (z. B. bei Quad-, Zylinder- oder Equirect-Ebenen) oder über XRWebGLBinding.getViewSubImage() (bei Projektionsebenen).

Wichtig ist der Unterschied zum viewport: Der Viewport beschreibt nur den Bereich, in den für eine bestimmte Ansicht gezeichnet wird. Die Textur selbst kann größer sein – etwa wenn beide Augen in einer gemeinsamen, nebeneinander angeordneten Textur liegen oder der Browser mehr Speicher reserviert, als die Ebene braucht. colorTextureHeight (zusammen mit colorTextureWidth) gibt die tatsächliche Größe der Textur an.

Typische Einsatzfälle sind:

  • das Anlegen eigener Renderbuffer oder Tiefentexturen in passender Größe, wenn die Ebene ohne Tiefen-/Stencil-Anhang erzeugt wurde,
  • das Umrechnen von Viewport-Pixeln in normalisierte Texturkoordinaten (z. B. für Post-Processing-Shader),
  • das Prüfen, ob sich die Texturgröße zwischen Frames geändert hat, damit eigene Ressourcen neu angelegt werden können.

Rückgabewert

Typ
number
Beschreibung
Eine vorzeichenlose Ganzzahl (unsigned long) mit der Höhe der Farbtextur in Pixeln.

Beispiele

Texturgröße einer Projektionsebene pro Ansicht auslesen

// Voraussetzung: Session mit requiredFeatures: ['layers']
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const binding = new XRWebGLBinding(session, gl);
const layer = binding.createProjectionLayer({ textureType: 'texture' });
session.updateRenderState({ layers: [layer] });

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

  for (const view of pose.views) {
    const subImage = binding.getViewSubImage(layer, view);
    const { width, height } = subImage.viewport;
    console.log(`${view.eye}: Textur ${subImage.colorTextureWidth}x${subImage.colorTextureHeight}, Viewport ${width}x${height}`);
  }
};
session.requestAnimationFrame(onFrame);
left: Textur 3664x1920, Viewport 1832x1920 right: Textur 3664x1920, Viewport 1832x1920

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

let depthRb = null;
let rbWidth = 0;
let rbHeight = 0;

const ensureDepthBuffer = (gl, subImage) => {
  const w = subImage.colorTextureWidth;
  const h = subImage.colorTextureHeight;
  if (depthRb && w === rbWidth && h === rbHeight) return depthRb;

  if (depthRb) gl.deleteRenderbuffer(depthRb);
  depthRb = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, depthRb);
  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT24, w, h);
  rbWidth = w;
  rbHeight = h;
  console.log(`Tiefenpuffer neu: ${w}x${h}`);
  return depthRb;
};

// Im Frame-Callback:
// const subImage = binding.getSubImage(quadLayer, frame);
// gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
// gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, subImage.colorTexture, 0);
// gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, ensureDepthBuffer(gl, subImage));
Tiefenpuffer neu: 1024x1024

Viewport in normalisierte Texturkoordinaten umrechnen

const viewportToUv = (subImage) => {
  const { x, y, width, height } = subImage.viewport;
  const texW = subImage.colorTextureWidth;
  const texH = subImage.colorTextureHeight;
  return {
    u0: x / texW,
    v0: y / texH,
    u1: (x + width) / texW,
    v1: (y + height) / texH
  };
};

// z. B. als Uniform an einen Post-Processing-Shader übergeben
// const uv = viewportToUv(subImage);
// gl.uniform4f(uvRectLoc, uv.u0, uv.v0, uv.u1, uv.v1);
{ u0: 0.5, v0: 0, u1: 1, v1: 1 } // z. B. für das rechte Auge

// Wichtig · Fallstricke

  • Nicht mit dem Viewport verwechseln: Für gl.viewport() immer subImage.viewport verwenden. colorTextureHeight ist die Höhe der gesamten Textur und kann größer sein als der Zeichenbereich einer Ansicht.
  • Nur innerhalb des Frames gültig: Sub-Images und ihre Texturen gelten nur im aktuellen requestAnimationFrame-Callback. Sub-Image jeden Frame neu holen und Texturen nicht über Frames hinweg speichern.
  • Texturarrays: Bei Ebenen mit textureType: 'texture-array' beschreibt der Wert die Höhe einer einzelnen Schicht. Welche Schicht gemeint ist, steht in imageIndex.
  • Kompatibilität: Die WebXR Layers API ist experimentell und wird bisher vor allem von Chromium-basierten XR-Browsern (z. B. Meta Quest Browser) unterstützt. Die Session muss mit dem Feature 'layers' angefragt werden, und es wird ein sicherer Kontext (HTTPS) benötigt. Vorher prüfen, ob die Funktion vorhanden ist, z. B. mit 'XRWebGLBinding' in window.
  • Es gibt passende Eigenschaften für andere Anhänge: depthStencilTextureHeight und motionVectorTextureHeight. Diese können von der Farbtextur abweichen oder null sein.