[特殊字符]The Omniscient Tome | 全知之书

项目地址: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。

相关推荐
OpsEye42 分钟前
怎么实现大模型的按用户、按应用配额限流?
javascript·ai编程
林恒smileZAZ44 分钟前
浏览器为什么加载不了超大图片
前端·vue.js·html5
云舜言传1 小时前
Bloom 手势演示操作 · 录屏指南
javascript·深度学习·机器学习
Highcharts.js5 小时前
BI可视化图表“维护难”问题的解决方案
开发语言·前端·javascript·编辑器·ecmascript·bi·highcharts
倚窗听花_5 小时前
IIS部署前端Vue项目
前端·javascript·vue.js
yixun_gdas5 小时前
政企网站错敏巡查:错敏都藏在哪些位置?
开发语言·前端·javascript·内容运营
小羊没烦恼!5 小时前
.NET 11 Runtime Async 详解
java·运维·开发语言·javascript·python
java1234_小锋6 小时前
【技术专题】HTML5 网页技术 - HTML5 SVG
前端·html·html5
飞飞鱼在摸鱼6 小时前
前端转Agent开发 | JavaScript 从 0 到 1 完全指南
前端·javascript
Suprman7 小时前
从 B/S 到 Electron:平面排版套料系统桌面版开发实战
javascript·平面·electron·排序算法