Start · Sprachen · JavaScript · Referenz · XRCompositionLayer.needsRedraw

XRCompositionLayer.needsRedraw

Eigenschaft

Schreibgeschützter boolescher Wert. Er zeigt an, dass der Inhalt einer WebXR-Kompositionsebene verloren ging und im nächsten Frame neu gezeichnet werden muss.

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

Signatur

XRCompositionLayer.needsRedraw

Beschreibung

Die Eigenschaft needsRedraw gehört zu XRCompositionLayer, der Basisschnittstelle aller Ebenen der WebXR Layers API. Dazu zählen XRProjectionLayer, XRQuadLayer, XRCylinderLayer, XREquirectLayer und XRCubeLayer. Den Wert setzt der Browser. Ist er true, hat der Compositor den Inhalt der Ebene verworfen oder noch nie erhalten. Die Anwendung muss die Ebene dann neu befüllen.

Wichtig ist das vor allem bei statischen Ebenen, also Ebenen mit isStatic: true. Deren Inhalt zeichnet man einmal, danach zeigt der Compositor ihn ohne erneutes Rendern an. Das spart Rechenzeit, zum Beispiel bei Menüs, Texttafeln oder Skyboxen. In bestimmten Fällen kann der Inhalt aber verloren gehen, etwa nach dem Wechsel der Sitzungssichtbarkeit oder wenn der Compositor Speicher freigibt. Dann steht needsRedraw auf true.

Frisch erzeugte Ebenen haben zunächst needsRedraw === true. Normalerweise prüft man den Wert in jedem Durchlauf der Frame-Schleife (XRSession.requestAnimationFrame()). Ist er true, holt man über XRWebGLBinding.getSubImage() die Zieltextur und zeichnet den Inhalt neu. Ist er false, überspringt man die Ebene.

Rückgabewert

Typ
boolean
Beschreibung
true, wenn der Inhalt der Ebene im nächsten Frame neu gezeichnet werden muss. Sonst false.

Beispiele

Statische Quad-Ebene nur bei Bedarf neu zeichnen

const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });

const session = await navigator.xr.requestSession('immersive-vr', {
  requiredFeatures: ['layers']
});
const refSpace = await session.requestReferenceSpace('local');
const xrGlBinding = new XRWebGLBinding(session, gl);

// Statische Texttafel: Inhalt wird nur bei Bedarf gezeichnet
const quadLayer = xrGlBinding.createQuadLayer({
  space: refSpace,
  viewPixelWidth: 1024,
  viewPixelHeight: 512,
  layout: 'mono',
  isStatic: true,
  transform: new XRRigidTransform({ x: 0, y: 1.5, z: -2 })
});

session.updateRenderState({ layers: [quadLayer] });

const fb = gl.createFramebuffer();

const drawPanel = (frame) => {
  const subImage = xrGlBinding.getSubImage(quadLayer, frame);
  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
  gl.framebufferTexture2D(
    gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D,
    subImage.colorTexture, 0
  );
  const { x, y, width, height } = subImage.viewport;
  gl.viewport(x, y, width, height);
  gl.clearColor(0.1, 0.2, 0.4, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  // ... hier Text/Grafik der Tafel zeichnen ...
  console.log('Tafel neu gezeichnet');
};

const onXRFrame = (time, frame) => {
  frame.session.requestAnimationFrame(onXRFrame);
  if (quadLayer.needsRedraw) {
    drawPanel(frame);
  }
};

session.requestAnimationFrame(onXRFrame);
Tafel neu gezeichnet // einmal beim Start und danach nur, wenn der Inhalt verloren ging

Mehrere Ebenen gemeinsam prüfen

// layers: Array aus XRCompositionLayer-Objekten, renderers: Map Ebene -> Zeichenfunktion
const redrawDirtyLayers = (frame, layers, renderers, binding) => {
  let count = 0;
  for (const layer of layers) {
    if (!layer.needsRedraw) continue;
    const subImage = binding.getSubImage(layer, frame);
    renderers.get(layer)(subImage);
    count++;
  }
  return count;
};

// In der Frame-Schleife:
// const n = redrawDirtyLayers(frame, [menuLayer, skyLayer], renderers, xrGlBinding);
// if (n > 0) console.log(`${n} Ebene(n) neu gezeichnet`);
2 Ebene(n) neu gezeichnet // z. B. im ersten Frame

Status einer neu erzeugten Ebene abfragen

const cylinderLayer = xrGlBinding.createCylinderLayer({
  space: refSpace,
  viewPixelWidth: 1200,
  viewPixelHeight: 600,
  isStatic: true
});

console.log(cylinderLayer.isStatic);    // true
console.log(cylinderLayer.needsRedraw); // true – noch kein Inhalt vorhanden
true true

// Wichtig · Fallstricke

  • Schreibgeschützt: Eine Zuweisung wie layer.needsRedraw = false hat keine Wirkung. Der Browser setzt den Wert selbst zurück, sobald die Anwendung neuen Inhalt geliefert hat.
  • Statische Ebenen: Laut Spezifikation wirft XRWebGLBinding.getSubImage() bei einer Ebene mit isStatic: true einen InvalidStateError, wenn needsRedraw gerade false ist. Prüfe den Wert deshalb immer vor dem Zeichnen.
  • Bei nicht statischen Ebenen, etwa einer XRProjectionLayer mit bewegter Szene, zeichnet man ohnehin in jedem Frame neu. Dort dient needsRedraw höchstens als zusätzlicher Hinweis.
  • Ebenen, die über XRMediaBinding aus einem <video> erzeugt werden, befüllt der Browser selbst. Für sie spielt die Eigenschaft praktisch keine Rolle.
  • Kompatibilität: Die WebXR Layers API ist experimentell. Sie läuft nur in sicheren Kontexten (HTTPS) und nur, wenn die Sitzung mit dem Merkmal 'layers' angefordert wurde. Unterstützt wird sie vor allem vom Meta Quest Browser und von Chromium-Browsern mit WebXR. Firefox und Safari unterstützen sie derzeit nicht. Die Verfügbarkeit lässt sich zum Beispiel mit 'XRWebGLBinding' in window und typeof XRWebGLBinding.prototype.createQuadLayer === 'function' prüfen.