Search code examples
javascripthtmlthree.js3d

OrbitControls not working with Loading file


So I have this code which basically shows a 3D file (obj, stl, 3mf) inputted by the user using three js OBJLoader, STLLoader, and 3MFLoader. All works fine but I tried some (inside this code) to add OrbitControls to this so that the user can zoom in, zoom out, rotate, etc. with the file but it does not seem to work. The console has no errors at all but rotating, zooming in and out, etc. doesn't work as well with the render.

<input type="file" name="file" id="file" onchange="loadFile(event)" />
<div id="filePreview" style="width: 100%; height: 30vh"></div>
<script>
  var loadFile = function (event) {
    let oInput = document.getElementById("file");
    var _validFileExtensions = [".obj", ".stl", ".3mf"];
    function ValidateSingleInput() {
      if (oInput.type == "file") {
        var sFileName = oInput.value;
        if (sFileName.length > 0) {
          var blnValid = false;
          for (var j = 0; j < _validFileExtensions.length; j++) {
            var sCurExtension = _validFileExtensions[j];
            if (
              sFileName
                .substr(
                  sFileName.length - sCurExtension.length,
                  sCurExtension.length
                )
                .toLowerCase() == sCurExtension.toLowerCase()
            ) {
              window.fileUrl = URL.createObjectURL(event.target.files[0]);
              var scene = new THREE.Scene();

              var camera = new THREE.PerspectiveCamera(
                75,
                window.innerWidth / window.innerHeight,
                0.1,
                1000
              );

              var renderer = new THREE.WebGLRenderer();

              const controls = new THREE.OrbitControls( camera, renderer.domElement, scene );

              camera.position.z = 200;
              controls.update();

              var scene = new THREE.Scene();

              var camera = new THREE.PerspectiveCamera(
                45,
                window.innerWidth / window.innerHeight,
                1,
                2000
              );
              camera.position.z = 250;
              camera.lookAt(scene.position);
              controls.update();

              var directionalLight = new THREE.DirectionalLight(0xffeedd);
              directionalLight.position.set(0, 0, 1).normalize();
              scene.add(directionalLight);

              var mesh = null;
              if (sCurExtension == ".obj") {
                var objLoader = new THREE.OBJLoader();
                objLoader.load(window.fileUrl, function (object) {
                  mesh = object;
                  mesh.position.y = -50;
                  scene.add(mesh);
                });
              } else if (sCurExtension == ".3mf") {
                var loader = new THREE.ThreeMFLoader();
                loader.load(window.fileUrl, function (object) {
                  mesh = object;
                  mesh.position.y = -50;
                  scene.add(mesh);
                });
              } else if (sCurExtension == ".stl") {
                var loader = new THREE.STLLoader();
                loader.load(window.fileUrl, function (geometry) {
                  var material = new THREE.MeshPhongMaterial({
                    specular: 0x111111,
                    shininess: 200,
                    shading: THREE.FlatShading,
                  });
                  mesh = new THREE.Mesh(geometry, material);
                  mesh.position.y = -50;
                  scene.add(mesh);
                });
              }

              renderer.setPixelRatio(window.devicePixelRatio);
              renderer.setSize(
                filePreview.offsetWidth,
                filePreview.offsetHeight
              );

              renderer.setClearColor(0x000000);
              document.body.appendChild(renderer.domElement);

              animate();

              function animate() {
                requestAnimationFrame(animate);

                controls.update();

                renderer.render(scene, camera);
              }

              filePreview.appendChild(renderer.domElement);
              blnValid = true;
              break;
            }
          }

          if (!blnValid) {
            alert(
              "Sorry, " +
                sFileName +
                " is invalid, allowed extensions are: " +
                _validFileExtensions.join(", ")
            );
            oInput.value = "";
            return false;
          }
        }
      }
      return true;
    }

    ValidateSingleInput();
  };
</script>

<script src="http://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/loaders/3MFLoader.js"></script>
<script src="https://threejs.org/examples/js/loaders/OBJLoader.js"></script>
<script src="https://threejs.org/examples/js/loaders/STLLoader.js"></script>

Can anyone check the code out and tell me why it is not working and how to fix it?


Solution

  • OrbitControls is not directly exported as part of the Three.js library; instead it's exported as part of the examples.

    If you're using a bundler (such as WebPack) you can import it like this:

    // Typical Three.js import
    import * as THREE from "three"
    
    // Additional OrbitControls import
    import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
    

    Or if you're using a script import, you can use this:

    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    canvas {
      display: block;
    }
    <script type="module">
      import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.121.1/build/three.module.js";
      import { OrbitControls } from "https://cdn.jsdelivr.net/npm/three@0.121.1/examples/jsm/controls/OrbitControls.js";
    
      const renderer = new THREE.WebGLRenderer();
      renderer.setSize(window.innerWidth, window.innerHeight);
      document.body.appendChild(renderer.domElement);
    
      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      );
      const controls = new OrbitControls(camera, renderer.domElement);
    
      const geometry = new THREE.BoxBufferGeometry(1, 1, 1);
      const material = new THREE.MeshNormalMaterial();
      const cube = new THREE.Mesh(geometry, material);
      scene.add(cube);
    
      camera.position.z = 5;
    
      (function animate() {
        requestAnimationFrame(animate);
    
        controls.update();
        renderer.render(scene, camera);
      })();
    </script>

    Then you can use it like this:

    const controls = new OrbitControls( camera, renderer.domElement, scene );