quat:高性能四元数运算库
一款轻量且高性能的 TypeScript 四元数库,专为 3D 旋转计算设计。支持四元数的创建、运算、插值、转换等全功能操作,以及批量点旋转,同时提供通用模块支持(ESM/CJS/IIFE),可无缝集成到 Node.js、打包工具及浏览器环境中。
核心特性
- 多环境兼容:支持 ESM(Node.js/打包工具)、CommonJS(Node.js)和 IIFE(浏览器全局变量),可通过 CDN 直接引入。
- 极致性能:基于
Float32Array 实现,内存布局优化,CPU 缓存利用率高,垃圾回收开销最小化。 - 完整 3D 旋转工具链:覆盖四元数与欧拉角/矩阵的转换、插值计算及批量顶点旋转。
- 类型安全:严格的 TypeScript 类型定义 + 运行时类型检查,避免无效旋转数据导致的错误。
- 浏览器友好:提供 IIFE 构建版本(v1.1.0+),可通过 unpkg 加载,自动暴露全局变量
quat 直接使用。
安装方式
1. 包管理器(ESM/CJS)
适用于 Node.js 或打包工具(Webpack/Vite/Rollup):
npm install quat
yarn add quat
2. 浏览器 CDN(IIFE)
直接在浏览器中加载预构建的 IIFE 包(自动暴露全局变量 quat):
<script src="https://unpkg.com/quat@latest/dist/index.global.js"></script>
<script>const q = quat.create();
</script>
使用示例
ESM 环境(TypeScript/JavaScript)
import * as quat from 'quat';
const q1 = quat.create();
const q2 = quat.from([0, 1, 0], Math.PI / 2);
const q3 = quat.of(Math.PI/2, 0, 0);
const q4 = quat.set(0.5, 0.5, 0, Math.SQRT1_2);
const combined = quat.multiply(q2, q3);
const conjugate = quat.conjugate(combined);
const inverse = quat.invert(combined);
const normalized = quat.normalize(q4);
const slerped = quat.slerp(q2, q3, 0.5);
const lerped = quat.lerp(q2, q3, 0.5);
const sqlerped = quat.sqlerp(q1, q2, q3, q4, 0.5);
const point = [1, 0, 0];
const rotatedPoint = quat.rotatePoint(q2, point);
const vertices = new Float32Array([1,0,0, 0,1,0, 0,0,1]);
const rotatedVertices = new Float32Array(vertices.length);
quat.rotatePoints(q2, vertices, rotatedVertices);
const mat = quat.toMat3(q2);
const qFromMat = quat.fromMat3(mat);
const isQuat = quat.isQuat(q2);
const quatStr = quat.str(q2);
CommonJS 环境(Node.js)
const quat = require('quat');
const randomQuat = quat.random();
const axis = new Float32Array(3);
const angle = quat.getAxisAngle(axis, randomQuat);
console.log(`绕轴 [${axis.join(', ')}] 旋转 ${angle.toFixed(2)} 弧度`);
浏览器 IIFE 环境(全局变量)
<script src="https://unpkg.com/quat@latest/dist/index.global.js"></script>
<script>const rotateZ90 = quat.from([0,0,1], Math.PI/2); const squareVertices = new Float32Array([1,1,0, -1,1,0, -1,-1,0, 1,-1,0 ]);const rotatedSquare = new Float32Array(squareVertices.length);quat.rotatePoints(rotateZ90, squareVertices, rotatedSquare);console.log('旋转后的顶点:', rotatedSquare);
</script>
完整 API 参考
所有方法均支持可选的 out 参数以复用内存(减少垃圾回收),若未传入 out,则默认创建新的 Float32Array 实例返回。
1. 四元数创建
| 方法 | 函数签名 | 描述 |
|---|
create | (): Quat | 创建单位四元数 [0, 0, 0, 1]。 |
from | (axis: [number,number,number] | ReadonlyVec3, angle: number, out?: Quat): Quat | 从旋转轴(建议单位向量)和角度(弧度)创建四元数。 |
of | (x: number, y: number, z: number, out?: Quat): Quat | 从 XYZ 欧拉角(弧度,旋转顺序 X→Y→Z,与 Three.js 兼容)创建四元数。 |
set | (x: number, y: number, z: number, w: number, out?: Quat): Quat | 从显式分量创建四元数(x/y/z 为虚部,w 为实部)。 |
fromMat3 | (mat: ReadonlyMat3, out?: Quat): Quat | 将 3x3 列优先旋转矩阵转换为四元数。 |
fromArray | (arr: number[]): Quat | 将 4 元素普通数组 [x,y,z,w] 转换为四元数,数组长度非 4 时抛出错误。 |
random | (out?: Quat): Quat | 生成随机单位四元数(旋转分布均匀)。 |
2. 四元数运算
| 方法 | 函数签名 | 描述 |
|---|
multiply | (a: ReadonlyQuat, b: ReadonlyQuat, out?: Quat): Quat | 四元数乘法(out = a * b),几何意义:先应用 b 的旋转,再应用 a 的旋转。 |
add | (a: ReadonlyQuat, b: ReadonlyQuat, out?: Quat): Quat | 四元数分量相加(out[i] = a[i] + b[i])。 |
scale | (a: ReadonlyQuat, s: number, out?: Quat): Quat | 四元数标量缩放(out[i] = a[i] * s)。 |
conjugate | (a: ReadonlyQuat, out?: Quat): Quat | 计算共轭四元数(翻转虚部:out = [-x, -y, -z, w])。 |
invert | (a: ReadonlyQuat, out?: Quat): Quat | 计算逆四元数(单位四元数的逆等于其共轭)。 |
normalize | (a: ReadonlyQuat, out?: Quat): Quat | 归一化四元数(确保单位长度,是有效旋转的前提,避免缩放效果)。 |
exp | (a: ReadonlyQuat, out?: Quat): Quat | 计算四元数的指数(高阶旋转数学运算)。 |
ln | (a: ReadonlyQuat, out?: Quat): Quat | 计算四元数的自然对数(高阶旋转数学运算)。 |
pow | (a: ReadonlyQuat, b: number, out?: Quat): Quat | 计算四元数的标量幂(a^b),基于 ln 和 exp 实现(如 pow(q, 0.5) 可将旋转角度减半)。 |
3. 插值计算
| 方法 | 函数签名 | 描述 |
|---|
slerp | (a: ReadonlyQuat, b: ReadonlyQuat, t: number, out?: Quat): Quat | 球面线性插值,保持角速度恒定(最适合平滑旋转动画),t ∈ [0,1](0 对应 a,1 对应 b)。 |
lerp | (a: ReadonlyQuat, b: ReadonlyQuat, t: number, out?: Quat): Quat | 线性插值,速度快但角速度非恒定,需后续归一化才能作为有效旋转四元数。 |
sqlerp | (a: ReadonlyQuat, b: ReadonlyQuat, c: ReadonlyQuat, d: ReadonlyQuat, t: number, out?: Quat): Quat | 球面二次插值,通过两个控制点(b、c)实现 a 到 d 的平滑曲线过渡。 |
4. 点与顶点旋转
| 方法 | 函数签名 | 描述 |
|---|
rotatePoint | (q: ReadonlyQuat, point: [number,number,number] | ReadonlyVec3, out?: Vec3): Vec3 | 旋转单个 3D 点,基于公式 p' = q * p * q⁻¹(p 为纯四元数 [x,y,z,0])。 |
rotatePoints | (q: ReadonlyQuat, points: Float32Array, out: Float32Array): Float32Array | 批量旋转扁平化 3D 点数组(格式:[x1,y1,z1,x2,y2,z2,...]),专为 WebGL 顶点数据优化,比循环调用 rotatePoint 快 40%+。若 points 与 out 长度不相等或长度非 3 的倍数,将抛出错误。 |
5. 矩阵转换
| 方法 | 函数签名 | 描述 |
|---|
toMat3 | (q: ReadonlyQuat, out?: Mat3): Mat3 | 将四元数转换为 3x3 列优先旋转矩阵(兼容 WebGL/OpenGL)。 |
fromMat3 | (mat: ReadonlyMat3, out?: Quat): Quat | 将 3x3 列优先旋转矩阵转换为四元数(toMat3 的逆操作)。 |
6. 旋转轴与角度提取
| 方法 | 函数签名 | 描述 |
|---|
getAxisAngle | (outAxis: Vec3, q: ReadonlyQuat): number | 从四元数中提取旋转轴(存储到 outAxis)和角度(返回值,单位:弧度),复用 outAxis 避免内存分配。 |
7. 工具函数
| 方法 | 函数签名 | 描述 |
|---|
clone | (a: ReadonlyQuat): Quat | 深拷贝四元数。 |
copy | (a: ReadonlyQuat, out: Quat): Quat | 将 a 的值复制到 out(复用 out 的内存)。 |
toArray | (q: ReadonlyQuat): number[] | 将四元数转换为 4 元素普通数组 [x,y,z,w]。 |
str | (a: ReadonlyQuat): string | 将四元数转换为人类可读字符串(如:"quat(0.707107, 0.000000, 0.000000, 0.707107)")。 |
length | (a: ReadonlyQuat): number | 计算四元数的模长(长度),公式:√(x²+y²+z²+w²)。 |
squaredLength | (a: ReadonlyQuat): number | 计算四元数的平方模长(x²+y²+z²+w²),比 length 快(避免开方),适合用于比较。 |
dot | (a: ReadonlyQuat, b: ReadonlyQuat): number | 计算两个四元数的点积(a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w),用于相似度判断和 slerp 计算。 |
equals | (a: ReadonlyQuat, b: ReadonlyQuat): boolean | 检查两个四元数是否近似相等(考虑浮点误差,判断条件:dot(a,b) ≥ 1 - 1e-6)。 |
exactEquals | (a: ReadonlyQuat, b: ReadonlyQuat): boolean | 检查两个四元数是否完全相等(严格分量对比,仅用于精确值判断)。 |
isQuat | (value: unknown): value is Quat | 运行时类型守卫:判断值是否为有效四元数(Float32Array 且长度为 4)。 |
isVec3 | (value: unknown): value is Vec3 | 运行时类型守卫:判断值是否为有效三维向量(Float32Array 且长度为 3)。 |
类型定义
TypeScript 类型定义已内置(无需额外安装 @types/quat):
export type Quat = Float32Array & { length: 4 };
export type ReadonlyQuat = Readonly<Float32Array> & { length: 4 };
export type Vec3 = Float32Array & { length: 3 };
export type ReadonlyVec3 = Readonly<Float32Array> & { length: 3 };
export type Mat3 = Float32Array & { length: 9 };
export type ReadonlyMat3 = Readonly<Float32Array> & { length: 9 };
许可证
MIT