Three.js 的魔法手势:让 3D 世界在指尖起舞

在数字艺术的奇幻森林里,Three.js 就是那位手持魔杖的魔法师,它能将枯燥的代码编织成令人惊叹的 3D 世界。不过,当这个虚拟世界只停留在屏幕上,像个高冷的艺术品,难免有些遗憾。别担心!今天我们要给 Three.js 的魔法书里添上关键一页 ------ 用手势交互打破次元壁,让用户能亲手触摸、旋转、缩放这个奇妙的 3D 世界。

一、Three.js 的底层魔法与交互困境

Three.js 的底层就像一个精密的魔法工厂,它利用 WebGL 技术直接与显卡对话,将顶点数据、纹理信息等原材料,通过一系列复杂的 "魔法咒语"(也就是数学变换和着色器渲染),快速组装成 3D 模型呈现在浏览器中。然而,在这个 3D 世界里,传统的鼠标点击和键盘操作就像隔着一层玻璃与世界互动,在移动端更是显得格格不入。想象一下,你捧着手机,却只能眼巴巴地看着精美的 3D 模型,无法像在现实中那样用手指摆弄它,是不是很憋屈?这时候,我们就需要引入 Hammer.js 这个 "交互小精灵",来解锁 Three.js 的手势交互新姿势。

二、召唤 Hammer.js 小精灵

Hammer.js 就像 Three.js 的得力助手,它能精准捕捉移动端的各种触摸手势,把用户手指的滑动、捏合等动作,翻译成 Three.js 能听懂的指令。

首先,我们要在项目中引入 Hammer.js。这就好比给我们的魔法团队招来新成员,在 HTML 文件里,通过

xml 复制代码
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>

或者如果你使用的是现代的前端构建工具,比如 npm,也可以用一句咒语把它召唤到项目里:

复制代码
npm install hammerjs

然后在 JavaScript 文件中引入:

javascript 复制代码
import Hammer from 'hammerjs';

三、给 3D 世界赋予手势魔法

接下来,我们要把 Hammer.js 和 Three.js 这两个魔法高手结合起来,给 3D 场景加上手势交互的超能力。

假设我们已经搭建好了一个简单的 Three.js 场景,有一个立方体在场景中:

ini 复制代码
// 创建场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建一个立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 设置相机位置
camera.position.z = 5;

现在,我们要给这个场景加上捏合缩放和滑动旋转的手势交互。

1. 滑动旋转:让模型跟着手指跳舞

我们先给场景绑定一个滑动手势事件,当用户在屏幕上滑动时,让立方体跟着旋转。这就好比给立方体系上一根无形的绳子,用户一拉绳子,它就开始旋转:

ini 复制代码
const hammertime = new Hammer(renderer.domElement);
hammertime.on('pan', function (ev) {
    cube.rotation.x += 0.01 * ev.deltaY;
    cube.rotation.y += 0.01 * ev.deltaX;
});

在这段代码里,我们首先创建了一个 Hammer 实例,并把 Three.js 渲染器的 DOM 元素作为参数传进去,这就相当于给 Hammer 划定了一个 "工作范围",让它只关注这个区域内的手势操作。然后,我们监听pan事件,也就是滑动事件。当用户滑动时,ev.deltaX和ev.deltaY分别记录了水平和垂直方向的滑动距离,我们根据这个距离,按一定比例(这里是 0.01)来更新立方体的旋转角度,这样立方体就会随着用户的滑动优雅地旋转起来。

2. 捏合缩放:像变魔术一样放大缩小

接下来是更神奇的捏合缩放功能。当用户用两根手指在屏幕上捏合或张开时,我们要让 3D 模型相应地缩小或放大,这就像在施展一个大小变化的魔法:

ini 复制代码
hammertime.on('pinch', function (ev) {
    const factor = ev.scale;
    cube.scale.x *= factor;
    cube.scale.y *= factor;
    cube.scale.z *= factor;
});

这里我们监听pinch事件,也就是捏合事件。ev.scale记录了捏合操作的缩放比例,当用户两根手指张开,这个值会大于 1,模型就会放大;当两根手指捏合,这个值会小于 1,模型就会缩小。我们把这个缩放比例分别应用到立方体的x、y、z三个轴向上,这样立方体就能像被施了魔法一样,随着手指的动作自由变换大小。

四、魔法升级:更丝滑的用户体验

为了让交互体验更加流畅自然,我们还可以对代码进行一些优化。比如,给旋转和缩放操作加上一些限制,避免模型旋转过度或者缩放到离谱的大小。我们也可以添加一些过渡动画,让模型的变化更加柔和,就像给魔法加上了特效:

ini 复制代码
// 限制旋转角度
const maxRotation = Math.PI;
hammertime.on('pan', function (ev) {
    const newRotationX = cube.rotation.x + 0.01 * ev.deltaY;
    const newRotationY = cube.rotation.y + 0.01 * ev.deltaX;
    cube.rotation.x = Math.max(-maxRotation, Math.min(maxRotation, newRotationX));
    cube.rotation.y = Math.max(-maxRotation, Math.min(maxRotation, newRotationY));
});
// 添加缩放过渡动画
let targetScale = cube.scale.clone();
const easingFactor = 0.1;
function updateScale() {
    cube.scale.x += (targetScale.x - cube.scale.x) * easingFactor;
    cube.scale.y += (targetScale.y - cube.scale.y) * easingFactor;
    cube.scale.z += (targetScale.z - cube.scale.z) * easingFactor;
    requestAnimationFrame(updateScale);
}
updateScale();
hammertime.on('pinch', function (ev) {
    const factor = ev.scale;
    targetScale.x *= factor;
    targetScale.y *= factor;
    targetScale.z *= factor;
});

在限制旋转角度的代码中,我们设定了一个最大旋转角度maxRotation,每次更新旋转角度时,都用Math.max和Math.min函数来确保旋转角度不会超出范围。在缩放过渡动画的代码中,我们引入了一个targetScale变量来记录目标缩放值,通过一个updateScale函数不断地让当前缩放值向目标缩放值靠近,每次靠近的幅度由easingFactor控制,这样模型的缩放就会变得平滑自然。

五、魔法的边界与未来

虽然我们已经成功给 Three.js 场景加上了炫酷的手势交互,但这只是魔法世界的冰山一角。在实际应用中,我们还会遇到各种挑战,比如不同设备的手势识别差异、复杂 3D 场景的性能优化等等。不过别担心,随着技术的不断发展,Three.js 和 Hammer.js 这些魔法工具也在不断升级,未来我们将能创造出更加逼真、流畅、有趣的 3D 交互体验,让用户真正沉浸在数字魔法的世界里。

现在,快去施展你的代码魔法,让 Three.js 的 3D 世界在用户的指尖上欢快起舞吧!

以上文章详细介绍了 Three.js 结合 Hammer.js 实现手势交互的方法。你对文章的内容深度、讲解方式是否满意?若有其他修改或补充需求,随时和我说。

相关推荐
崔庆才丨静觅12 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606113 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了13 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅13 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅13 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅14 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment14 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅14 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊14 小时前
jwt介绍
前端
爱敲代码的小鱼14 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax