用外部旋转更新内部旋转
Updating an intrinsic rotation with an extrinsic rotation
我正在尝试为个人项目制作魔方模型,使用 Zdog for lightweight 3d graphics. Zdog uses a {x,y,z}
vector to represent rotation - I believe this is essentially a Tait-Bryan angle。
为了制作顶部、右侧、前部等的旋转动画,我将 9 个块附加到立方体中心的 anchor,然后将其沿所需方向旋转 90 度。这很好用,但是当动画完成后,我需要“保存”9 个块上的平移和旋转。翻译相对简单,但我坚持旋转。我基本上需要这样的功能:
function updateRotation(xyz, axis, angle) {
// xyz is a {x,y,z} vector
// axis is "x", "y", or "z"
// rotation is the angle of rotation in radians
}
将世界坐标中的axis
/angle
旋转应用于对象[中的xyz
矢量=30=]坐标。最初我只有 xyz[axis] += angle
,但这仅在其他轴没有任何旋转时才有效。然后我想我可以使用查找 table,我认为这是可能的,因为我只使用四分之一圈,但构建 table 比我想象的要难。
我开始怀疑我需要将 xyz
向量转换为其他表示形式(矩阵?四元数?)并在那里应用旋转,但我不确定从哪里开始。令人沮丧的是,我的块在动画结束时处于正确的位置 - 我只是不确定如何应用父级变换,以便我可以将它们从父级分离而不会丢失旋转。
据我所知,这不能仅用欧拉角来完成(至少不是以任何简单的方式)。我的解决方案是转换为四元数,旋转,然后转换回欧拉:
function updateRotation(obj, axis, rotation) {
const {x, y, z} = obj.rotate;
const q = new Quaternion()
.rotateZ(z)
.rotateY(y)
.rotateX(x);
const q2 = new Quaternion();
if (axis === 'x') {
q2.rotateX(rotation);
} else if (axis === 'y') {
q2.rotateY(rotation);
} else if (axis === 'z') {
q2.rotateZ(rotation);
}
q.multiply(q2, null);
const e = new Euler().fromQuaternion(q);
obj.rotate.x = e.x;
obj.rotate.y = e.y;
obj.rotate.z = e.z;
obj.normalizeRotate();
}
这使用 Euler
和 Quaternion
类 来自 math.gl。
(据我所知,Zdog 实际上使用 ZYX
欧拉角,因此创建第一个四元数时的旋转顺序。)
我正在尝试为个人项目制作魔方模型,使用 Zdog for lightweight 3d graphics. Zdog uses a {x,y,z}
vector to represent rotation - I believe this is essentially a Tait-Bryan angle。
为了制作顶部、右侧、前部等的旋转动画,我将 9 个块附加到立方体中心的 anchor,然后将其沿所需方向旋转 90 度。这很好用,但是当动画完成后,我需要“保存”9 个块上的平移和旋转。翻译相对简单,但我坚持旋转。我基本上需要这样的功能:
function updateRotation(xyz, axis, angle) {
// xyz is a {x,y,z} vector
// axis is "x", "y", or "z"
// rotation is the angle of rotation in radians
}
将世界坐标中的axis
/angle
旋转应用于对象[中的xyz
矢量=30=]坐标。最初我只有 xyz[axis] += angle
,但这仅在其他轴没有任何旋转时才有效。然后我想我可以使用查找 table,我认为这是可能的,因为我只使用四分之一圈,但构建 table 比我想象的要难。
我开始怀疑我需要将 xyz
向量转换为其他表示形式(矩阵?四元数?)并在那里应用旋转,但我不确定从哪里开始。令人沮丧的是,我的块在动画结束时处于正确的位置 - 我只是不确定如何应用父级变换,以便我可以将它们从父级分离而不会丢失旋转。
据我所知,这不能仅用欧拉角来完成(至少不是以任何简单的方式)。我的解决方案是转换为四元数,旋转,然后转换回欧拉:
function updateRotation(obj, axis, rotation) {
const {x, y, z} = obj.rotate;
const q = new Quaternion()
.rotateZ(z)
.rotateY(y)
.rotateX(x);
const q2 = new Quaternion();
if (axis === 'x') {
q2.rotateX(rotation);
} else if (axis === 'y') {
q2.rotateY(rotation);
} else if (axis === 'z') {
q2.rotateZ(rotation);
}
q.multiply(q2, null);
const e = new Euler().fromQuaternion(q);
obj.rotate.x = e.x;
obj.rotate.y = e.y;
obj.rotate.z = e.z;
obj.normalizeRotate();
}
这使用 Euler
和 Quaternion
类 来自 math.gl。
(据我所知,Zdog 实际上使用 ZYX
欧拉角,因此创建第一个四元数时的旋转顺序。)