Three.js 自定义相机脚本:让镜头舞动起来

在 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 自定义相机脚本。你若觉得某些部分需要补充,或有新的功能需求,欢迎随时和我说。

相关推荐
WeiXiao_Hyy17 分钟前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡34 分钟前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone39 分钟前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09011 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king2 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳2 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵3 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星3 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_3 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js