2

Hello I'm trying to move an object to front of camera, and when it reached to target position, I want it to stop. but it doesn't work.

function objectToCamera(mX, mY, object)
{
                var vector = new THREE.Vector3(mX, mY, 1);
                vector.unproject(camera);
                vector.sub(object.position);        

                var dx = object.position.x - camera.position.x;
                var dy = object.position.y - camera.position.y;
                var dz = object.position.z - camera.position.z;

                var distance = Math.sqrt(dx*dx + dy*dy + dz*dz);

                if(lastDistance < distance && lastDistance != -1)
                    keepOut = -1;

                lastDistance = distance;

                setTimeout(function(){
                    if( distance > 200 && keepOut == 1)
                    {
                        var amount = (1)*(indexForZoom/3);

                        amount = (amount>15) ? 15 : (1)*(indexForZoom/3);

                        if(distance - amount < 200)
                            amount = (distance-200)+1;

                        indexForZoom++;
                        object.translateZ(amount);
                        controls.target.addVectors(controls.target,vector.setLength(amount));
                        objectToCamera(mX, mY, object)
                    }
                    else
                    {
                    //  stopForZoom = 1;
                        keepOut = -1;
                        objectClickHandler(object.name, object);
                    }
                }, 10);
}

I'm checking the distance between camera and object, and if target distance has reached I'm letting it stop, but it doesn't work. In coordinates, if i'm in positive X coordinates, distance is decreasing, and otherwise, distance is increasing.

I think, in my codes, distance should be decreasing always, but it is not.

Please help. Thanks.

Image to explain my case

6
  • I've been looking at the code or a few minutes. The controls, that's orbitcontrols right? That would mean that (after rotating the orbit) it is possible that the camera's y position is not 0. You check the distance from camera to object, but only translate on Z axis, then it's possible the distance is never below 200. Is the goal to set the object to a fixed distance in the center of the cameraView? Then i would suggest getting camera.worldDirection, set the length to 200 and lerp the object position to that target. Else, maybe add a jsfiddle? :s :) Commented Jan 8, 2020 at 12:47
  • also; var distance = camera.position.distanceTo( object.position ); is a vector3 function ;) Commented Jan 8, 2020 at 12:56
  • @EthanHermsey Thanks for reply. Yes, it is orbitcontrols. I have tried with object.position.addVectors(~) before, but it doens't work too. If I moved camera to object, it exactly works. Even position.distanceTo doesn't work too. But above all ways, works fine when I just move the camera to object. Commented Jan 10, 2020 at 0:02
  • Sounds very strange. Did you see the answer @gman posted below?! He did a very neat job with his code and explanation! Is this the functionallity you where looking for? Commented Jan 10, 2020 at 0:20
  • I don't know what is the different between moving object and moving camera. Moving camera to object works exactly fine, but object does not.. Maybe I need to make a new project, and test it without any function. Commented Jan 10, 2020 at 0:50

1 Answer 1

10

you can use object.position.lerp(target, amount) to move an object toward target. Amount is a value from 0 to 1 with 1 = 100% all the way to target and 0.5 = 50% way to target.

If you want to move at a fixed speed then you can get the distance to the target

distance = object.position.distanceTo(target);

Say you want a max of 0.1 units per interation. then

moveSpeed = 0.1;
distance = object.position.distanceTo(target);
amount = Math.min(moveSpeed, distance) / distance;
object.position.lerp(target, amount)

All that's left is for you to choose a target.

The position in front of the camera is

const distanceFromCamera = 3;  // 3 units
const target = new THREE.Vector3(0, 0, -distanceToCamera);
target.applyMatrix4(camera.matrixWorld);

So for example if you move the camera (drag with mouse, use scrollwheel). Note: in the code the speed is adjusted to be frame rate independent.

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const fov = 45;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 1000;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.set(0, 10, 20);

  const controls = new THREE.OrbitControls(camera, canvas);
  controls.target.set(0, 0, 0);
  controls.update();

  const scene = new THREE.Scene();
  scene.background = new THREE.Color('lightblue');

  {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(0, 10, 0);
    light.target.position.set(-5, 0, 0);
    scene.add(light);
    scene.add(light.target);
  }

  const gridHelper = new THREE.GridHelper(100, 10);
  scene.add(gridHelper);
  gridHelper.position.set(0, -5, 0);

  const cube = new THREE.Mesh(
     new THREE.BoxBufferGeometry(1, 1, 1),
     new THREE.MeshPhongMaterial({color: 'red'}),
  );
  scene.add(cube);

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  let then = 0;
  function render(now) {
    now *= 0.001; // convert to seconds
    const deltaTime = now - then;
    then = now;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }
    
    cube.rotation.x = now;
    cube.rotation.y = now * 1.1;
    
    // move cube in front of camera
    {
      const distanceFromCamera = 3;  // 3 units
      const target = new THREE.Vector3(0, 0, -distanceFromCamera);
      target.applyMatrix4(camera.matrixWorld);    
    
      const moveSpeed = 15;  // units per second
      const distance = cube.position.distanceTo(target);
      if (distance > 0) {
        const amount = Math.min(moveSpeed * deltaTime, distance) / distance;
        cube.position.lerp(target, amount);
        cube.material.color.set('green');
      } else {
        cube.material.color.set('red');
      }
    }

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
body { margin: 0; }
#c { width: 100vw; height: 100vh; display: block; }
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r112/build/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r112/examples/js/controls/OrbitControls.js"></script>
<canvas id="c"></canvas>

Note, you might want to call camera.updateMatrixWorld() before all that math to make sure the target isn't one frame late.

If the object is in a hierarchy then there's more to do. You can do the math or you can use just attach the object to the scene and then attach it it back to its place in the hierarchy

const parent = object.parent;

// move object to scene without changing it's world orientation
scene.attach(object);

// do stuff above

// move object to parent without changing it's world orientation
parent.attach(object);
Sign up to request clarification or add additional context in comments.

2 Comments

I found a problem! The object was grouping, and I removed group, it works perfect! Thanks @gman !
Sorry, I have a one more question. I am pivoting some objects, and animate with ` objectPivot.rotation.y += 0.001; ` With this condition, it is not coming to center of camera, but when I remove the animate, it comes perfectly. I have to animate it, and I'm trying to let rotation.y = 0; or object.lookAt(camera.position); before object to move, nothing works.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.