查找表示从一个向量到另一个向量的旋转的四元数

发布于 2024-07-29 02:49:18 字数 45 浏览 9 评论 0原文

我有两个向量 u 和 v。有没有办法找到表示从 u 到 v 的旋转的四元数?

I have two vectors u and v. Is there a way of finding a quaternion representing the rotation from u to v?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

不弃不离 2024-08-05 02:49:18
Quaternion q;
vector a = crossproduct(v1, v2);
q.xyz = a;
q.w = sqrt((v1.Length ^ 2) * (v2.Length ^ 2)) + dotproduct(v1, v2);

不要忘记标准化 q。

理查德关于不存在唯一旋转的说法是正确的,但上面应该给出“最短弧线”,这可能正是您所需要的。

Quaternion q;
vector a = crossproduct(v1, v2);
q.xyz = a;
q.w = sqrt((v1.Length ^ 2) * (v2.Length ^ 2)) + dotproduct(v1, v2);

Don't forget to normalize q.

Richard is right about there not being a unique rotation, but the above should give the "shortest arc," which is probably what you need.

倥絔 2024-08-05 02:49:18

半程矢量解决方案

我想出了一个我相信 Imbrondir 试图呈现的解决方案(尽管有一个小错误,这可能就是为什么 sinisterchipmunk 无法验证它)。

假设我们可以构造一个表示绕轴旋转的四元数,如下所示:

q.w == cos(angle / 2)
q.x == sin(angle / 2) * axis.x
q.y == sin(angle / 2) * axis.y
q.z == sin(angle / 2) * axis.z

两个归一化向量的点积和叉积为:

dot     == cos(theta)
cross.x == sin(theta) * perpendicular.x
cross.y == sin(theta) * perpendicular.y
cross.z == sin(theta) * perpendicular.z

视为从 uv 的旋转> 可以通过围绕垂直向量旋转 theta(向量之间的角度)来实现,看起来我们可以直接从点积和叉积的结果构造一个表示这种旋转的四元数; 然而,就目前情况而言,theta = angle / 2,这意味着这样做会导致所需旋转的两倍。

一种解决方案是计算 uv 之间的向量,并使用 u的点积和叉积half-way 向量来构造一个四元数,表示 uhalf-way 向量之间角度的旋转两倍,其中带我们一路到达v

有一种特殊情况,其中 u == -v 和唯一的中途向量变得无法计算。 这是预期的,因为有无限多个“最短弧”旋转可以将我们从 u 带到 v,并且我们必须简单地围绕与 u 正交的任何向量旋转 180 度strong>u(或v)作为我们的特殊情况解决方案。 这是通过获取 u 与任何其他不平行于 u 的向量的归一化叉积来完成的。

接下来是伪代码(显然,实际上,特殊情况必须考虑浮点不准确性——可能通过根据某个阈值而不是绝对值检查点积)。

另请注意,当 u == v没有特殊情况(生成单位四元数 - 亲自检查并查看)。

// N.B. the arguments are _not_ axis and angle, but rather the
// raw scalar-vector components.
Quaternion(float w, Vector3 xyz);

Quaternion get_rotation_between(Vector3 u, Vector3 v)
{
  // It is important that the inputs are of equal length when
  // calculating the half-way vector.
  u = normalized(u);
  v = normalized(v);

  // Unfortunately, we have to check for when u == -v, as u + v
  // in this case will be (0, 0, 0), which cannot be normalized.
  if (u == -v)
  {
    // 180 degree rotation around any orthogonal vector
    return Quaternion(0, normalized(orthogonal(u)));
  }

  Vector3 half = normalized(u + v);
  return Quaternion(dot(u, half), cross(u, half));
}

orthogonal 函数返回与给定向量正交的任何向量。 该实现使用具有最正交基向量的叉积。

Vector3 orthogonal(Vector3 v)
{
    float x = abs(v.x);
    float y = abs(v.y);
    float z = abs(v.z);

    Vector3 other = x < y ? (x < z ? X_AXIS : Z_AXIS) : (y < z ? Y_AXIS : Z_AXIS);
    return cross(v, other);
}

半路四元数解决方案

这实际上是已接受的答案中提出的解决方案,它似乎比中路向量解决方案稍微快一些(根据我的测量,快约 20%,尽管不要相信我的话)。 我将其添加到此处,以防像我这样的其他人对解释感兴趣。

