原文参考我的公众号文章 threejs第X人称视角
3D世界,像机的位置和旋转情况决定了我们能看到什么,这篇文章主要讲讲如何简单的实现第一人称/第三人称视角跟随。
1.给物体添加跟随像机(Object3D)
原理
创建一个 Object3D
对象 - 「跟随像机」
,并把它添加到移动的物体上,这样「跟随像机」
的位置(position
)和旋转状态(quaternion
)就会跟着移动物体同步更新。
然后再实时把「跟随像机」
的位置和旋转状态应用到主camera上。
应用
键盘控制器或者 joyStick 控制器控制如:小车、人物角色在场景中移动、漫游!
实现如下
1.【跟随像机】的创建与位置初始化
let targetMesh = "PlayerMesh";
let slerpDamping = 0.01; //镜头变化动画速度
// 创建跟随像机
let followCamera = new THREE.Object3D();
// 初始化跟随像机位置
followCamera.position.copy(camera.position);
// 或者直接设定为要跟随的物体的位置 followCamera.position.copy(chassisBody.position);
followCamera.position.y = 6;
followCamera.position.z = 16;
// 添加跟随像机-方式1
// scene.add(followCamera);
// followCamera.parent = targetMesh;
// 添加跟随像机-方式2
targetMesh.add(followCamera);
2.【跟随像机】的更新
camera.position.lerp(
followCamera.getWorldPosition(new THREE.Vector3()),
slerpDamping
);
camera.quaternion.slerp(
followCamera.getWorldQuaternion(new THREE.Quaternion()),
slerpDamping
);
// 或者让camera看向targetMesh的位置
// camera.lookAt(targetMesh.position);
3.切换跟随模式:第一人称 or 第三人称
实现模式切换,只需要动态改变跟随像机的位置即可!
let view = "1"; // 当前模式
document.addEventListener("keyup", (e) => {
if (e.key == "c") {
onViewChangeCallback();
}
});
const onViewChangeCallback = () => {
if (view == "1") {
view = "3";
slerpDamping = 0.01;
followCamera.position.y = 6;
followCamera.position.z = 16;
}
if (view == "3") {
view = "1";
slerpDamping = 1;
followCamera.position.x = 0;
followCamera.position.y = 1.5;
followCamera.position.z = 1;
}
};
2.将主像机挂载到移动物体上
看代码注释,主要思路是让 camera 挂载到在被控制的对象上,与1类似。
class FollowCamera {
cameraControl = null; //像机控制器,让像机跟随
cameraTarget = null; //像机观测点
construct() {}
/**初始化像机控制器 */
setupCameraControl() {
this.cameraControl = new THREE.Object3D();
this.cameraControl.add(this.camera);
this.cameraTarget = new THREE.Vector3(0, 0, 6);
this.scene.add(this.cameraControl);
}
/**让物体和相机保持相对位置 */
updateCameraControl() {
if (this.cameraControl && this.cameraTarget) {
//将像机控制器移动到物体的位置
this.cameraControl.position.copy(this.playerMesh.position);
//将像机控制器放在Y轴0的位置,因为物体会上上下下
this.cameraControl.position.y = 0;
//把控制器的观测目标点移动到物体的位置
this.cameraTarget.copy(this.playerMesh.position);
//再把把控制器的观测目标点沿着Z轴移动6米,总是保持在物体前6米的位置
this.cameraTarget.z += 6; //保持注视着物体的前6米处(保持相对位置)
//像机观测着控制器的观测目标点
this.camera.lookAt(this.cameraTarget);
}
}
handlePlayerMove(elapsedTime) {
this.playerMesh.rotation.set(0, 0, Math.sin(elapsedTime) * 0.5, "XYZ");
if (!this.isActive) {
this.playerMesh.position.y = Math.cos(elapsedTime) * 0.3; //待机时的动画
} else {
this.playerMesh.position.z -= 0.02 * elapsedTime; //前进
if (this.isSpace) {
this.playerMesh.position.y += 0.01; //攀升
} else {
this.playerMesh.position.y -= 0.01; //坠落
}
}
}
annimate(elapsedTime, deltaTime) {
if (this.playerMesh) {
this.handlePlayerMove(elapsedTime);
this.updateCameraControl();
}
}
}
3.像机与物体相对静止
仅处理像机位置变化,根据不同场景使用。物体移动的底层原理就是做矩阵变化,那么想要让相机和物体的距离不变,我们只需要让相机和物体做相同的变化。
const animate = () => {
const relativeCameraOffset = new THREE.Vector3(0, 5, 10);
const cameraOffset = relativeCameraOffset.applyMatrix4(
playerMesh.matrixWorld
);
// 更新像机位置
camera.position.copy(cameraOffset);
// 始终让相机看向物体
controls.target = playerMesh.position;
};
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。