一、四元数基础概念
在计算机图形学中,四元数是一种用于表示旋转和方向的强大数学工具。四元数由一个实部和三个虚部组成,形式为q = w + xi + yj + zk ,其中w是实部,x、y、z分别是虚部i、j、k的系数。虚部i、j、k满足特定的乘法规则:i * i = j * j = k * k = -1,i * j = k,j * k = i,k * i = j ,并且乘法不满足交换律,例如j * i = -k。
四元数与复数类似,但扩展到了四维空间,相比传统的欧拉角和旋转矩阵,四元数在表示旋转时具有诸多优势,如避免万向节死锁、更高效的插值运算等。
二、四元数的运算
1. 四元数的加法
两个四元数q1 = w1 + x1i + y1j + z1k和q2 = w2 + x2i + y2j + z2k相加,结果是一个新的四元数q = (w1 + w2) + (x1 + x2)i + (y1 + y2)j + (z1 + z2)k。在 JavaScript 中可以这样实现:
function quaternionAdd(q1, q2) {
return {
w: q1.w + q2.w,
x: q1.x + q2.x,
y: q1.y + q2.y,
z: q1.z + q2.z
};
}
2. 四元数的乘法
四元数乘法遵循上述虚部的乘法规则,通过展开各项并合并同类项得到结果。两个四元数q1和q2相乘的 JavaScript 实现如下:
function quaternionMultiply(q1, q2) {
return {
w: q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z,
x: q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
y: q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x,
z: q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w
};
}
3. 四元数的共轭
四元数q = w + xi + yj + zk的共轭q* = w - xi - yj - zk,即虚部取反。在 JavaScript 中:
function quaternionConjugate(q) {
return {
w: q.w,
x: -q.x,
y: -q.y,
z: -q.z
};
}
4. 四元数的模
四元数q的模||q|| = √(w² + x² + y² + z²),表示四元数的大小。计算模的 JavaScript 代码如下:
function quaternionMagnitude(q) {
return Math.sqrt(q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z);
}
5. 四元数的归一化
归一化四元数是将其四元数的模变为 1,通过将四元数的每个分量除以它的模来实现。归一化的 JavaScript 函数:
function quaternionNormalize(q) {
const magnitude = quaternionMagnitude(q);
return {
w: q.w / magnitude,
x: q.x / magnitude,
y: q.y / magnitude,
z: q.z / magnitude
};
}
三、四元数表示旋转
在计算机图形学中,四元数常用于表示三维空间中的旋转。绕单位向量(x, y, z)旋转角度θ的四元数可以表示为:
q = cos(θ/2) + x * sin(θ/2) * i + y * sin(θ/2) * j + z * sin(θ/2) * k
将一个三维向量v用四元数q进行旋转,需要先将向量v转换为纯四元数p = 0 + vx * i + vy * j + vz * k ,然后通过计算q * p * q*得到旋转后的向量对应的四元数,其虚部即为旋转后的三维向量。以下是用 JavaScript 实现向量旋转的代码:
function rotateVectorByQuaternion(v, q) {
const p = {w: 0, x: v.x, y: v.y, z: v.z};
const qp = quaternionMultiply(q, p);
const qpq = quaternionMultiply(qp, quaternionConjugate(q));
return {x: qpq.x, y: qpq.y, z: qpq.z};
}
四、四元数插值
在动画和计算机图形应用中,常常需要在两个旋转之间进行平滑过渡,这就需要用到四元数插值。常见的插值方法是球面线性插值(Slerp)。
Slerp 在两个四元数q1和q2之间,根据插值因子t(0 到 1 之间)计算插值结果。其基本思想是在四维空间的超球面上沿着最短路径进行插值。JavaScript 实现 Slerp 的代码如下:
function slerp(q1, q2, t) {
let dot = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;
if (dot < 0) {
q2 = {w: -q2.w, x: -q2.x, y: -q2.y, z: -q2.z};
dot = -dot;
}
const k0 = 1 - t;
const k1 = t;
if (dot > 0.9995) {
return {
w: k0 * q1.w + k1 * q2.w,
x: k0 * q1.x + k1 * q2.x,
y: k0 * q1.y + k1 * q2.y,
z: k0 * q1.z + k1 * q2.z
};
}
const theta = Math.acos(dot);
const sinTheta = Math.sin(theta);
return {
w: Math.sin((1 - t) * theta) / sinTheta * q1.w + Math.sin(t * theta) / sinTheta * q2.w,
x: Math.sin((1 - t) * theta) / sinTheta * q1.x + Math.sin(t * theta) / sinTheta * q2.x,
y: Math.sin((1 - t) * theta) / sinTheta * q1.y + Math.sin(t * theta) / sinTheta * q2.y,
z: Math.sin((1 - t) * theta) / sinTheta * q1.z + Math.sin(t * theta) / sinTheta * q2.z
};
}
通过以上内容,你已经对四元数在计算机图形学中的概念、运算、旋转表示和插值有了深入了解。在实际应用中,四元数可以用于游戏开发中的角色动画、3D 建模软件中的物体旋转等场景,发挥其高效和稳定的优势 。