在数字艺术的奇幻森林里,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 实现手势交互的方法。你对文章的内容深度、讲解方式是否满意?若有其他修改或补充需求,随时和我说。