0

我正在尝试理解四元数,并且在将其转换为实际有用的东西时遇到了很多麻烦。我看过一些 3blue1brown 的视频并阅读了一些教程,但我似乎无法将我看到的东西翻译成简单的东西,这意味着我根本不了解它。

从我能想到的最简单的例子开始,我想从 xyz (1, 0, 0) 处的一个点开始,围绕 Z 轴旋转 90 度。这应该给我点(0、1、0)。使用三角函数,进行旋转很简单(doSimple())。

正如我所说,我缺乏对四元数基础知识的理解,但据我所知,3d 空间中的一个点可以用 x、y、z 和 0 表示 w。而且gl-matrix有一个 'quat.rotateZ' 方法,看起来它应该围绕该轴旋转一个角度。我的结果似乎表明它只旋转了 1/2 角度并且方向错误(repl.it):

const { quat } = require('gl-matrix');

const doSimple = () => {
  // simple using trig:
  const x = 1, y = 0;
  const angle = Math.PI / 2; // 15 degrees
  const newX = x * Math.cos(angle) - y * Math.sin(angle);
  const newY = x * Math.sin(angle) + y * Math.cos(angle);
  console.log({ angle, x, y, newX, newY });
}

const doQuat = () => {
  let [x, y, z, w] = [1, 0, 0, 0];
  const a = quat.fromValues(x, y, z, w);
  const ninetyDegrees = Math.PI / 2;
  const b = quat.create();
  quat.rotateZ(b, a, ninetyDegrees);
  const results = { a, b }
  console.log(results)
}

const doAngle = () => {
  let [x1, y1, z1, w1] = [1, 0, 0, 0];
  let [x2, y2, z2, w2] = [0, 1, 0, 0];
  const q1 = quat.fromValues(x1, y1, z1, w1);
  const q2 = quat.fromValues(x2, y2, z2, w2);
  const angle = quat.getAngle(q1, q2);
  console.log({ angle });
}

doSimple();
doQuat();
doAngle();

doSimple()在我看来很好:

{
  angle: 1.5707963267948966,
  x: 1,
  y: 0,
  newX: 6.123233995736766e-17,
  newY: 1
}

doQuat()使用quat.rotateZ()并且似乎只旋转 45 度并且方向错误:

{
  a: Float32Array(4) [ 1, 0, 0, 0 ],
  b: Float32Array(4) [ 0.7071067690849304, -0.7071067690849304, 0, 0 ]
}

doAngle()似乎报告在 (1,0,0) 和 (0,1,0) 之间有 180 度:

{ angle: 3.141592653589793 }

所以我知道我完全误解了一些东西,但我不知道它是什么......

- -编辑 - -

我认为我的很多困惑源于示例中的不同术语。 gl-matrix使用 x,y,z,w。3blue1brown 使用<blank>, i,j,k。 本文使用 q0,q1,q2,q3。 论文中的这个计算器似乎没有意义,因为 Yaw 围绕 Z 轴旋转,围绕 Y 轴俯仰,围绕 X 轴滚动?

如果我在 3d 空间中思考,我思考事物的正常方式是 Z 面向屏幕外,X 和 Y 代表屏幕上的正常 2d 图形(X 点“右”,Y 点“上”)。偏航应该围绕 Y 轴旋转,俯仰应该围绕 X 轴旋转。

我想错了吗?在尝试学习时,是否有一组(或多组)查看坐标系、旋转和四元数的标准方法?例如我认为由于 gl-matrix 使用 x,y,z,w 而论文使用 q0,q1,q2,q3 而 3b1b 使用空白,i,j,k,我认为转换如下:

  • q0 -> 空白 -> w
  • q1 -> i -> x
  • q2 -> j -> y
  • q3 -> k -> z
4

1 回答 1

0

我发现了一些东西,并且认为我现在至少有一个很好的学习基础。看3b1b 的互动视频,将轴对齐,我想如何查看它们,x 和 y 像 2d 图形,z 通过屏幕指向我,理解 f(i) 表示 x=1 处的点,i 代表x 轴,到处玩耍帮助了我。

  • (blank,i,j,k) 或 (q0,q1,q2,q3) 确实等价于 (w,x,y,z)
  • 旋转一个点涉及两次乘法: f(p) = q * p * q -1所以这是一个两步过程
  • glMatrix的rotateZ函数好像并没有像我想的那样,我真的不知道它是做什么的

所以似乎有效:

// fromEuler gives quat from X,Y,Z in DEGREES
const euler = quat.fromEuler(quat.create(), 0, 0, 90);

// p is my point, at (1,0,0) with w=0
let [x, y, z, w] = [1, 0, 0, 0];
const p = quat.fromValues(x, y, z, w);

// so I need q (rotation which is euler 90 degrees about Z axis)
// and inverse of q.  Formula:
// f(p) = q * p * qInverse
const q = quat.clone(euler);
const qInverse = quat.invert(quat.create(), q);

// first q * p, then result * qInverse
let pPrime = quat.multiply(quat.create(), q, p);
pPrime = quat.multiply(quat.create(), pPrime, qInverse);

这给了我正在寻找的东西:

{
  euler: Float32Array(4) [ 0, 0, 0.7071067690849304, 0.7071067690849304 ],
  p: Float32Array(4) [ 1, 0, 0, 0 ],
  q: Float32Array(4) [ 0, 0, 0.7071067690849304, 0.7071067690849304 ],
  qInverse: Float32Array(4) [ -0, -0, -0.7071067690849304, 0.7071067690849304 ],
  pPrime: Float32Array(4) [ 0, 0.9999999403953552, 0, 0 ]
}
Ok, from point (1, 0, 0) gives (0, 1, 0)
q (euler rotation 90 degrees about z axis):
  xyzw: (x = 0,y = 0,z = 0.71,w = 0.71)
  ijk: (0.71, i = 0, j = 0, k = 0.71)
qInverse:
  xyzw: (x = 0,y = 0,z = -0.71,w = 0.71)
  ijk: (0.71, i = 0, j = 0, k = -0.71)

四元数使用 angle/2 表示 sin 和 cos,为什么我会得到 45 度。现在我可以

于 2021-11-08T01:54:23.877 回答