title: Use threejs to rotate an object so that it faces a random point at regular intervals
body: <p>I'm trying to use threejs to rotate an object so that it faces a random point at regular intervals.
  The code is below.</p>
  <pre><code>&lt;script type=&quot;module&quot;&gt;
  
      import * as THREE from 'https://cdn.skypack.dev/three';
      import {OBJLoader} from 'https://cdn.skypack.dev/three/examples/jsm/loaders/OBJLoader.js';
      import {MTLLoader} from 'https://cdn.skypack.dev/three/examples/jsm/loaders/MTLLoader.js';
  
      let camera;
      let scene;
      let renderer;
  
      class Fish {
          constructor() {
  
              class FishObj extends THREE.Group {
                  constructor() {
                      super();
  
                      let mtlLoader = new MTLLoader();
  
                      //Load body.
                      mtlLoader.load('3dModels/fishObj-body.mtl', (mtl) =&gt; {
                          mtl.preload();
  
                          let objLoader = new OBJLoader();
                          objLoader.setMaterials(mtl);
  
                          objLoader.load('3dModels/fishObj-body.obj', (obj) =&gt; {
  
                              obj.children[0].scale.set(5, 5, 5);
                              obj.children[0].castShadow = true;
  
                              this.add(obj.children[0]);
  
                          });
                      });
  
                      //Load tail fin.
                      mtlLoader.load('3dModels/fishObj-tale.mtl', (mtl) =&gt; {
                          mtl.preload();
  
                          let objLoader = new OBJLoader();
                          objLoader.setMaterials(mtl);
  
                          objLoader.load('3dModels/fishObj-tale.obj', (obj) =&gt; {
  
                              obj.children[0].scale.set(5, 5, 5);
                              obj.children[0].position.set(0, 0, 2.5);
                              obj.children[0].castShadow = true;
  
                              this.add(obj.children[0]);
  
                          });
                      });
  
                      //Load top fin.
                      mtlLoader.load('3dModels/fishObj-top.mtl', (mtl) =&gt; {
                          mtl.preload();
  
                          let objLoader = new OBJLoader();
                          objLoader.setMaterials(mtl);
  
                          objLoader.load('3dModels/fishObj-top.obj', (obj) =&gt; {
  
                              obj.children[0].scale.set(5, 5, 5);
                              obj.children[0].position.set(0, 2.5, 0);
                              obj.children[0].castShadow = true;
  
                              this.add(obj.children[0]);
  
                          });
                      });
  
                      //Load left fin.
                      mtlLoader.load('3dModels/fishObj-left.mtl', (mtl) =&gt; {
                          mtl.preload();
  
                          let objLoader = new OBJLoader();
                          objLoader.setMaterials(mtl);
  
                          objLoader.load('3dModels/fishObj-left.obj', (obj) =&gt; {
  
                              obj.children[0].scale.set(5, 5, 5);
                              obj.children[0].position.set(-4, 0, -3);
                              obj.children[0].castShadow = true;
  
                              this.add(obj.children[0]);
  
                          });
                      });
  
                      //Load right fin.
                      mtlLoader.load('3dModels/fishObj-right.mtl', (mtl) =&gt; {
                          mtl.preload();
  
                          let objLoader = new OBJLoader();
                          objLoader.setMaterials(mtl);
  
                          objLoader.load('3dModels/fishObj-right.obj', (obj) =&gt; {
  
                              obj.children[0].scale.set(5, 5, 5);
                              obj.children[0].position.set(4, 0, -3);
                              obj.children[0].castShadow = true;
  
                              this.add(obj.children[0]);
  
                          });
                      });
  
                      let axes = new THREE.AxesHelper(20);
                      this.add(axes);
  
                  }
              }
  
              this.obj = new FishObj();
              this.name = 'fish';
  
              this.fishDirection = new THREE.Vector3();
              this.nextPosition = this.obj.position;
              this.nextAngle = this.obj.rotation;
              this.tmpV = new THREE.Vector3();
  
              this.isRotating = false;
              this.isStraight = false;
              this.changeToRotate = Math.random() &lt; 0.5;
              this.changeToStraight = this.changeToRotate === false;
  
          }
  
          setNextAngle() {
  
              this.tmpV.set((Math.random() * 10) - (Math.random() * 10), (Math.random() * 10) - (Math.random() * 10), (Math.random() * 10) - (Math.random() * 10));
              this.tmpV.sub(this.obj.position);
              this.tmpV.normalize();
  
              this.nextAngleY = Math.atan2(this.tmpV.x, this.tmpV.z) + this.obj.rotation.y;
              this.nextAngleX = Math.atan2(this.tmpV.z, this.tmpV.y) + this.obj.rotation.x;
  
          }
  
          setRotationTime(step) {
              this.rotationStartTime = step;
              this.rotationPeriod = 120;
              this.rotationEndTime = step + this.rotationPeriod;
          }
  
          rotate(step) {
              this.obj.rotation.x = this.nextAngleX * (- 0.5 * Math.cos(Math.PI * (((step - this.rotationStartTime) / this.rotationPeriod) - 90)) + 0.5);
              this.obj.rotation.y = this.nextAngleY * (- 0.5 * Math.cos(Math.PI * (((step - this.rotationStartTime) / this.rotationPeriod) - 90)) + 0.5);
          }
  
          setNextPoint() {
              this.nextPositionX = Math.random() * 10 - Math.random() * 10;
              this.nextPositionY = Math.random() * 10 - Math.random() * 10;
              this.nextPositionZ = Math.random() * 10 - Math.random() * 10;
          }
  
          setStraightTime(step) {
              this.straightStartTime = step;
              this.straightPeriod = Math.random() * 5 * 60;
              this.straightEndTime = step + this.straightPeriod;
          }
  
          update(step) {
              if ( this.changeToRotate ) {
                  this.setNextAngle();
                  this.setRotationTime(step);
                  this.isRotating = true;
                  this.isStraight = false;
                  this.changeToRotate = false;
                  this.changeToStraight = false;
              } else if ( this.isRotating ) {
                  if ( step &gt;= this.rotationStartTime &amp;&amp; step &lt; this.rotationEndTime ) {
                      this.rotate(step);
                  } else if ( step &gt;= this.rotationEndTime ) {
                      this.isRotating = false;
                      this.isStraight = false;
                      this.changeToRotate = true;
                      this.changeToStraight = false;
                  }
              }
          }
      }
  
      const init = () =&gt; {
  
          scene = new THREE.Scene();
          camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
  
          renderer = new THREE.WebGLRenderer();
          renderer.setClearColor(new THREE.Color(0xEEEEEE));
          renderer.setSize(window.innerWidth, window.innerHeight);
          renderer.shadowMap.enabled = true;
  
          let axes = new THREE.AxesHelper(20);
          scene.add(axes);
  
          let planeGeometry = new THREE.PlaneGeometry(60, 60);
          let planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
          let plane = new THREE.Mesh(planeGeometry, planeMaterial);
          plane.receiveShadow = true;
  
          plane.rotation.x = -0.5 * Math.PI;
          plane.position.x = 0;
          plane.position.y = -10;
          plane.position.z = 0;
  
          scene.add(plane);
  
          let fish = new Fish();
          scene.add(fish.obj);
  
          let spotLight = new THREE.SpotLight(0xffffff);
          spotLight.position.set(-20, 30, -5);
          spotLight.castShadow = true;
          spotLight.shadow.mapSize.width = 2048;
          spotLight.shadow.mapSize.height = 2048;
  
          scene.add(spotLight);
  
          camera.position.x = -10;
          camera.position.y = 40;
          camera.position.z = 30;
          camera.lookAt(scene.position);
  
          document.getElementById(&quot;WebGL-output&quot;).appendChild(renderer.domElement);
  
          let step = 0;
  
          const renderScene = () =&gt; {
  
              step++;
              fish.update(step);
  
              requestAnimationFrame(renderScene);
              renderer.render(scene, camera);
          }
  
          renderScene();
  
      }
  </code></pre>
  <p>In the code, for the purpose of change the fish direction, change the flags(isRotating, changeToRotate) regularly in the Fish.update() method. From this, the fishObj changes its direction regularly using the methods setNextAngle(), setRotationTime() and rotate().
  Current rotate() method rotates the object from angle 0(x:0, y:0) to next angle(x:nextAngleX, y:nextAngleY) every time.
  So I change the rotate() method like below so that the fish start rotation from the last angle.</p>
  <pre><code>        rotate(step) {
              this.obj.rotation.x += this.nextAngleX * (- 0.5 * Math.cos(Math.PI * (((step - this.rotationStartTime) / this.rotationPeriod) - 90)) + 0.5);
              this.obj.rotation.y += this.nextAngleY * (- 0.5 * Math.cos(Math.PI * (((step - this.rotationStartTime) / this.rotationPeriod) - 90)) + 0.5);
          }
  //(- 0.5 * Math.cos(Math.PI * (((step - this.rotationStartTime) / this.rotationPeriod) - 90)) + 0.5) is the equation so that the object starting and ending rotation gradually.
  </code></pre>
  <p>The above code ended up spinning the fish into a mess.
  This may be funny but not properly.</p>
  <p>I have researched the threejs official docs, other web articles, this StackOverFlow, and so on. So I'm confused about what method and class should I use(THREE.Object3.rotate, THREE.quartanion, axes, THREE.Vector3, Vector3.normalize....?!), what order of using these methods and classes.</p>
  <p>Please help me.</p>
  <p>three.js : v0.136.0</p>