向启用了OrbitControls的three.js项目添加点-and-点击导航

huangapple go评论67阅读模式
英文:

Adding point-and-click navigation to a three.js project where OrbitControls is enabled

问题

我在three.js中正在制作一个带有点-and-click导航功能的导航测试

这个问题出在当与OrbitControls一起使用时,相机移动时始终指向同一位置:向启用了OrbitControls的three.js项目添加点-and-点击导航

OrbitControls给相机提供一个目标,使其保持注视,从而实现“轨道”效果。我的第一次尝试是在相机移动期间使用controls.enabled = false禁用OrbitControls,然后在gsaponComplete()回调函数中重新启用它,但是这并不起作用,因为controls.enabled = false只是禁用与用户的交互,而不会阻止相机注视其目标。

我还尝试在动画循环中添加条件,防止OrbitControls在移动期间影响相机:

if (!camera_is_moving) {
    controls.update();
}

但是相机一旦动画完成就会重新注视目标。

最后,我决定在一个名为offset的变量中存储相机到其目标的距离,然后在动画结束时使用该偏移量定义一个新的目标。move_cam() 函数最终如下:

const move_cam = () => {
    camera_is_moving = true;
    const offset = {
        x: controls.target.x - camera.position.x,
        y: controls.target.y - camera.position.y,
        z: controls.target.z - camera.position.z,
    };

    const new_pos = { ...marker.position };
    new_pos.y = CAMERA_HEIGHT;

    gsap.to(camera.position, {
        duration: 2,
        x: new_pos.x,
        y: new_pos.y,
        z: new_pos.z,

        onComplete: () => {
            controls.target.x = offset.x + camera.position.x;
            // controls.target.y = offset.x + camera.position.y;
            controls.target.z = offset.x + camera.position.z;

            offset.x = controls.target.x - camera.position.x;
            offset.y = controls.target.y - camera.position.y;
            offset.z = controls.target.z - camera.position.z;
            camera_is_moving = false;
        }
    });
};

我确信这会起作用,而且确实有点作用,但相机在动画结束时有点颤动,好像我分配的新目标不太正确:向启用了OrbitControls的three.js项目添加点-and-点击导航

如果你仔细观察GIF,可以看到动画末尾,相机会颤动一下。有时它非常明显,有时它只是一个小的移动。

我不知道是什么原因导致这个问题,我的目标是使相机的旋转在动画之前和之后保持相同,所以我认为如果我通过与相机本身相同的量来偏移相机的目标,它应该会起作用,但显然没有。

有人可以帮助我解决这个问题吗?

如果你想尝试并看看我是什么意思,我在这个GitHub仓库中上传了项目。完整的js文件在这里

提前感谢你。

英文:

I am making a navigation test in three.js with a point-and-click navigation functionality.

The point-and-click mechanic is really simple : a raycaster determines the point in the plane where the user clicked and I move the camera there with gsap:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const move_cam = () =&gt; {
    const new_pos = { ...marker.position };
    gsap.to(camera.position, {
      duration: 2,
      x: new_pos.x,
      z: new_pos.z,

      onComplete: () =&gt; {
      }
    });
  };

<!-- end snippet -->

The problem with this is that, when used along with OrbitControls, the camera moves while always pointing to the same place :
向启用了OrbitControls的three.js项目添加点-and-点击导航

The reason is that OrbitControls gives a target to the camera to keep looking at, allowing it to "orbit".

My first attempt was just to disable OrbitControls during the camera movement with controls.enabled= false and reenabling it after the fact with the callback function onComplete() of gsap but it doesn't work since controls.enabled= false only disables the interaction with the user but it doesn't keep the camera from looking at its target.

I also thought about preventing OrbitControls to affect the camera during the movement by adding a condition to the animation loop :

if (!camera_is_moving) {
controls.update();
}

But the camera goes back to looking at the target as soon as the animation is finished.

As a last ressort, I decided to store the distance of the camera to its target in an variable called offset and then using that offset to define a new target at the end of the animation. And the move_cam() function ended up like this :

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const move_cam = () =&gt; {
    camera_is_moving = true;
    const offset = {
      x: controls.target.x - camera.position.x,
      y: controls.target.y - camera.position.y,
      z: controls.target.z - camera.position.z,
    };

    const new_pos = { ...marker.position };
    new_pos.y = CAMERA_HEIGHT;
    
    gsap.to(camera.position, {
      duration: 2,
      x: new_pos.x,
      y: new_pos.y,
      z: new_pos.z,

      onComplete: () =&gt; {
        controls.target.x = offset.x + camera.position.x;
        // controls.target.y= offset.x + camera.position.y;
        controls.target.z = offset.x + camera.position.z;

        offset.x = controls.target.x - camera.position.x;
        offset.y = controls.target.y - camera.position.y;
        offset.z = controls.target.z - camera.position.z;
        camera_is_moving = false;
      }

    });
  };

<!-- end snippet -->

I was sure it would work and I kind of did but the camera kind of twitches at the end of the animation as if the new target I assigned was not quite the correct one :

向启用了OrbitControls的three.js项目添加点-and-点击导航

If you look closely at the gif, right at the end of the animation, the camera stutters a bit. Sometimes it's very significant and sometimes it's just a small movement.

I don't know what's causing this, my objective is that the camera's rotation stays the same as before the animation so I thought that if I offset the camera's target by the same amount as the camera itself, it would work but apparently, it didn't.

Can anyone help me with this?

I uploaded the project in this Github repo if you want to try and see what I mean.
The full js file is here.

Thank you in advance.

答案1

得分: 0

我通过使用gsap单独为摄像机目标设置动画来解决了这个问题,而不是在onComplete()回调中设置其值,因此move_cam()函数最终如下:

英文:

I managed to solve it by animating the camera target separately with gsap instead of setting its value in the onComplete() callback so the move_cam() function ended up like this :

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const move_cam = () =&gt; {
    camera_is_moving = true;
    controls.enabled = false;
    const offset = {
      x: controls.target.x - camera.position.x,
      y: controls.target.y - camera.position.y,
      z: controls.target.z - camera.position.z,
    };
    const new_pos = { ...marker.position };
    new_pos.y = camera.position.y;

    gsap.to(this.camera.position, {
      duration: this.camera_travel_duration,
      x: new_pos.x,
      y: new_pos.y,
      z: new_pos.z,

      onComplete: () =&gt; {
        offset.x = controls.target.x - camera.position.x;
        offset.y = controls.target.y - camera.position.y;
        offset.z = controls.target.z - camera.position.z;

        camera_is_moving = false;
        controls.enabled = true;
      },
    });
    gsap.to(controls.target, {
      duration: camera_travel_duration,
      x: offset.x + new_pos.x,
      z: offset.z + new_pos.z,
    });
  };

<!-- end snippet -->

I solves my problem completely but I still don't know why the previous code didn't work.

huangapple
  • 本文由 发表于 2023年3月15日 21:06:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75745151.html
  • gsap
  • javascript
  • orbitcontrols
  • three.js