篇章 5:Three.js 互动派对——让模型听你指挥

289 阅读8分钟

🎬 开场白

上次的蹦迪派对是不是还没嗨够?💃🕺

立方体在旋转跳跃,机器人在展示着机械舞步……但你有没有觉得少了点什么?🤔   对!少了你这位指挥家🎩。  

想象一下,如果舞台上这些模型不再是“自顾自”地表演,而是能听从你的指挥:  

  • 你用鼠标轻轻一推,镜头就跟着舞动🎥  
  • 你按下键盘,舞者就立刻走位换阵👣  
  • 你拉动一个滑块,舞台灯光颜色瞬间切换🔘
  • 甚至音乐一起,舞台和角色立刻跟着节奏燃爆全场🔥  

这一次,你不只是观众,而是 整场派对的 DJ + 灯光师 + 舞蹈总监。  

欢迎来到 Three.js 互动派对,在这里,模型们会乖乖听你指挥,舞台由你掌控🎛️!

🗺️先认识几种常见“坐标语言”

在 3D 世界里,我们会遇到好几种“坐标语言”,学会它们,就像掌握了不同国家的手势翻译,鼠标、模型和相机才能愉快交流:

坐标类型范围/形式使用场景通俗理解
世界坐标(World Coordinates)x, y, z ∈ 无界或场景边界放置模型、场景布局就像你在自家客厅里摆家具:沙发在左、茶几在中间、电视靠右,不管你站哪儿,家具位置不变
相机/视图坐标(Camera/View Coordinates)相机为原点,z向前摄像机观察物体、裁剪视锥就像戴上相机眼镜看世界,所有东西都相对于你眼睛位置,前面的东西 z>0,左边右边都有 x,y
裁剪坐标(Clip Coordinates)-1 ≤ x,y,z ≤ 1(透视除法前)GPU 裁剪、投影计算就像把世界压进一个立方体盒子里,超出盒子的都被裁掉,不管原来多大
归一化设备坐标(NDC)-1 ≤ x,y,z ≤ 1(透视除法后)方便 GPU 映射到屏幕世界被拉成 [-1,1] 的标准尺寸,像把不同大小的水果都切成同一大小的方块,方便统一处理
屏幕/像素坐标(Screen Coordinates)x ∈ [0, 屏幕宽], y ∈ [0, 屏幕高]UI、鼠标点击、2D 渲染最直观的:你的鼠标点了屏幕左上角(0,0),右下角(屏宽,屏高),完全跟显示器坐标挂钩
DOM 坐标 / 客户端坐标(clientX, clientY)x ∈ [0, 可视窗口宽], y ∈ [0, 可视窗口高]Web 鼠标事件、拖拽就像在浏览器窗口里玩“找茬游戏”,坐标相对于浏览器窗口,不管滚动条怎么动

透视除法(Perspective Divide)

基本概念

透视除法是将 裁剪坐标(Clip Coordinates) 转换为 归一化设备坐标(NDC) 的关键步骤。

公式

NDCx = clipX / clipW
NDCy = clipY / clipW
NDCz = clipZ / clipW

clipX, clipY, clipZ, clipW:裁剪坐标(4D 齐次坐标)
透视除法就是把裁剪坐标除以 W,得到最终的屏幕坐标(NDC),范围在 [-1, 1]。 为什么要除以 WW可以理解成“离相机的距离”。

  • 离相机越远,W 越大 → 除以 W 后,坐标会变小 → 在屏幕上看起来更远、更小
  • 离相机越近,W 越小 → 除以 W 后,坐标会变大 → 在屏幕上看起来更近、更大

举例说明

假设有两个物体在相机前:  

  • 物体 A 离相机近,裁剪坐标:clipX = 2, clipY = 1, clipZ = 5, clipW = 5  
  • 物体 B 离相机远,裁剪坐标:clipX = 4, clipY = 2, clipZ = 20, clipW = 20
// A 的 NDC 坐标:
ndcX = clipX / clipW = 2 / 5 = 0.4
ndcY = clipY / clipW = 1 / 5 = 0.2
// B 的 NDC 坐标:
ndcX = clipX / clipW = 4 / 20 = 0.2
ndcY = clipY / clipW = 2 / 20 = 0.1

注意:clipZ 也会除以 clipW 得到 ndcZ,但是 ndcZ 不用来画在屏幕上,而是用作深度比较(Z-buffer)来判断遮挡关系。
通俗理解:
X、Y 控制“你看到的画面位置”,所以要受透视影响
Z 控制“谁在前谁在后”,屏幕上你看不到 Z 的变化,只用来判断深度

归一化设备坐标(NDC)的作用总结

作用通俗解释计算方法
统一坐标系不管屏幕大小、分辨率多少,所有坐标都缩放到 [-1,1],方便计算 📏NDCx = (2*screenX / screenWidth) - 1
NDCy = 1 - (2*screenY / screenHeight)
可见性判断在 [-1,1] 里的会显示,超出就裁掉,就像舞台聚光灯圈内才是主角 💡NDC 坐标超出 [-1,1] → 被裁剪掉
交互桥梁鼠标/触摸屏坐标必须转成 NDC 才能和 3D 世界对话,否则两边鸡同鸭讲 🐔🦆NDCx = (2*screenX / screenWidth) - 1
NDCy = 1 - (2*screenY / screenHeight)
设备无关不管是 4K 屏、1080P 还是 VR 眼镜,NDC 都一样,超强通用性 🌍NDC 范围固定 [-1,1],和设备分辨率无关

