Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 围绕另一个向量旋转一个向量_C++_Math_Vector_3d_Rotation - Fatal编程技术网

C++ 围绕另一个向量旋转一个向量

C++ 围绕另一个向量旋转一个向量,c++,math,vector,3d,rotation,C++,Math,Vector,3d,Rotation,我正在为OpenGL编写一个3d矢量类。如何将一个向量v1围绕另一个向量v2旋转一个角度a?使用a。最容易理解的方法是旋转坐标轴,使向量v2与Z轴对齐,然后围绕Z轴旋转a,然后向后旋转,使Z轴与v2对齐 当您写下这三个操作的旋转矩阵时,您可能会注意到,您会依次应用三个矩阵。为了达到同样的效果,您可以将三个矩阵相乘。您可能会发现这是一个更优雅、更有效的解决方案 在最近看到这个答案的颠簸之后,我想我应该提供一个更有力的答案。一种不用理解四元数的全部数学含义就可以使用的方法。我假设(给定C++标签)

我正在为OpenGL编写一个3d矢量类。如何将一个向量v1围绕另一个向量v2旋转一个角度a?

使用a。

最容易理解的方法是旋转坐标轴,使向量v2与Z轴对齐,然后围绕Z轴旋转a,然后向后旋转,使Z轴与v2对齐

当您写下这三个操作的旋转矩阵时,您可能会注意到,您会依次应用三个矩阵。为了达到同样的效果,您可以将三个矩阵相乘。

您可能会发现这是一个更优雅、更有效的解决方案


在最近看到这个答案的颠簸之后,我想我应该提供一个更有力的答案。一种不用理解四元数的全部数学含义就可以使用的方法。我假设(给定C++标签)你有一个类似于<代码>向量3>代码>类,具有“代码”>“内部< /代码>”、“代码>交叉<代码>、<代码> *= <代码>标量运算符等…

#include <cfloat>
#include <cmath>

...

void make_quat (float quat[4], const Vector3 & v2, float angle)
{
    // BTW: there's no reason you can't use 'doubles' for angle, etc.
    // there's not much point in applying a rotation outside of [-PI, +PI];
    // as that covers the practical 2.PI range.

    // any time graphics / floating point overlap, we have to think hard
    // about degenerate cases that can arise quite naturally (think of
    // pathological cancellation errors that are *possible* in seemingly
    // benign operations like inner products - and other running sums).

    Vector3 axis (v2);

    float rl = sqrt(inner(axis, axis));
    if (rl < FLT_EPSILON) // we'll handle this as no rotation:
    {
        quat[0] = 0.0, quat[1] = 0.0, quat[2] = 0.0, quat[3] = 1.0;
        return; // the 'identity' unit quaternion.
    }

    float ca = cos(angle);

    // we know a maths library is never going to yield a value outside
    // of [-1.0, +1.0] right? Well, maybe we're using something else -
    // like an approximating polynomial, or a faster hack that's a little
    // rough 'around the edge' cases? let's *ensure* a clamped range:
    ca = (ca < -1.0f) ? -1.0f : ((ca > +1.0f) ? +1.0f : ca);

    // now we find cos / sin of a half-angle. we can use a faster identity
    // for this, secure in the knowledge that 'sqrt' will be valid....

    float cq = sqrt((1.0f + ca) / 2.0f); // cos(acos(ca) / 2.0);
    float sq = sqrt((1.0f - ca) / 2.0f); // sin(acos(ca) / 2.0);

    axis *= sq / rl; // i.e., scaling each element, and finally:

    quat[0] = axis[0], quat[1] = axis[1], quat[2] = axis[2], quat[3] = cq;
}
最后,使用四元数:
float q[4]
旋转一个3D“向量”(或者如果您愿意,问题命名为
v1
,表示为向量的“点”
v
),有一个有点奇怪的公式:
v'=q*v*共轭(q)
。四元数有共轭,类似于复数。下面是例行公事:

static inline void
qrot (float v[3], const float q[4])
{
    // 3D vector rotation: v = q * v * conj(q)

    float r[4], p[4];

    r[0] = + v[0], r[1] = + v[1], r[2] = + v[2], r[3] = +0.0;
    glView__qmul(r, q, r);

    p[0] = - q[0], p[1] = - q[1], p[2] = - q[2], p[3] = q[3];
    glView__qmul(r, r, p);

    v[0] = r[0], v[1] = r[1], v[2] = r[2];
}

把它们放在一起。显然,您可以在适当的地方使用
static
关键字。现代优化编译器可能会忽略
内联
提示,这取决于它们自己的代码生成试探法。但现在让我们只关注正确性:

