Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three.js Move an object to front of camera

Tags:

three.js

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

like image 543
Eugene Fitzher Avatar asked Jan 27 '26 01:01

Eugene Fitzher


1 Answers

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);

Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!