本质上,您可以计算导致所需旋转两倍的四元数(如其他解决方案中详细说明),并找到该角度和零度之间的四元数,而不是使用半程向量计算四元数。

正如我之前所解释的,双倍所需旋转的四元数是:

q.w   == dot(u, v)
q.xyz == cross(u, v)

零旋转的四元数是:

q.w   == 1
q.xyz == (0, 0, 0)

计算中途四元数只是将四元数相加并将结果标准化的问题,就像矢量一样。 然而,与向量的情况一样,四元数必须具有相同的大小,否则结果将偏向具有较大大小的四元数。

由两个向量的点积和叉积构建的四元数将与这些乘积具有相同的量级:length(u) * length(v)。 我们可以放大单位四元数,而不是将所有四个分量除以这个因子。 如果您想知道为什么使用 sqrt(length(u) ^ 2 * length(v) ^ 2) 接受的答案似乎使问题变得复杂,这是因为向量的平方长度计算起来更快比长度,所以我们可以节省一次 sqrt 计算。 结果是:

q.w   = dot(u, v) + sqrt(length_2(u) * length_2(v))
q.xyz = cross(u, v)

然后对结果进行归一化。 伪代码如下:

Quaternion get_rotation_between(Vector3 u, Vector3 v)
{
  float k_cos_theta = dot(u, v);
  float k = sqrt(length_2(u) * length_2(v));

  if (k_cos_theta / k == -1)
  {
    // 180 degree rotation around any orthogonal vector
    return Quaternion(0, normalized(orthogonal(u)));
  }

  return normalized(Quaternion(k_cos_theta + k, cross(u, v)));
}

Half-Way Vector Solution

I came up with the solution that I believe Imbrondir was trying to present (albeit with a minor mistake, which was probably why sinisterchipmunk had trouble verifying it).

Given that we can construct a quaternion representing a rotation around an axis like so:

q.w == cos(angle / 2)
q.x == sin(angle / 2) * axis.x
q.y == sin(angle / 2) * axis.y
q.z == sin(angle / 2) * axis.z

And that the dot and cross product of two normalized vectors are:

dot     == cos(theta)
cross.x == sin(theta) * perpendicular.x
cross.y == sin(theta) * perpendicular.y
cross.z == sin(theta) * perpendicular.z

Seeing as a rotation from u to v can be achieved by rotating by theta (the angle between the vectors) around the perpendicular vector, it looks as though we can directly construct a quaternion representing such a rotation from the results of the dot and cross products; however, as it stands, theta = angle / 2, which means that doing so would result in twice the desired rotation.

One solution is to compute a vector half-way between u and v, and use the dot and cross product of u and the half-way vector to construct a quaternion representing a rotation of twice the angle between u and the half-way vector, which takes us all the way to v!

There is a special case, where u == -v and a unique half-way vector becomes impossible to calculate. This is expected, given the infinitely many "shortest arc" rotations which can take us from u to v, and we must simply rotate by 180 degrees around any vector orthogonal to u (or v) as our special-case solution. This is done by taking the normalized cross product of u with any other vector not parallel to u.

Pseudo code follows (obviously, in reality the special case would have to account for floating point inaccuracies -- probably by checking the dot products against some threshold rather than an absolute value).

Also note that there is no special case when u == v (the identity quaternion is produced -- check and see for yourself).

// N.B. the arguments are _not_ axis and angle, but rather the
// raw scalar-vector components.
Quaternion(float w, Vector3 xyz);

Quaternion get_rotation_between(Vector3 u, Vector3 v)
{
  // It is important that the inputs are of equal length when
  // calculating the half-way vector.
  u = normalized(u);
  v = normalized(v);

  // Unfortunately, we have to check for when u == -v, as u + v
  // in this case will be (0, 0, 0), which cannot be normalized.
  if (u == -v)
  {
    // 180 degree rotation around any orthogonal vector
    return Quaternion(0, normalized(orthogonal(u)));
  }

  Vector3 half = normalized(u + v);
  return Quaternion(dot(u, half), cross(u, half));
}

The orthogonal function returns any vector orthogonal to the given vector. This implementation uses the cross product with the most orthogonal basis vector.