如何将一个向量v1围绕另一个向量v2旋转一个角度a

假设某种
Vector3
类,以及
(A)
弧度,我们想要四元数表示绕轴
v2
旋转的角度
(A)
,并且我们想要将该四元数旋转应用到
v1
,以得到以下结果:

float q[4]; // we want to find the unit quaternion for `v2` and `A`...

make_quat(q, v2, A);

// what about `v1`? can we access elements with `operator [] (int)` (?)
// if so, let's assume the memory: `v1[0] .. v1[2]` is contiguous.
// you can figure out how you want to store and manage your Vector3 class.

qrot(& v1[0], q);

// `v1` has been rotated by `(A)` radians about the direction vector `v2` ...

这是人们希望在Beta文档站点中看到的扩展吗?我不完全清楚它的要求、预期的严格性等。

我在这里发现:

矩阵运算给出:

[v] = [v]x{[i] + sin(a)/d*[L] + ((1 - cos(a))/(d*d)*([L]x[L]))} 
我编写了自己的Matrix3类和Vector3库,实现了这个向量旋转。它工作得绝对完美。我使用它来避免在相机视野之外绘制模型

我想这就是“使用3d旋转矩阵”的方法。我快速地看了一眼四元数,但从未使用过它们,所以我坚持使用一些我可以绕着头看的东西。

这可能会很有用:

double c = cos(A);
double s = sin(A);
double C = 1.0 - c;

double Q[3][3];
Q[0][0] = v2[0] * v2[0] * C + c;
Q[0][1] = v2[1] * v2[0] * C + v2[2] * s;
Q[0][2] = v2[2] * v2[0] * C - v2[1] * s;

Q[1][0] = v2[1] * v2[0] * C - v2[2] * s;
Q[1][1] = v2[1] * v2[1] * C + c;
Q[1][2] = v2[2] * v2[1] * C + v2[0] * s;

Q[2][0] = v2[0] * v2[2] * C + v2[1] * s;
Q[2][1] = v2[2] * v2[1] * C - v2[0] * s;
Q[2][2] = v2[2] * v2[2] * C + c;

v1[0] = v1[0] * Q[0][0] + v1[0] * Q[0][1] + v1[0] * Q[0][2];
v1[1] = v1[1] * Q[1][0] + v1[1] * Q[1][1] + v1[1] * Q[1][2];
v1[2] = v1[2] * Q[2][0] + v1[2] * Q[2][1] + v1[2] * Q[2][2];

你说的“沿着”向量旋转是什么意思?我是说“反对”或“围绕”,对不起,我的英语很差。我建议你阅读3d数学入门书,而不是每次发现问题都在这里问这样的问题。一个非常好的主题介绍是+1:我个人认为这是最好的方法,原因有很多。可惜你没有早点回答,你可能是被选中的答案。我不会投反对票,但这太复杂了。一个更简单的解决方案,我认为实际上更容易理解(但那只是我自己),就是使用Brett Hale建议的基于四元数的方法。@andand:四元数很好也很简单,当然,一旦你理解了四元数。OP似乎对普通的3D线性代数有困难,目前四元数在阶梯上的位置可能太高了三步。我不知道这是错误的,但这一步产生了错误的结果。这个答案是根据
[v] = [v]x{[i] + sin(a)/d*[L] + ((1 - cos(a))/(d*d)*([L]x[L]))} 
double c = cos(A);
double s = sin(A);
double C = 1.0 - c;

double Q[3][3];
Q[0][0] = v2[0] * v2[0] * C + c;
Q[0][1] = v2[1] * v2[0] * C + v2[2] * s;
Q[0][2] = v2[2] * v2[0] * C - v2[1] * s;

Q[1][0] = v2[1] * v2[0] * C - v2[2] * s;
Q[1][1] = v2[1] * v2[1] * C + c;
Q[1][2] = v2[2] * v2[1] * C + v2[0] * s;

Q[2][0] = v2[0] * v2[2] * C + v2[1] * s;
Q[2][1] = v2[2] * v2[1] * C - v2[0] * s;
Q[2][2] = v2[2] * v2[2] * C + c;

v1[0] = v1[0] * Q[0][0] + v1[0] * Q[0][1] + v1[0] * Q[0][2];
v1[1] = v1[1] * Q[1][0] + v1[1] * Q[1][1] + v1[1] * Q[1][2];
v1[2] = v1[2] * Q[2][0] + v1[2] * Q[2][1] + v1[2] * Q[2][2];