项目地址:https://github.com/MoonPointer-Byte/AnswerBook/

🔮 前言

在 Web 交互日益同质化的今天,如何打破“鼠标点击”的传统范式?

最近我尝试将 3D 图形学 (Three.js) 与 计算机视觉 (Google MediaPipe) 结合,开发了一个极具沉浸感的互动项目——《全知之书 (The Omniscient Tome)》

在这个项目中,用户无需触碰键盘鼠标,只需对着摄像头挥挥手,就能在虚空中浏览一座宏大的魔法图书馆,选中并翻阅古老的典籍,获取随机的命运神谕。

先看效果图:

隔空手势翻阅 3D 魔法书


✨ 核心功能与亮点

  1. 🧙‍♂️ 零接触 AI 交互:基于 MediaPipe 的手部骨骼追踪,识别单手(浏览)、双手(开启)、握拳(重置)三种手势。

  2. 📚 程序化纹理 (Procedural Textures):项目中所有的书籍封面、皮革纹理、烫金边框、内页文字,全部通过 Canvas API 动态生成,无需加载任何外部图片资源,不仅加载快,而且每一本书都是独一无二的。

  3. 📖 拟真物理翻页:摒弃简单的贴图替换,构建了包含封面、封底、书脊的完整 3D 结构,实现了绕书脊轴心的物理翻页动画。

  4. 🌟 电影级后处理:使用了 UnrealBloom (泛光) 滤镜,配合粒子系统和动态点光源,营造出神秘的魔法氛围。


🛠️ 技术栈


💻 核心实现原理解析

1. 3D 书籍的建模与“关节”设计

要实现书本自然的“翻开”效果,不能简单地旋转整个物体。我将书本拆分为三个部分,并建立父子层级:

  • Root (根节点): 控制整本书的位置和整体旋转。

  • Spine (书脊): 固定在 Root 上。

  • BackGroup (封底组): 包含封底和右侧书页,固定在 Root 上。

  • FrontGroup (封面组)关键点! 包含封面和左侧书页。它的旋转轴心设置在书脊处。

codeJavaScript

// 简化的建模逻辑
const root = new THREE.Group();

// 封面组 (这是可以活动的关节)
const frontGroup = new THREE.Group();
// 将封面几何体向右偏移,使其旋转轴心位于左侧边缘(书脊处)
const frontCover = new THREE.Mesh(coverGeo, matCover);
frontCover.position.set(B_W/2, 0, P_T/2 + B_T/2); 
frontGroup.add(frontCover);

// 初始状态:合上 (旋转 -PI)
frontGroup.rotation.y = -Math.PI; 

root.add(frontGroup);
root.add(backGroup); // 封底是固定的

当触发“开启”状态时,使用 GSAP 将 frontGroup.rotation.y 从 -Math.PI (合上) 动画过渡到 0 (摊平),就实现了翻书效果。

2. Canvas 动态纹理与中文书法

为了让每一本书翻开时都有不同的“神谕”,并没有预先准备几十张图片,而是利用 CanvasTexture 实时绘制。

这里利用了 Canvas 的绘图能力来模拟羊皮纸质感发光文字

codeJavaScript

function drawInnerPage(canvas, text) {
    const ctx = canvas.getContext('2d');
    const w = canvas.width, h = canvas.height;
    
    // 1. 绘制发光底色 (配合 Bloom 滤镜)
    ctx.fillStyle = "#ffffff"; 
    ctx.fillRect(0,0,w,h);
    
    // 2. 绘制古风中文文字
    if (text) {
        ctx.fillStyle = "#221100"; // 深墨色
        ctx.font = "300px 'Ma Shan Zheng', cursive"; // 书法字体
        ctx.textAlign = "center"; 
        ctx.textBaseline = "middle";
        ctx.fillText(text, w/2, h/2);
    }
}

// 在翻书时动态更新纹理
const pageTex = book.userData.pageMat.map;
drawInnerPage(pageTex.image, "机缘"); 
pageTex.needsUpdate = true; // 告诉 Three.js 纹理已更新

3. MediaPipe 手势状态机

交互逻辑使用了一个简单的状态机来管理,防止手势冲突。

  • IDLE (待机): 寻找手部信号。

  • MOVE (浏览): 单手张开。映射手掌 X 轴坐标到 Scroll 速度。

  • CHARGING (蓄力): 双手张开。计算蓄力进度条,触发 Bloom 增强。

  • REVEALED (揭晓): 书籍打开状态。

  • SHUFFLE (重置): 检测到握拳(Fist),拥有最高优先级,强制重置所有状态。

codeJavaScript

// 手势识别核心逻辑
if (fistHands > 0) {
    input.mode = 'SHUFFLE'; // 握拳优先级最高
} else if (openHands === 2) {
    input.mode = 'ACTIVATE'; // 双手开启
} else if (openHands === 1) {
    input.mode = 'MOVE';     // 单手移动
}

// 状态机处理
if (input.mode === 'SHUFFLE') {
    resetGame();
} else if (input.mode === 'MOVE') {
    // 平滑滚动逻辑
    scrollTarget -= (input.x - 0.5) * speed;
}

🎨 视觉美化:Bloom 与 粒子

为了达到“魔法”效果,后处理(Post-processing)是必不可少的。

使用了 UnrealBloomPass,但调整了 threshold (阈值),确保只有书本的金色边框、魔法阵和翻开后的白纸会发光,而背景保持深邃的黑。

同时,配合一个简单的粒子系统(Explosion Particles),在书本翻开的瞬间释放粒子,增加冲击力。

如何在本地运行?

  1. 克隆项目到本地。

  2. 由于涉及摄像头权限和纹理加载,不能直接双击 HTML 打开

  3. 推荐使用 VS Code 安装 Live Server 插件,右键 Open with Live Server。

  4. 或者使用 Node.js: npx http-server。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