gpt4 book ai didi

c++ - 围绕另一个 vector 旋转一个 vector

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:56:12 24 4
gpt4 key购买 nike

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

最佳答案

您可能会发现 quaternions成为更优雅、更高效的解决方案。


在最近看到这个答案出现问题后,我想我会提供一个更可靠的答案。无需理解四元数的全部数学含义即可使用的一种。我将假设(给定 C++ 标记)您有一个类似于 Vector3 类的东西,具有“明显”的功能,如 innercross , 和 *= 标量运算符等...

#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;
}

因此,在给定原始参数 (, v2, A) 的情况下,float quat[4] 拥有表示轴和旋转角度的单位四元数。

这是四元数乘法的例程。 SSE/SIMD 可能会加快速度,但复杂的变换和照明在大多数情况下通常由 GPU 驱动。如果您记得复数乘法有点奇怪,那么四元数乘法就更奇怪了。复数乘法是交换运算:a*b = b*a。四元数甚至不保留此属性,即 q*p != p*q :

static inline void
qmul (float r[4], const float q[4], const float p[4])
{
// quaternion multiplication: r = q * p

float w0 = q[3], w1 = p[3];
float x0 = q[0], x1 = p[0];
float y0 = q[1], y1 = p[1];
float z0 = q[2], z1 = p[2];

r[3] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
r[0] = w0 * x1 + x0 * w1 + y0 * z1 - z0 * y1;
r[1] = w0 * y1 + y0 * w1 + z0 * x1 - x0 * z1;
r[2] = w0 * z1 + z0 * w1 + x0 * y1 - y0 * x1;
}

最后,旋转 3D“vector ”v(或者,如果您愿意,也可以旋转问题命名为 v1 的“点”v ,表示为 vector ),使用四元数:float q[4] 有一个有点奇怪的公式:v' = q * v * conjugate(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 关键字。现代优化编译器可能会忽略 inline 提示,具体取决于它们自己的代码生成试探法。但让我们现在只关注正确性:

How do I rotate a vector v1 about another vector v2 by an angle A?

假设某种 Vector3 类,(A) 以弧度表示,我们需要四元数表示旋转角度 (A) 关于轴 v2,我们希望将四元数旋转应用到 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 文档站点中看到的扩展内容吗?我不太清楚它的要求、预期的严谨性等。

关于c++ - 围绕另一个 vector 旋转一个 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7582398/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com