brianzinn / react-babylonjs

React for Babylon 3D engine
https://brianzinn.github.io/react-babylonjs/
809 stars 102 forks source link

Use current visibility state of canvas. Fixes #310 #311

Closed sevaseva closed 4 months ago

sevaseva commented 4 months ago

Even though the observer is created with one threshold, it may be notified with multiple successive entries (with different entry.time values) at once (perhaps if multiple DOM modification were made in the main thread and intermediate notification could not have been sent).

While I am here, removing logging that's confusing to devs, end users.

sevaseva commented 4 months ago

This plain HTML app prints all entries to console,helps see that two entries (first hiding the canvas and second making it visible it again) with different timestamps arrive to one callback call when "enter immersive session" button is clicked on chrome desktop with when Meta webxr emulator extension starts the session.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>.</title>

  <style>
    html,
    body {
      overflow: hidden;
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
    }

    #renderCanvas {
      width: 100%;
      height: 100%;
      touch-action: none;
    }
  </style>

  <script src="https://cdn.babylonjs.com/babylon.js"></script>
  <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
  <script src="https://code.jquery.com/pep/0.4.3/pep.js"></script>
</head>

<body>
  <canvas id="renderCanvas" touch-action="none"></canvas>

  <script>

    var isCanvasVisible = false;

    (async () => {

      const canvas = document.getElementById("renderCanvas");
      const engine = new BABYLON.Engine(canvas, true);
      const scene = new BABYLON.Scene(engine);

      const camera = new BABYLON.ArcRotateCamera("camera", 0, 1, 10, BABYLON.Vector3.Zero(), scene);
      camera.attachControl(canvas, true);

      new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
      BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 2, segments: 32 }, scene).position.y = 1;
      const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 6, height: 6 }, scene);

      await scene.createDefaultXRExperienceAsync({
        uiOptions: {
          sessionMode: 'immersive-vr',
          referenceSpaceType: "local-floor"
        },
        floorMeshes: [ground],
        optionalFeatures: true,
      });
      const callbackFn = (entries) => {
        console.log("Entries:", entries)
        const last = entries[entries.length - 1]
        isCanvasVisible = last.isIntersecting
        console.log("canvas visibility changed:", isCanvasVisible)
      }

      const observer = new IntersectionObserver(callbackFn, { threshold: 0 })
      observer.observe(canvas)

      engine.runRenderLoop(function () {
        if (isCanvasVisible) {
          scene.render();
        }
      });

      window.addEventListener("resize", function () {
        engine.resize();
      });
    })();
  </script>
</body>

</html>