threejs键盘控制相机

673 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情

一、前言

在3d场景中,我们能看到的一切,都是相机带来给我们的,所以相机就相当于我们的眼睛,而控制相机相当于我们双脚,我们移动双脚,带动眼睛看向不同的地方,不同的角度,要想充分展示我们的3d场景,那控制相机都是我们的必修课。

二、过程

1、明确我们需要控制相机的何种属性

基本是一个位置属性x,z值(即水平面上,三维的有点计算不了,鸽了鸽了),其次是相机的朝向属性。

2、目标效果

键盘wasd控制相机在x,z方向上移动,qe控制相机的旋转。

3、相机的生成和初始位置

let camera: THREE.PerspectiveCamera | THREE.Camera,renderer: THREE.WebGLRenderer,controls

相机的视图大小,定义好起始位置,朝向也写好。

camera = new THREE.PerspectiveCamera(
    75,
    1000 / 800,
    0.1,
    1000
  )
  camera.position.set(2, 1, 3)
  camera.lookAt(10, 100, 10)
  scene.add(camera)

4、然后我们导入一个车模型用来充当载体

也可以直接控制相机的位置position,进行相机的位置更新。 这里我们是把相机固定在车子的后上方,充当一个相对固定的机位,实现一个第三人称的相机视角,随着车子的位置信息改变,相机的位置也会对应修改。

采用objLoader配合mtlLoader加载器,加载我们的车辆模型和贴图,并且设置起始位置为原点,加入到场景中去。

// 加载3d车辆  obj模型
function setCar():void {
  var wepeaon = new OBJLoader()
  var carMateril = new MTLLoader()
  var container = new THREE.Object3D()
  carMateril.load('/assets/car/Bw_Fennek.mtl', (material) => {
    material.preload()
    wepeaon.setMaterials(material)
    wepeaon.load('/assets/car/Bw_Fennek.obj', (gltf) => {
      gltf.name = '3dcar'
      gltf.position.x = 0
      gltf.position.z = 0
      gltf.position.y = 0
      container.add(gltf)
      gltf.scale.set(0.2, 0.2, 0.2)
      car = gltf
      scene.add(gltf)
    },
    // 加载进度回调
    (xhr) => {
      console.log(xhr, (xhr.loaded / xhr.total) * 100 + '% loaded')
    },
    // 加载失败回调
    (error) => {
      console.log('an error happened', error)
    }
    )
  })
}

5、关键函数,监听wsad实现移动

我们开始监听键盘按下,每次按下就调用我们的监听函数keyDownWalk,在函数里监听我们按下的是哪个键,对应来修改模型车car的位置信息position。

首先是wasd,这四个键控制我们的前进后退左右平移,我们的平面是在xz平面,所以只需要修改car 的xz值即可,方向的话,根据你定义的前进方向来做修改调整就行,加上三角函数只是让运动变得更加顺滑。

然后是qe,这里我们是要控制相机的lookat属性,我们都知道相机是有朝向的,这个lookat属性就是控制相机朝向的点位,这个点位会始终保持在相机画面的中间,那我们更新这个点位,不就是相当于控制了相机旋转吗?

更新完小车的位置后,我们通过set方法,将小车的位置更新给相机,同时设置偏移量。

同时通过lookAt和Vector3创建的三维变量设置下相机的朝向。

// 挂载到监听事件
window.addEventListener('keydown', function (e) {
  keyDownWalk(e)
})
let cameraLook = {
  x: 0,
  y: 0,
  z: -7
}
function keyDownWalk(e: { keyCode: any }) {
    let keyCode = e.keyCode;
    let position = car.position, rotation = car.rotation.y;
    switch (keyCode) {
        case 87:        //w
            position.z -= 0.02 * Math.cos(rotation);
            position.x -= 0.02 * Math.sin(-rotation);
            break;
        case 65:        //a
            position.z += 0.02 * Math.cos(rotation + Math.PI/2);
            position.x += 0.02 * Math.sin(-rotation - Math.PI/2);
            break;
        case 68:        //d
            position.z += 0.02 * Math.cos(rotation - Math.PI/2);
            position.x += 0.02 * Math.sin(-rotation + Math.PI/2);
            break;
        case 83:        //s
            position.z += 0.02 * Math.cos(rotation);
            position.x += 0.02 * Math.sin(-rotation);
            break;
        case 81:        //q
            cameraLook.x += 0.5 * Math.cos(rotation);
            cameraLook.z += 0.5 * Math.sin(-rotation);
            break;
        case 69:        //e
            cameraLook.x -= 0.5 * Math.cos(rotation);
            cameraLook.z += 0.5 * Math.sin(-rotation);
            break;
        default:
            break;
    }
    camera.position.set(car.position.x, car.position.y, car.position.z + 7)
    camera.lookAt(new THREE.Vector3(cameraLook.x, cameraLook.y, cameraLook.z))
}

6、效果

到这里我们就能基本完成一个控制流程,实现了wasd键控制小车移动,相机位置更新,qe键控制相机的朝向位置。

这里是实际效果图。

控制相机.gif

三、小结

总的来说,控制相机的方式有许多种,基本思路都是实时更新相机位置和相机朝向,常见的就是用模型的位置信息更新相机位置,充当一个第一或者第三人称视角。

ps: 我是地霊殿__三無

Snipaste_2022-07-19_15-30-26.jpg