在 Three.js 的 3D 世界里,相机就像是我们的 "电子眼睛",决定着观众能看到怎样的奇幻景观。不过,默认的相机行为有时就像个 "愣头青",移动生硬、缺乏灵性。今天,咱们就化身 "相机驯兽师",编写自定义相机脚本,让它实现平滑过渡、限制运动范围,还能根据用户输入来一场华丽的动态表演!
一、相机基础知识:先摸清 "电子眼睛" 的脾气
在 Three.js 的舞台背后,相机分为正交相机(OrthographicCamera)和透视相机(PerspectiveCamera)。透视相机就像我们人类的眼睛,遵循近大远小的视觉规律,能营造出逼真的 3D 空间感;而正交相机则像工程图纸里的 "铁面无私者",无论远近,物体大小始终如一。
我们最常用的透视相机,它的创建就像组装一台精密的光学仪器:
dart
// 创建一个透视相机,视角75度,宽高比,近裁切面,远裁切面
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 将相机放置在初始位置
camera.position.set(0, 5, 10);
这里的视角、宽高比、近裁切面和远裁切面参数,就像是给相机设定的 "视力范围" 和 "观察规矩"。
二、实现平滑过渡:给相机装上 "丝滑轮滑"
默认的相机移动,就像突然急刹车又猛踩油门,让人头晕目眩。要实现平滑过渡,我们得给相机添加一个 "缓动系统",就像给它的 "脚步" 加上润滑油。
我们借助Tween.js库来实现这一效果。首先引入Tween.js,然后编写代码:
php
// 引入Tween.js库
import * as TWEEN from '@tweenjs/tween.js';
// 定义目标位置
const targetPosition = new THREE.Vector3(5, 5, 15);
// 创建缓动动画
const tween = new TWEEN.Tween(camera.position)
.to({ x: targetPosition.x, y: targetPosition.y, z: targetPosition.z }, 1000) // 1000毫秒内过渡到目标位置
.easing(TWEEN.Easing.Quadratic.InOut) // 使用二次方缓动函数
.start();
// 在动画循环中更新Tween
function animate() {
requestAnimationFrame(animate);
TWEEN.update();
renderer.render(scene, camera);
}
animate();
这段代码就像是给相机制定了一个优雅的 "移动计划表",让它在 1 秒内,以二次方缓动的优雅姿态,从当前位置滑向目标位置,整个过程丝滑流畅。
三、限制运动范围:给相机划定 "活动禁区"
有时候,我们不希望相机 "乱跑",比如在一个虚拟房间内,不能让它穿墙而出。这时候,我们就得给相机划定 "活动禁区",用数学的方式(虽然不用公式,但原理类似)来限制它的位置。
ini
// 定义相机运动范围
const minX = -10;
const maxX = 10;
const minY = 0;
const maxY = 20;
const minZ = 5;
const maxZ = 25;
// 在相机移动后检查并限制位置
function checkAndLimitCameraPosition() {
if (camera.position.x < minX) {
camera.position.x = minX;
} else if (camera.position.x > maxX) {
camera.position.x = maxX;
}
if (camera.position.y < minY) {
camera.position.y = minY;
} else if (camera.position.y > maxY) {
camera.position.y = maxY;
}
if (camera.position.z < minZ) {
camera.position.z = minZ;
} else if (camera.position.z > maxZ) {
camera.position.z = maxZ;
}
}
// 在动画循环中调用检查函数
function animate() {
requestAnimationFrame(animate);
// 假设这里有其他相机移动逻辑
checkAndLimitCameraPosition();
renderer.render(scene, camera);
}
animate();
这段代码就像给相机戴上了 "电子围栏",一旦它想要越界,就会被强制拉回到规定的范围内,保证它始终在我们设定的 "舞台" 上活动。
四、基于用户输入的动态变化:让相机听懂 "指挥"
为了让相机更 "智能",能根据用户的操作做出反应,我们需要监听用户输入事件,比如键盘按键、鼠标移动等。
1. 监听键盘按键控制相机移动
ini
// 记录键盘按键状态
const keys = {
w: false,
a: false,
s: false,
d: false
};
// 监听键盘按下事件
document.addEventListener('keydown', function (event) {
if (event.key === 'w') {
keys.w = true;
} else if (event.key === 'a') {
keys.a = true;
} else if (event.key ==='s') {
keys.s = true;
} else if (event.key === 'd') {
keys.d = true;
}
});
// 监听键盘松开事件
document.addEventListener('keyup', function (event) {
if (event.key === 'w') {
keys.w = false;
} else if (event.key === 'a') {
keys.a = false;
} else if (event.key ==='s') {
keys.s = false;
} else if (event.key === 'd') {
keys.d = false;
}
});
// 在动画循环中根据按键状态移动相机
function animate() {
requestAnimationFrame(animate);
const speed = 0.1;
if (keys.w) {
camera.position.z -= speed;
}
if (keys.s) {
camera.position.z += speed;
}
if (keys.a) {
camera.position.x -= speed;
}
if (keys.d) {
camera.position.x += speed;
}
renderer.render(scene, camera);
}
animate();
这段代码赋予了相机 "听指令" 的能力,当我们按下键盘上的 W、A、S、D 键时,相机就会按照我们的指示移动,就像一个听话的 "小跟班"。
2. 监听鼠标移动控制相机旋转
ini
let mouseX = 0;
let mouseY = 0;
const windowHalfX = window.innerWidth / 2;
const windowHalfY = window.innerHeight / 2;
// 监听鼠标移动事件
document.addEventListener('mousemove', function (event) {
mouseX = (event.clientX - windowHalfX);
mouseY = (event.clientY - windowHalfY);
});
// 在动画循环中根据鼠标位置旋转相机
function animate() {
requestAnimationFrame(animate);
const rotateSpeed = 0.001;
camera.rotation.y += (mouseX * rotateSpeed);
camera.rotation.x -= (mouseY * rotateSpeed);
// 限制相机的俯仰角度,避免"倒立"
camera.rotation.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, camera.rotation.x));
renderer.render(scene, camera);
}
animate();
有了这段代码,我们的鼠标就成了控制相机的 "方向盘",轻轻移动鼠标,相机就会跟着旋转视角,让我们可以全方位欣赏 3D 世界的美景,同时限制俯仰角度,保证画面始终 "端正"。
五、总结与展望
通过编写自定义相机脚本,我们让 Three.js 中的相机从 "呆板" 变得 "灵动"。从平滑过渡的优雅舞步,到限制运动范围的 "守规矩",再到基于用户输入的 "智能互动",每一步都像是在给相机注入新的 "灵魂"。
未来,我们还可以进一步探索更多有趣的功能,比如结合物理引擎让相机的移动更符合现实规律,或者根据场景氛围自动调整相机的参数。快拿起代码,开启属于你的 Three.js 相机定制之旅吧,让 3D 世界的视角变得独一无二!
上述内容从多方面讲解了 Three.js 自定义相机脚本。你若觉得某些部分需要补充,或有新的功能需求,欢迎随时和我说。