block by HarryStevens 4efcfa44173b35ca984d7649a5d16be3

Alocasia

Full Screen

Model from free3d.com. Use the arrow keys to move the camera.

index.html

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
    #loading {
      font-family: "Helvetica Neue", sans-serif;
      position: absolute;
      text-align: center;
      top: 33%;
      width: 100%;
    }
  </style>
</head>
<body>
  <div id="stats"></div>
  <div id="scene"></div>
  <div id="loading">Loading plant (<span class="percent"></span>%)</div>

  <script src="https://unpkg.com/three@0.106.2/build/three.min.js"></script>
  <script src="https://unpkg.com/three@0.106.2/examples/js/libs/stats.min.js"></script>
  <script src="https://unpkg.com/three@0.106.2/examples/js/libs/dat.gui.min.js"></script>
  <script src="https://unpkg.com/three@0.106.2/examples/js/loaders/OBJLoader.js"></script>
  <script src="https://unpkg.com/geometric@1.3.4/build/geometric.min.js"></script>

  <script>
    const controls = { rotate: false };
    const gui = (_ => {
      const gui = new dat.GUI();
      gui.add(controls, "rotate");
      return gui;
    })();

    let left = 0, right = 0, up = 0, down = 0;
    addEventListener("keydown", e => {
      switch (e.key) {
        case "ArrowLeft":
          left = 1;
          e.preventDefault();
          break;
        case "ArrowRight":
          right = 1;
          e.preventDefault();
          break;
        case "ArrowUp":
          up = 1;
          e.preventDefault();
          break;
        case "ArrowDown":
          down = 1;
          e.preventDefault();
          break;
      }
    });
    addEventListener("keyup", e => {
      switch (e.key) {
        case "ArrowLeft":
          left = 0;
          e.preventDefault();
          break;
        case "ArrowRight":
          right = 0;
          e.preventDefault();
          break;
        case "ArrowUp":
          up = 0;
          e.preventDefault();
          break;
        case "ArrowDown":
          down = 0;
          e.preventDefault();
          break;
      }
    });

    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 = (_ => {
      const scene = new THREE.Scene();
      scene.fog = new THREE.Fog("#eee", 0.010, 125);
      return scene;
    })();

    const camera = (_ => {
      const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 0.1, 1000);
      camera.position.set(-30, 15, 0);
      camera.lookAt(0, 5, 0);
      return camera;
    })();

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

    const plane = (_ => {
      const geom = new THREE.PlaneBufferGeometry(33, 33);
      const matl = new THREE.MeshLambertMaterial({ color: "#eee" });
      const plane = new THREE.Mesh(geom, matl);
      plane.rotation.x = -0.5 * Math.PI;
      plane.receiveShadow = true;
      scene.add(plane);
      return plane;
    })();

    const ambientLight = (_ => {
      const light = new THREE.AmbientLight("#000");
      scene.add(light);
      return light;
    })();

    const pointLight = (_ => {
      const light = new THREE.PointLight("#e0e5cd", 0.4);
      light.position.set(0, 50, 0);
      light.shadow.mapSize.width = 1024;
      light.shadow.mapSize.height = 1024;
      scene.add(light);
      return light;
    })();

    const spotLight = (_ => {
      const light = new THREE.SpotLight("#fff", 1);
      light.angle = Math.PI / 8;
      light.position.set(-20, 50, 20);
      light.castShadow = true;
      light.shadow.mapSize.width = 1024;
      light.shadow.mapSize.height = 1024;
      scene.add(light);
      return light;
    })();

    const loader = (_ => {
      const loader = new THREE.OBJLoader();
      loader.load(
        "01Alocasia_obj.obj",
        object => {
          const element = document.getElementById("loading");
          element.parentNode.removeChild(element);

          object.name = "plant";
          object.rotation.y = 5
          object.position.set(0, 0, 0);
          object.scale.set(0.01, 0.01, 0.01);

          object.children.forEach(child => {
            if (child.name === "Pot") {
              child.material = new THREE.MeshStandardMaterial({
                color: "#ffe685",
                metalness: .5,
                roughness: .5
              });
            }

            if (child.name.includes("Dirt")){
              child.material.color = new THREE.Color("#877050");
            }

            if (child.name === "stem" || child.name.includes("Leaf") || child.name.includes("leaf") || child.name.includes("lef")){
              child.material.color = new THREE.Color("#5a793a");
            }

            if (child.name === "Moh"){
              child.material.color = new THREE.Color("#b7ad8f");
            }
            
            child.castShadow = true;
            child.receiveShadow = true;
          });

          scene.add(object);
        },
        xhr => {
          document.querySelector(".percent").innerHTML = (xhr.loaded / xhr.total * 100).toFixed(1);
        },
        err => {
          console.log("Error:", err);
        }
      ); 
      return loader;
    })();

    function getPlant(){
      return scene.getObjectByName("plant", true);
    }

    function animate(){
      requestAnimationFrame(animate);
      stats.update();

      if (getPlant() && controls.rotate){
        getPlant().rotation.y += 0.01;
      }

      if (left){
        [camera.position.x, camera.position.z] = geometric.pointRotate([camera.position.x, camera.position.z], 0.575);
        camera.lookAt(0, 5, 0);
      }
      if (right){
        [camera.position.x, camera.position.z] = geometric.pointRotate([camera.position.x, camera.position.z], -0.575);
        camera.lookAt(0, 5, 0);
      }
      if (up){
        camera.position.y += 0.575;
        camera.lookAt(0, 5, 0);
      }
      if (down && camera.position.y >= 0.2){
        camera.position.y -= 0.575;
        camera.lookAt(0, 5, 0);
      }

      renderer.render(scene, camera);
    }
    animate();

    function resize(){
      camera.aspect = innerWidth / innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(innerWidth, innerHeight);
    }
    resize();
    onresize = resize;
  </script>

</body>
</html>