block by HarryStevens 87f0df7cc8ddf5daa3fd0ebf600f0083

THREE.js Globe

Full Screen

index.html

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
  </style>
</head>
<body>
  <div id="scene"></div>
  <div id="stats"></div>
  <script src="https://unpkg.com/three@0.146.0/build/three.js"></script>
  <script src="https://unpkg.com/three@0.146.0/examples/js/libs/stats.min.js"></script>
  <script src="https://unpkg.com/three@0.146.0/examples/js/controls/OrbitControls.js"></script>
  <script>
    const stats = (_ => {
      const stats = new Stats();
      stats.domElement.style.position = "absolute";
      stats.domElement.style.left = "0px";
      stats.domElement.style.top = "0px";
      document.getElementById("stats").appendChild(stats.domElement);
      return stats;
    })();

    const scene = new THREE.Scene();

    const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 0.1, 1000);

    const renderer = (_ => {
      const renderer = new THREE.WebGLRenderer();
      renderer.setClearColor("#fff");
      renderer.setPixelRatio(devicePixelRatio);
      document.getElementById("scene").appendChild(renderer.domElement);
      return renderer;
    })();

    const loader = new THREE.TextureLoader();

    const globe = (_ => {
      const geo = new THREE.SphereGeometry(4, 64, 64);
      const mat = new THREE.MeshBasicMaterial({
        map: loader.load("./earth.png")
      });
      const globe = new THREE.Mesh(geo, mat);
      scene.add(globe);
      return globe;
    })();

    const controls = (_ => {
      const controls = new THREE.OrbitControls(camera, renderer.domElement);

      controls.enableDamping = true;
      controls.dampingFactor = 0.1;
      controls.autoRotate = true;

      return controls;
    })();

    function animate(){
      requestAnimationFrame(animate);
      stats.update();
      controls.update();
      renderer.render(scene, camera);
    }
    animate();

    function size(){
      camera.aspect = innerWidth / innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(innerWidth, innerHeight);

      camera.position.z = cameraZ(camera, globe);

      // Disable zooming
      controls.maxDistance = camera.position.z;
      controls.minDistance = camera.position.z;
    }
    size();
    onresize = size;

    // Adapted from https://wejn.org/2020/12/cracking-the-threejs-object-fitting-nut/
    function cameraZ(camera, object){
      const boundingBox = new THREE.Box3();
      boundingBox.setFromObject(object);

      const fov = camera.fov * (Math.PI / 180);
      const fovh = 2 * Math.atan(Math.tan(fov / 2) * camera.aspect);

      const size = new THREE.Vector3();
      boundingBox.getSize(size);

      const dx = Math.abs(size.x / 2 / Math.tan(fovh / 2));
      const dy = Math.abs(size.y / 2 / Math.tan(fov / 2));
      const zDenominator = 10; // used to be 2

      return size.z / zDenominator + Math.max(dx, dy);
    };
  </script>
</body>
</html>