【问题标题】:Three.js Move an object to front of cameraThree.js 将对象移动到相机前面
【发布时间】:2020-04-25 12:42:19
【问题描述】:

您好,我正在尝试将一个物体移动到相机前面,当它到达目标位置时,我希望它停止。但它不起作用。

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

我正在检查相机和物体之间的距离,如果达到目标距离,我会让它停下来,但它不起作用。 在坐标中,如果我在正X坐标,距离减小,否则距离增加。

我认为,在我的代码中,距离应该一直在减少,但事实并非如此。

请帮忙。谢谢。

【问题讨论】:

  • 我一直在看代码或几分钟。控制,那是轨道控制,对吧?这意味着(在旋转轨道之后)相机的 y 位置可能不是 0。您检查相机到物体的距离,但仅在 Z 轴上平移,那么距离可能永远不会低于 200。是目标是将对象设置在cameraView中心的固定距离?然后我建议获取 camera.worldDirection,将长度设置为 200 并将对象位置调整到该目标。否则,也许添加一个jsfiddle? :s :)
  • 也; var distance = camera.position.distanceTo(object.position);是一个vector3函数;)
  • @EthanHermsey 感谢您的回复。是的,它是轨道控制。我之前尝试过 object.position.addVectors(~) ,但它也不起作用。如果我将相机移动到物体上,它确实有效。甚至 position.distanceTo 也不起作用。但最重要的是,当我将相机移动到对象时,效果很好。
  • 听起来很奇怪。您看到下面发布的@gman 答案了吗?!他的代码和解释做得非常好!这是您正在寻找的功能吗?
  • 我不知道移动物体和移动相机有什么区别。将相机移动到物体上工作得很好,但物体却不行。也许我需要做一个新项目,并在没有任何功能的情况下对其进行测试。

标签: three.js


【解决方案1】:

您可以使用object.position.lerp(target, amount) 将对象移向目标。金额是一个从 0 到 1 的值,其中 1 = 100% 一直到目标,0.5 = 50% 到目标。

如果你想以固定的速度移动,那么你可以获得到目标的距离

distance = object.position.distanceTo(target);

假设您希望每次交互最多 0.1 个单位。那么

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

剩下的就是让你选择一个目标。

镜头前的位置是

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

例如,如果您移动相机(用鼠标拖动,使用滚轮)。注意:在代码中,速度被调整为与帧速率无关。

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>

请注意,您可能想在所有数学运算之前调用camera.updateMatrixWorld(),以确保目标不会迟到一帧。

如果对象在层次结构中,那么还有更多工作要做。您可以进行数学运算,也可以将对象附加到场景中,然后将其附加回其在层次结构中的位置

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

【讨论】:

  • 我发现了一个问题!对象正在分组,我删除了组,效果很好!谢谢@gman!
  • 抱歉,我还有一个问题。我正在旋转一些对象,并使用 `objectPivot.rotation.y += 0.001; ` 在这种情况下,它不会到达相机的中心,但是当我移除动画时,它就完美了。我必须对其进行动画处理,并且我正在尝试让 rotation.y = 0;或 object.lookAt(camera.position);在物体移动之前,没有任何效果。
猜你喜欢
  • 2014-10-10
  • 1970-01-01
  • 2013-06-17
  • 1970-01-01
  • 2013-01-27
  • 1970-01-01
  • 1970-01-01
  • 2013-03-14
  • 2019-04-10
相关资源
最近更新 更多