举例说明

  • 屏幕尺寸:screenWidth = 1920pxscreenHeight = 1080px
  • 鼠标位置:screenX = 960pxscreenY = 540px(屏幕中心)

公式

NDCx = (2 * screenX / screenWidth) - 1
NDCy = 1 - (2 * screenY / screenHeight)

计算过程

屏幕坐标 (screenX, screenY)计算公式NDC 结果 (NDCx, NDCy)
(960, 540) 中心点NDCx = (2x960/1920)-1 = 0
NDCy = 1-(2*540/1080)=0
(0, 0)
(0, 0) 左上角NDCx = (2x0/1920)-1 = -1
NDCy = 1-(2x0/1080)=1
(-1, 1)
(1920, 1080) 右下角NDCx = (2x1920/1920)-1 = 1
NDCy = 1-(2x1080/1080)=-1
(1, -1)

小幽默记忆

屏幕左上角是舞台左边 -1,上面 +1;右下角是舞台右边 +1,下面 -1。中心点就是舞台正中央 0,0 🎭

🎥 鼠标控制:让镜头跟随你的手势

分类重点 / 难点文案解读
基础概念鼠标坐标转换鼠标在屏幕上动,模型得听懂你说的“向左走”“向右飘”,坐标转换就是翻译官 🕵️‍♂️
相机旋转与位置控制镜头不是定格摄影,要跟着你甩鼠标转圈圈,别让小球跑丢了!🎡
事件监听mousemove / mousedown / mouseup给鼠标装上耳朵,点下、拖动、松开都能被捕捉 👂
阻止默认事件 (preventDefault)不让浏览器耍小聪明,滚轮滚屏幕也能被你掌控 💪
平滑动画使用 requestAnimationFrame 做插值镜头不能一顿抖,像跳舞一样顺滑,别像踩到香蕉皮滑倒 🍌
阻尼(damping)给镜头加点惯性,甩一下鼠标,镜头慢慢跟上,好像滑雪 🏂
工具库OrbitControls / PointerLockControls有现成神器可以用,别非得自己搬砖,少点心累,多点快乐 🛠️
常见难点坐标系和角度容易搞混三维世界和屏幕世界差别大,小心别让镜头绕到背后 😵
鼠标速率太快或太慢太快像坐过山车,太慢像乌龟漫步,要找个黄金平衡 ⚖️

👣 键盘操作:舞者走位换阵

键盘就像舞台上的脚步控制器:  

  • W/A/S/D → 前后左右移动,让你的角色在场景中穿梭  
  • Q/E 或 Shift/Ctrl → 快速旋转、蹲下或加速,让动作更灵活
  • 空格键 → 跳跃或腾空,就像舞者腾起换位置  

🔘 滑块交互:实时调灯光

想象一下舞台表演 🎤:  

有灯光师在控制台前,手里推来推去的推子(滑块)。  

他一推,舞台上的光就变亮;一拉,光又变暗。  

换个颜色,舞台氛围瞬间就从“浪漫小夜曲”变成了“摇滚现场”。⚡  

在 Three.js 里,我们就能通过 滑块 (Slider) 来实现类似的效果:  

  • 🔆 强度滑块 → 灯光亮度,拉满就是“聚光灯打爆全场”,拉低就是“柔光小夜灯”。
  • 🎨 颜色滑块 → 灯光颜色,滑一滑,舞台从冷色变暖色,好像切换场景。  
  • 📍 位置滑块 → 灯光位置,像移动天花板上的灯,让舞者“被 spotlight 追随”。

💡 滑块分类与效果

滑块类型      控制参数      场景效果示例
强度滑块 🔆   light.intensity调整光亮度,拉高 → 聚光灯,拉低 → 柔光
颜色滑块 🎨   light.color    改变灯光颜色,冷色 → 暖色,瞬间切换场景氛围
位置滑块 📍   light.position 移动灯光位置,让光束追随舞者或固定某个点

🎶 音乐驱动:让模型随节奏舞动

想象一下夜店或者舞台 🎵:

DJ 手里抓着唱盘,音乐一响,节奏一到,舞台上的舞者就跟着节拍动起来:

  • 低音震动 → 舞者脚下轻轻跳动  
  • 高音旋律 → 手臂优雅摆动  
  • 鼓点猛烈 → 全身大幅律动,观众跟着嗨  

在 Three.js 里,我们可以让 模型跟随音乐节奏跳舞

  • 🔊 音频分析 (Audio Analysis): 使用 AudioContextTHREE.AudioAnalyser 获取音频频谱  
  • 📈 频谱数据映射到动作: 将高低音、鼓点映射到模型的不同关节或位置  
  • 💃 实时更新模型: 每一帧根据音量、节奏调整模型的旋转、位移或缩放,让舞者仿佛“活”起来

Filmage 2025-08-25_165559.gif

🌟 结尾

恭喜你!🎉 舞台上的灯光、音乐、镜头、舞者,终于不再是“各跳各的”,而是乖乖听从你这位指挥家的号令了。现在的你,已经不仅仅是“动画大师”,更是集 DJ + 灯光师 + 摄影师 + 编舞师 于一身的超级舞台导演。🎩✨

不过……舞台氛围是不是还少了点“魔法味”?🤔
别急,第六章我们就要请出压轴好戏:

✨ 粒子烟花、流光残影、Shader 魔法 ✨
让舞台直接从“蹦迪广场”升级到“国际演唱会现场”!🔥