Vector3 orthogonal(Vector3 v)
{
    float x = abs(v.x);
    float y = abs(v.y);
    float z = abs(v.z);

    Vector3 other = x < y ? (x < z ? X_AXIS : Z_AXIS) : (y < z ? Y_AXIS : Z_AXIS);
    return cross(v, other);
}

Half-Way Quaternion Solution

This is actually the solution presented in the accepted answer, and it seems to be marginally faster than the half-way vector solution (~20% faster by my measurements, though don't take my word for it). I'm adding it here in case others like myself are interested in an explanation.

Essentially, instead of calculating a quaternion using a half-way vector, you can calculate the quaternion which results in twice the required rotation (as detailed in the other solution), and find the quaternion half-way between that and zero degrees.

As I explained before, the quaternion for double the required rotation is:

q.w   == dot(u, v)
q.xyz == cross(u, v)

And the quaternion for zero rotation is:

q.w   == 1
q.xyz == (0, 0, 0)

Calculating the half-way quaternion is simply a matter of summing the quaternions and normalizing the result, just like with vectors. However, as is also the case with vectors, the quaternions must have the same magnitude, otherwise the result will be skewed towards the quaternion with the larger magnitude.

A quaternion constructed from the dot and cross product of two vectors will have the same magnitude as those products: length(u) * length(v). Rather than dividing all four components by this factor, we can instead scale up the identity quaternion. And if you were wondering why the accepted answer seemingly complicates matters by using sqrt(length(u) ^ 2 * length(v) ^ 2), it's because the squared length of a vector is quicker to calculate than the length, so we can save one sqrt calculation. The result is:

q.w   = dot(u, v) + sqrt(length_2(u) * length_2(v))
q.xyz = cross(u, v)

And then normalize the result. Pseudo code follows:

Quaternion get_rotation_between(Vector3 u, Vector3 v)
{
  float k_cos_theta = dot(u, v);
  float k = sqrt(length_2(u) * length_2(v));

  if (k_cos_theta / k == -1)
  {
    // 180 degree rotation around any orthogonal vector
    return Quaternion(0, normalized(orthogonal(u)));
  }

  return normalized(Quaternion(k_cos_theta + k, cross(u, v)));
}
恋你朝朝暮暮 2024-08-05 02:49:18

所述问题没有明确定义:给定的向量对不存在唯一的旋转。 例如,考虑 u = <1, 0, 0> 和 v = <0, 1, 0> 的情况。 从 u 到 v 的一次旋转将是绕 z 轴的 pi / 2 旋转。 从 u 到 v 的另一个旋转是围绕向量 <1, 1, 0>pi 旋转。

The problem as stated is not well-defined: there is not a unique rotation for a given pair of vectors. Consider the case, for example, where u = <1, 0, 0> and v = <0, 1, 0>. One rotation from u to v would be a pi / 2 rotation around the z-axis. Another rotation from u to v would be a pi rotation around the vector <1, 1, 0>.

世俗缘 2024-08-05 02:49:18

我对四元数不太擅长。 然而,我为此苦苦挣扎了几个小时,无法使 Polaris878 解决方案发挥作用。 我尝试过预规范化 v1 和 v2。 标准化 q。 标准化 q.xyz。 但我还是不明白。 结果还是没有给我正确的结果。

但最终我找到了一个可行的解决方案。 如果它对其他人有帮助,这是我的工作(python)代码:

def diffVectors(v1, v2):
    """ Get rotation Quaternion between 2 vectors """
    v1.normalize(), v2.normalize()
    v = v1+v2
    v.normalize()
    angle = v.dot(v2)
    axis = v.cross(v2)
    return Quaternion( angle, *axis )

如果 v1 和 v2 是并行的,则必须做出特殊情况,例如 v1 == v2 或 v1 == -v2 (具有一定的容忍度),我认为解决方案应该是四元数(1, 0,0,0)(无旋转)或四元数(0, *v1)(180 度旋转)

I'm not much good on Quaternion. However I struggled for hours on this, and could not make Polaris878 solution work. I've tried pre-normalizing v1 and v2. Normalizing q. Normalizing q.xyz. Yet still I don't get it. The result still didn't give me the right result.

In the end though I found a solution that did. If it helps anyone else, here's my working (python) code:

def diffVectors(v1, v2):
    """ Get rotation Quaternion between 2 vectors """
    v1.normalize(), v2.normalize()
    v = v1+v2
    v.normalize()
    angle = v.dot(v2)
    axis = v.cross(v2)
    return Quaternion( angle, *axis )

A special case must be made if v1 and v2 are paralell like v1 == v2 or v1 == -v2 (with some tolerance), where I believe the solutions should be Quaternion(1, 0,0,0) (no rotation) or Quaternion(0, *v1) (180 degree rotation)

提笔书几行 2024-08-05 02:49:18

要找到将 u 旋转到 v 的最小旋转四元数,请使用

align(quat(1, 0, 0, 0), u, v)

通用解决方案

function align(Q, u, v)
    U = quat(0, ux, uy, uz)
    V = quat(0, vx, vy, vz)
    return normalize(length(U*V)*Q - V*Q*U)

为什么要进行此通用化?

R = align(Q, u, v)

最重要的是R是最接近Q的四元数,其局部u方向全局指向v方向。 因此,R 是最接近 Q 的四元数,它将把 u 旋转到 v

这可用于为您提供所有可能的旋转,从 u 旋转到 v,具体取决于 Q 的选择。 如果您想要从 uv 的最小旋转(如其他解决方案所示),请使用 Q = quat(1, 0, 0, 0)

最常见的是,我发现您想要执行的实际操作是一个轴与另一个轴的一般对齐

// If you find yourself often doing something like
quatFromTo(toWorldSpace(Q, localFrom), worldTo)*Q
// you should instead consider doing 
align(Q, localFrom, worldTo)

示例

假设您想要四元数 Y,它代表 Q 的偏航,即绕 y 轴的纯旋转。 我们可以使用以下代码计算 Y

Y = align(quat(Qw, Qx, Qy, Qz), vec(0, 1, 0), vec(0, 1, 0))

// simplifies to
Y = normalize(quat(Qw, 0, Qy, 0))

对齐为 4x4 投影矩阵

如果要重复执行相同的对齐操作,因为此操作与将四元数投影到嵌入 4D 空间的 2D 平面上相同,我们可以将此操作表示为与 4x4 投影矩阵的乘法,A*Q

A = I - leftQ(V)*rightQ(U)/length(U*V)

// which expands to
A = mat4(
    1 + ux*vx + uy*vy + uz*vz, uy*vz - uz*vy, uz*vx - ux*vz, ux*vy - uy*vx,
    uy*vz - uz*vy, 1 + ux*vx - uy*vy - uz*vz, uy*vx + ux*vy, uz*vx + ux*vz,
    uz*vx - ux*vz, uy*vx + ux*vy, 1 - ux*vx + uy*vy - uz*vz, uz*vy + uy*vz,
    ux*vy - uy*vx, uz*vx + ux*vz, uz*vy + uy*vz, 1 - ux*vx - uy*vy + uz*vz)

// A can be applied to Q with the usual matrix-vector multiplication
R = normalize(A*Q)
//LeftQ is a 4x4 matrix which represents the multiplication on the left
//RightQ is a 4x4 matrix which represents the multiplication on the Right
LeftQ(w, x, y, z) = mat4(
    w, -x, -y, -z,
    x,  w, -z,  y,
    y,  z,  w, -x,
    z, -y,  x,  w)

RightQ(w, x, y, z) = mat4(
    w, -x, -y, -z,
    x,  w,  z, -y,
    y, -z,  w,  x,
    z,  y, -x,  w)

I = mat4(
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1)

To find the quaternion of smallest rotation which rotates u to v, use

align(quat(1, 0, 0, 0), u, v)

The Generalized Solution

function align(Q, u, v)
    U = quat(0, ux, uy, uz)
    V = quat(0, vx, vy, vz)
    return normalize(length(U*V)*Q - V*Q*U)

Why This Generalization?

R = align(Q, u, v)

Most importantly, R is the quaternion closest to Q whose local u direction points globally in the v direction. Consequently, R is the quaternion closest to Q which will rotate u to v.

This can be used to give you all possible rotations which rotate from u to v, depending on the choice of Q. If you want the minimal rotation from u to v, as the other solutions give, use Q = quat(1, 0, 0, 0).

Most commonly, I find that the real operation you want to do is a general alignment of one axis with another.

// If you find yourself often doing something like
quatFromTo(toWorldSpace(Q, localFrom), worldTo)*Q
// you should instead consider doing 
align(Q, localFrom, worldTo)

Example

Say you want the quaternion Y which only represents Q's yaw, the pure rotation about the y axis. We can compute Y with the following.

Y = align(quat(Qw, Qx, Qy, Qz), vec(0, 1, 0), vec(0, 1, 0))

// simplifies to
Y = normalize(quat(Qw, 0, Qy, 0))

Alignment as a 4x4 Projection Matrix

If you want to perform the same alignment operation repeatedly, because this operation is the same as the projection of a quaternion onto a 2D plane embedded in 4D space, we can represent this operation as the multiplication with 4x4 projection matrix, A*Q.

A = I - leftQ(V)*rightQ(U)/length(U*V)

// which expands to
A = mat4(
    1 + ux*vx + uy*vy + uz*vz, uy*vz - uz*vy, uz*vx - ux*vz, ux*vy - uy*vx,
    uy*vz - uz*vy, 1 + ux*vx - uy*vy - uz*vz, uy*vx + ux*vy, uz*vx + ux*vz,
    uz*vx - ux*vz, uy*vx + ux*vy, 1 - ux*vx + uy*vy - uz*vz, uz*vy + uy*vz,
    ux*vy - uy*vx, uz*vx + ux*vz, uz*vy + uy*vz, 1 - ux*vx - uy*vy + uz*vz)

// A can be applied to Q with the usual matrix-vector multiplication
R = normalize(A*Q)
//LeftQ is a 4x4 matrix which represents the multiplication on the left
//RightQ is a 4x4 matrix which represents the multiplication on the Right
LeftQ(w, x, y, z) = mat4(
    w, -x, -y, -z,
    x,  w, -z,  y,
    y,  z,  w, -x,
    z, -y,  x,  w)

RightQ(w, x, y, z) = mat4(
    w, -x, -y, -z,
    x,  w,  z, -y,
    y, -z,  w,  x,
    z,  y, -x,  w)

I = mat4(
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1)
梦在夏天 2024-08-05 02:49:18

从算法的角度来看,最快的解决方案是在伪代码中查找

 Quaternion shortest_arc(const vector3& v1, const vector3& v2 ) 
 {
     // input vectors NOT unit
     Quaternion q( cross(v1, v2), dot(v1, v2) );
     // reducing to half angle
     q.w += q.magnitude(); // 4 multiplication instead of 6 and more numerical stable

     // handling close to 180 degree case
     //... code skipped 

        return q.normalized(); // normalize if you need UNIT quaternion
 }

确保您需要单位四元数(通常,插值需要它)。

笔记:
非单位四元数可以用于比单位更快的某些操作。

From algorithm point of view , the fastest solution looks in pseudocode

 Quaternion shortest_arc(const vector3& v1, const vector3& v2 ) 
 {
     // input vectors NOT unit
     Quaternion q( cross(v1, v2), dot(v1, v2) );
     // reducing to half angle
     q.w += q.magnitude(); // 4 multiplication instead of 6 and more numerical stable

     // handling close to 180 degree case
     //... code skipped 

        return q.normalized(); // normalize if you need UNIT quaternion
 }

Be sure that you need unit quaternions (usualy, it is required for interpolation).

NOTE:
Nonunit quaternions can be used with some operations faster than unit.

空城之時有危險 2024-08-05 02:49:18

为什么不使用纯四元数表示向量? 如果你先将它们标准化也许会更好。
q1 = (0 ux uy uz)'
q2 = (0 vx vy vz)'
q1 qrot = q2
预乘 q1-1
qrot = q1-1 q2
其中 q1-1 = q1conj / qnorm
这可以被认为是“左分裂”。
右除法,这不是你想要的,是:
qrot,right = q2-1 q1

Why not represent the vector using pure quaternions? It's better if you normalize them first perhaps.
q1 = (0 ux uy uz)'
q2 = (0 vx vy vz)'
q1 qrot = q2
Pre-multiply with q1-1
qrot = q1-1 q2
where q1-1 = q1conj / qnorm
This is can be thought of as "left division".
Right division, which is not what you want is:
qrot,right = q2-1 q1

〆凄凉。 2024-08-05 02:49:18

有些答案似乎没有考虑叉积可能为 0 的可能性。下面的代码片段使用角轴表示:

//v1, v2 are assumed to be normalized
Vector3 axis = v1.cross(v2);
if (axis == Vector3::Zero())
    axis = up();
else
    axis = axis.normalized();

return toQuaternion(axis, ang);

toQuaternion 可以按如下方式实现:

static Quaternion toQuaternion(const Vector3& axis, float angle)
{
    auto s = std::sin(angle / 2);
    auto u = axis.normalized();
    return Quaternion(std::cos(angle / 2), u.x() * s, u.y() * s, u.z() * s);
}

如果您使用的是 Eigen 库,你也可以这样做:

Quaternion::FromTwoVectors(from, to)

Some of the answers don't seem to consider possibility that cross product could be 0. Below snippet uses angle-axis representation:

//v1, v2 are assumed to be normalized
Vector3 axis = v1.cross(v2);
if (axis == Vector3::Zero())
    axis = up();
else
    axis = axis.normalized();

return toQuaternion(axis, ang);

The toQuaternion can be implemented as follows:

static Quaternion toQuaternion(const Vector3& axis, float angle)
{
    auto s = std::sin(angle / 2);
    auto u = axis.normalized();
    return Quaternion(std::cos(angle / 2), u.x() * s, u.y() * s, u.z() * s);
}

If you are using Eigen library, you can also just do:

Quaternion::FromTwoVectors(from, to)
甜味拾荒者 2024-08-05 02:49:18

function fromVectors(u, v) {

  d = dot(u, v)
  w = cross(u, v)

  return Quaternion(d + sqrt(d * d + dot(w, w)), w).normalize()
}

如果已知向量 u 到向量 v 单位向量,该函数简化为

function fromUnitVectors(u, v) {
  return Quaternion(1 + dot(u, v), cross(u, v)).normalize()
}

根据您的用例,可能需要处理点积为 1(平行向量)和 -1(指向相反方向的向量)时的情况。

One can rotate a vector u to vector v with

function fromVectors(u, v) {

  d = dot(u, v)
  w = cross(u, v)

  return Quaternion(d + sqrt(d * d + dot(w, w)), w).normalize()
}

If it is known that the vectors u to vector v are unit vectors, the function reduces to

function fromUnitVectors(u, v) {
  return Quaternion(1 + dot(u, v), cross(u, v)).normalize()
}

Depending on your use-case, handling the cases when the dot product is 1 (parallel vectors) and -1 (vectors pointing in opposite directions) may be needed.

捎一片雪花 2024-08-05 02:49:18

仅使用归一化四元数,我们可以用以下术语表达约瑟夫·汤普森的答案。

设 q_v = (0, u_x, v_y, v_z) 和 q_w = (0, v_x, v_y, v_z) 并考虑

q = q_v * q_w = (-u dot v, uxv)。

因此将 q 表示为 q(q_0, q_1, q_2, q_3) 我们有

q_r = (1 - q_0, q_1, q_2, q_3).normalize()

Working just with normalized quaternions, we can express Joseph Thompson's answer in the follwing terms.

Let q_v = (0, u_x, v_y, v_z) and q_w = (0, v_x, v_y, v_z) and consider

q = q_v * q_w = (-u dot v, u x v).

So representing q as q(q_0, q_1, q_2, q_3) we have

q_r = (1 - q_0, q_1, q_2, q_3).normalize()

等待我真够勒 2024-08-05 02:49:18

@RicharDunlap 是对的:解决方案有无数种。 而说“最小旋转”则不清楚。

但是有一个“规范”四元数,它将归一化向量u映射到归一化向量v。 准确地说,它将通过法向量u原点的平面映射到通过法向量v原点的平面。 这样的描述,可谓是独一无二。

这个四元数是:

re = sqrt((1 + sum(u*v))/2)
w = crossProduct(u, v) / 2 / re
q = (re, w[1], w[2], w[3])

@RicharDunlap is right: there's an infinity of solutions. And saying the "smallest rotation" is not clear.

But there is a "canonical" quaternion which maps a normalized vector u to a normalized vector v. Precisely, it maps the plane passing through the origin with normal vector u to the plane passing through the origin with normal vector v. With such a description, it is unique.

This quaternion is:

re = sqrt((1 + sum(u*v))/2)
w = crossProduct(u, v) / 2 / re
q = (re, w[1], w[2], w[3])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文