关于 threejs-core-math
threejs-core-math 是面向 Three.js 开发者的数学 API 参考技能,涵盖核心类、变换、插值、坐标约定及常见问题。
主要功能
- 01向量与矩阵 API 参考
- 02Quaternion 与 Euler 旋转指南
- 03颜色和 MathUtils 操作
- 04包围体查询
- 05坐标与对象变更注意事项
适用场景
- 01实现对象变换
- 02制作平滑旋转动画
- 03检查相交与边界
- 04避免常见数学错误
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ impertio-studio/ three.js-claude-skill-package --skill threejs-core-math安装后在 Claude Code 中输入/threejs-core-math确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.gitkeepreferences/anti-patterns.mdexamples.mdmethods.md详细介绍
threejs-core-math
快速参考
坐标系
Three.js 使用右手坐标系,Y 轴朝上:
| 轴 | 方向 | 说明 |
|---|---|---|
| X | 向右 | 正方向朝屏幕右侧 |
| Y | 向上 | 正方向朝天花板 |
| Z | 朝向观察者 | 正方向从屏幕向外 |
导入转换规则:
| 来源 | 坐标约定 | 转换方式 |
|---|---|---|
| Blender | Z 轴朝上 | glTF 导出器会自动转换 |
| FBX | Z 轴朝上 | FBXLoader 会自动转换 |
| OBJ | 无标准 | 加载后务必检查方向 |
| IFC | Z 轴朝上 | 务必应用绕 X 轴旋转 -90 度,或使用可转换坐标的加载器 |
切勿假设导入的模型符合 Three.js 的坐标约定——加载后务必检查方向。
核心数学类
| 类 | 用途 | 标识值/默认值 |
|---|---|---|
Vector3 | 位置、方向、缩放 | (0, 0, 0) |
Vector2 | UV 坐标、2D 位置 | (0, 0) |
Vector4 | 齐次坐标、着色器数据 | (0, 0, 0, 0) |
Matrix4 | 4x4 变换矩阵 | 单位矩阵 |
Quaternion | 避免万向节锁的旋转表示 | (0, 0, 0, 1) |
Euler | 易读的旋转角度 | (0, 0, 0, 'XYZ') |
Color | RGB 颜色(范围为 0-1) | (1, 1, 1) 白色 |
Box3 | 轴对齐包围盒 | 空(最小值为 +Inf,最大值为 -Inf) |
Sphere | 包围球 | 球心在原点,半径为 -1 |
Plane | 无限平面 | 法线 (1,0,0),常数为 0 |
Ray | 原点 + 方向 | 原点 (0,0,0),方向 (0,0,-1) |
Frustum | 由 6 个平面组成的视锥体 | -- |
重要警告
切勿修改多个对象共享的 Vector3/Matrix4/Quaternion——大多数方法都会原地修改对象。修改共享实例前务必使用 .clone()。
// WRONG: mutates the shared vector
const offset = new Vector3(1, 0, 0);
meshA.position.add(offset);
meshB.position.add(offset); // offset is still (1, 0, 0) BUT if you
// had stored meshA.position somewhere,
// it would be mutated
// CORRECT: clone before mutation
const pos = sharedPosition.clone().add(offset);
切勿直接插值 Euler 角度——这会产生错误的旋转路径并触发万向节锁。务必先转换为 Quaternion,使用 slerp(),需要时再转换回来。
除非理解四元数数学,否则切勿手动设置 Quaternion 的 x、y、z、w 值。务必使用 setFromAxisAngle()、setFromEuler() 或 slerp()。
切勿使用 lerp() 为 Color 创建色相变化动画——这会产生浑浊的中间色。要在不同色相之间过渡,务必使用 lerpHSL()。
当 Three.js 要求使用弧度时,务必使用 MathUtils.degToRad()——所有旋转方法都使用弧度,而不是角度。
Vector3
使用最广泛的数学类。所有会修改对象的方法都会返回 this,以便链式调用。
算术: add(v)、addScalar(s)、sub(v)、multiply(v)、multiplyScalar(s)、divide(v)、divideScalar(s)、negate()
几何: dot(v): number、cross(v)、length(): number、lengthSq(): number、normalize()、setLength(l)、reflect(normal)、project(camera)、unproject(camera)
距离: distanceTo(v): number、distanceToSquared(v): number、manhattanDistanceTo(v): number
插值: lerp(v, alpha)、lerpVectors(v1, v2, t)、clamp(min, max)、clampLength(min, max)
变换: applyMatrix4(m)、applyQuaternion(q)、applyAxisAngle(axis, angle)、applyEuler(euler)
转换: setFromMatrixPosition(m)、setFromMatrixScale(m)、setFromSphericalCoords(r, phi, theta)、toArray(arr?, offset?)、fromArray(arr, offset?)
赋值: set(x, y, z)、copy(v)、clone()、equals(v): boolean
Vector2 的不同之处:只有 x、y。没有 cross()(cross(v): number 会返回标量)。不支持 3D 变换。
Vector4 的不同之处:具有 x、y、z、w。用于齐次坐标和着色器 uniform。
Matrix4
按列存储(WebGL 约定)。elements 数组中包含 16 个浮点数:
elements[0] elements[4] elements[8] elements[12] // Translation = [12,13,14]
elements[1] elements[5] elements[9] elements[13]
elements[2] elements[6] elements[10] elements[14]
elements[3] elements[7] elements[11] elements[15]
组合: compose(position, quaternion, scale) / decompose(position, quaternion, scale)——标准的 TRS(平移-旋转-缩放)模式。
乘法顺序: 从右到左。M1.multiply(M2) 表示先应用 M2,再应用 M1。使用 premultiply(m) 执行左乘(this = m * this)。
工厂方法: makeTranslation(x,y,z)、makeScale(x,y,z)、makeRotationX(theta)、makeRotationY(theta)、makeRotationZ(theta)、makeRotationAxis(axis, angle)、lookAt(eye, target, up)
操作: invert()、transpose()、determinant(): number、identity()、extractBasis(x, y, z)、extractRotation(m)、setPosition(v)
Quaternion
表示旋转且不会发生万向节锁。对于插值动画和复合旋转,务必优先使用 Quaternion,而非 Euler。
import { Quaternion } from 'three';
const q = new Quaternion(); // identity: (0, 0, 0, 1)
设置方法: setFromAxisAngle(axis, angle)、setFromEuler(euler)、setFromRotationMatrix(m)、setFromUnitVectors(vFrom, vTo)
操作: multiply(q)(先应用 q,再应用当前四元数)、premultiply(q)、slerp(qb, t)、slerpQuaternions(qa, qb, t)、rotateTowards(q, step)、conjugate()、invert()、normalize()
比较: dot(q): number、angleTo(q): number、equals(q): boolean
Euler
以弧度表示、具有旋转顺序且便于人类阅读的旋转。
import { Euler } from 'three';
const e = new Euler(0, Math.PI / 2, 0, 'XYZ');
旋转顺序: 'XYZ'(默认)、'YXZ'、'ZXY'、'ZYX'、'YZX'、'XZY'
万向节锁: 在 'XYZ' 顺序下,Y = +/- 90 degrees 时会发生万向节锁。症状:出现意外跳变、丢失一个旋转轴。
方法: setFromRotationMatrix(m)、setFromQuaternion(q, order?)、reorder(newOrder)、equals(euler): boolean
Euler 与 Quaternion 的选择流程
| 场景 | 使用 |
|---|---|
| 设置固定旋转 | Euler——便于人类阅读 |
| 平滑旋转动画 | Quaternion + slerp() |
| 组合多个旋转 | Quaternion + multiply() |
| 避免万向节锁 | Quaternion |
| 从用户输入读取旋转(度数) | Euler,通过 quaternion.setFromEuler(euler) 转换 |
| 在场景图中存储旋转 | object.rotation(Euler)会自动与 object.quaternion 同步 |
Color
import { Color } from 'three';
new Color(0xff0000); // hex integer
new Color('red'); // CSS color name
new Color('rgb(255, 0, 0)'); // CSS rgb string
new Color('#ff0000'); // CSS hex string
new Color('hsl(0, 100%, 50%)'); // CSS hsl string
new Color(1.0, 0.0, 0.0); // RGB floats (0-1 range)
属性: r、g、b(数字,范围为 0-1)。
设置方法: set(value)、setHex(hex)、setRGB(r,g,b)、setHSL(h,s,l)、setStyle(css)、setColorName(name)
获取方法: getHex(): number、getHexString(): string、getHSL(target): {h,s,l}、getStyle(): string
插值: lerp(color, alpha)(RGB)、lerpHSL(color, alpha)(色相变化时感知效果更好)、lerpColors(c1, c2, alpha)
色彩空间: convertSRGBToLinear()、convertLinearToSRGB()——务必将纹理颜色转换到线性空间,以实现物理正确的渲染。
MathUtils
静态实用方法——切勿实例化,务必通过 MathUtils.method() 调用。
import { MathUtils } from 'three';
MathUtils.degToRad(90); // 1.5707...
MathUtils.clamp(value, 0, 1); // clamp to range
MathUtils.lerp(0, 100, 0.5); // 50
MathUtils.mapLinear(5, 0, 10, 0, 100); // 50
MathUtils.smoothstep(0.5, 0, 1); // Hermite ease
MathUtils.damp(current, target, lambda, dt); // frame-rate-independent damping
MathUtils.generateUUID(); // RFC 4122 v4 UUID
damp() 对平滑的摄像机跟随和 UI 动画尤其有用——它能产生与帧率无关的指数衰减,与动画循环中简单的 lerp 不同。
边界体
Box3(轴对齐包围盒)
import { Box3, Vector3 } from 'three';
const box = new Box3();
box.setFromObject(mesh); // compute from mesh
box.containsPoint(new Vector3(1, 2, 3)); // boolean
box.intersectsBox(otherBox); // boolean
box.getCenter(new Vector3()); // center point
box.getSize(new Vector3()); // dimensions
Sphere、Plane、Ray、Frustum
- Sphere:
containsPoint()、intersectsBox()、intersectsSphere()、distanceToPoint() - Plane:
distanceToPoint()、projectPoint()、intersectLine() - Ray:
intersectBox()、intersectSphere()、intersectPlane()、distanceToPoint() - Frustum:
setFromProjectionMatrix(m)、containsPoint()、intersectsObject()、intersectsBox()
参考链接
- references/methods.md——Vector3、Matrix4、Quaternion、Euler、Color、MathUtils、Box3、Sphere、Plane、Ray 的完整方法签名
- references/examples.md——常见 3D 数学运算的可运行代码示例
- references/anti-patterns.md——使用 Three.js 数学类时应避免的做法
Official Sources
- https://threejs.org/docs/#api/en/math/Vector3
- https://threejs.org/docs/#api/en/math/Matrix4
- https://threejs.org/docs/#api/en/math/Quaternion
- https://threejs.org/docs/#api/en/math/Euler
- https://threejs.org/docs/#api/en/math/Color
- https://threejs.org/docs/#api/en/math/MathUtils
- https://threejs.org/docs/#api/en/math/Box3