本技能针对 Three.js 中的数学计算,主张优先使用引擎自带数学类,而不是手写三角函数或自定义实现,因为这些类经过充分测试、能处理边界情况,并与 Three.js 对象无缝协作。文档强调贯穿始终的参考系问题,即世界空间与局部空间的区别,即使使用内置类,忽略参考系也会出错。
用途
该文档用于指导在 Three.js 项目中正确处理球面坐标、旋转、朝向相机的广告牌以及对象尺寸测量,减少因角度计算、旋转表示选择和空间变换导致的错误。
主要能力
一、球面坐标与三角函数。涉及 sin/cos 的场景应改用 Euler、Vector3 和 Quaternion。例如轨道位置可构造 Spherical 并读入向量;由累积角度得到方向时,可构造 Euler 并应用到前向向量。文档给出示例:用 Spherical(radius, polarAngle, azimuthalAngle) 设置位置;用 Euler(pitch, yaw, 0, 'YXZ') 对 Vector3(0, 0, -1) 应用后得到方向。
二、旋转。旋转表示按用途选择:轨道相机和 FPS 相机适合用 Euler 的 YXZ 顺序,使 pitch 与 yaw 分别累积;通用旋转、插值(slerp)以及避免万向锁时使用 Quaternion。在两种表示之间转换时需注意 Euler 顺序,尽量保持单一表示以减少错误。Three.js 对象同时暴露 .rotation(Euler)和 .quaternion(Quaternion),并自动保持同步。
三、广告牌。用于标签、血条、图标等面向相机的四边形必须在世界空间定向。若它是旋转对象(如敌人、炮塔)的子对象,把相机朝向复制到其局部旋转上是错误的,因为父级的世界旋转仍会叠加,导致四边形随父级倾斜旋转,这是血条旋转错误的常见原因。文档给出两种修正:方案 A,在世界空间定向并补偿父级世界旋转,示例中先复制相机四元数作为期望世界旋转,再取父级世界四元数的逆并左乘;方案 B,更简单,不把标签挂到移动对象下,而是直接放入世界空间并设置位置与相机四元数。此外 THREE.Sprite 始终自动面向相机,可完全避开该问题,适合简单血条和图标。
四、测量对象尺寸。new Box3().setFromObject(object) 对静态网格正确,但对蒙皮、绑定或动画对象(如角色)会不稳定且错误:它会合并所有后代,包括远离身体的骨骼以及角色系统保留的引用或克隆子对象;同时它按绑定姿态几何体扩展,包围盒会随动画每帧变化。错误结果常达到可见身体高度的 2–3 倍甚至更多,并悄悄破坏依赖该数值的功能。文档举出典型故障:把一个角色缩放到与另一个角色测得的高度一致时,因被测角色正在动画而膨胀、另一个是干净测量,结果得到巨大角色。文档给出三种正确做法:读取 SkinnedMesh 的 geometry.boundingBox(稳定绑定姿态范围,需先 computeBoundingBox),注意该盒位于局部几何空间,要得到世界单位高度需用 mesh.matrixWorld 变换,从而计入父节点缩放(glTF 导入缩放通常在这里),直接读取或只乘 mesh.scale 都会测错;在模型加载时、绑定动画或包装之前测量原始模型一次;避免测量,改用已知常量作为目标角色高度。文档最后提醒,不要每帧对活动角色调用 setFromObject 并信任其高度。
使用方式
在编写涉及坐标、旋转、朝向和尺寸的 Three.js 代码时,按上述原则选择内置类和表示方式,并参考文档中的示例代码片段进行改写。
适用场景
适用于 Three.js 游戏或交互式 3D 项目中处理轨道相机、第一人称相机、对象朝向、广告牌 UI(血条、标签、图标)以及角色尺寸测量等任务。
限制
文档为技能说明,未提供安装命令、收费信息或具体运行环境要求;所述正确性依赖 Three.js 的对应 API 行为。