ThreeJS 吐温JS |平滑地移动和旋转相机到物体

ThreeJS Tween JS | Move AND Rotate the camera to an object smoothly

当我点击一个对象时,我可以围绕它移动和旋转。

这是非平滑代码:

mouseEvents() {
  window.addEventListener('click', (event: MouseEvent) => {
    event.preventDefault()
    // Get the mouse position
    this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1
    this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1

    this.raycaster.setFromCamera(this.mouse, this.camera)

    var intersects = this.raycaster.intersectObjects(this.scene.children, true)
    for (var i=0; i<intersects.length; i++) {
      // Look at the object and rotate around it
      this.controls.target.set( intersects[i].point.x, intersects[i].point.y, intersects[i].point.z )
      // Move to the object
      this.camera.position.x = intersects[i].point.x
      this.camera.position.y = intersects[i].point.y
      this.camera.position.z = (intersects[i].point.z) + 1000     
    }
  })
}

现在我想做完全相同的旋转,但旋转和移动平稳。在网上看了一堆之后,我找到了 TweenJS 并使用了它。 问题是我可以顺畅地向物体移动,但我不知道如何顺畅地看着物体并绕着它旋转

下面是流畅的代码:

mouseEvents() {
  window.addEventListener('click', (event: MouseEvent) => {
    event.preventDefault()
    // Get the mouse position
    this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1
    this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1

    this.raycaster.setFromCamera(this.mouse, this.camera)

    var intersects = this.raycaster.intersectObjects(this.scene.children, true)
    for (var i=0; i<intersects.length; i++) {
      // Look at the object and rotate around it smoothly (using tweenjs I suppose)
      ????????????
      // Move to the object smoothly
      var position = this.camera.position;
      var target = { x : intersects[i].point.x, y: intersects[i].point.y, z: intersects[i].point.z + 1000 };
      var tween = new TWEEN.Tween(position).to(target, 2000);
      tween.easing(TWEEN.Easing.Linear.None)
      tween.start()
    }
  })
}

您可能需要在渲染循环或补间自定义更新函数中的某处添加 camera.lookAt( yourTargetPoint )。

var target = new THREE.Vector3()
mouseEvents() {
  window.addEventListener('click', (event: MouseEvent) => {
    event.preventDefault()
    // Get the mouse position
    this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1
    this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1

    this.raycaster.setFromCamera(this.mouse, this.camera)

    var intersects = this.raycaster.intersectObjects(this.scene.children, true)
    for (var i=0; i<intersects.length; i++) {
      target.copy(intersects[i].point)
      var tween = new TWEEN.Tween(this.camera.position).to(target, 2000)
      tween.easing(TWEEN.Easing.Linear.None)
      tween.onUpdate(() => {
        this.camera.lookAt( target )
      })
      tween.start()
break; // BREAK HERE BECAUSE WE ONLY CARE ABOUT THE FIRST/AKA NEAREST COLLISION
    }
  })
}

您还需要确保将相机添加到场景中。您可以使用 ISNT 连接到场景的相机进行渲染,但其矩阵不会在渲染阶段更新,在这种情况下,您必须调用 .updateMatrixWorld() 来强制更新其矩阵。但是只 scene.add(camera)

更容易

我找到了另一个解决方案。我使用了 2 个不同的补间,1 个用于移动相机,1 个用于使相机注视对象。

代码如下:

mouseEvents() {
  window.addEventListener('click', (event: MouseEvent) => {
    event.preventDefault()
    // Get the mouse position
    this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1
    this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1

    this.raycaster.setFromCamera(this.mouse, this.camera)

    var intersects = this.raycaster.intersectObjects(this.scene.children, true)
    for (var i=0; i<intersects.length; i++) {

      // Move the camera towards the object and stay 1000 above it on z axis
      var positionX = intersects[i].point.x
      var positionY = intersects[i].point.y
      var positionZ = (intersects[i].point.z) + 1000    

      var positionStart = this.camera.position
      var positionEnd = { x : positionX, y: positionY, z: positionZ }
      var tweenPosition = new TWEEN.Tween(positionStart).to(positionEnd, 2000)
      tweenPosition.easing(TWEEN.Easing.Linear.None)
      tweenPosition.start()

      // Make the camera look at the object
      var rotationX = intersects[i].point.x
      var rotationY = intersects[i].point.y
      var rotationZ = intersects[i].point.z

      var rotationStart = this.controls.target
      var rotationEnd = { x : rotationX, y: rotationY, z: rotationZ }
      var tweenRotation = new TWEEN.Tween(rotationStart).to(rotationEnd, 2000)
      tweenRotation.easing(TWEEN.Easing.Linear.None)
      tweenRotation.start()

    }
  })
}