持续创作,加速成长!这是我参与「掘金日新计划 · 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键控制相机的朝向位置。
这里是实际效果图。
三、小结
总的来说,控制相机的方式有许多种,基本思路都是实时更新相机位置和相机朝向,常见的就是用模型的位置信息更新相机位置,充当一个第一或者第三人称视角。
ps: 我是地霊殿__三無