【发布时间】:2014-04-25 04:19:42
【问题描述】:
我的数学库需要一个更快的四元数向量乘法例程。现在我正在使用规范的v' = qv(q^-1),它产生的结果与将向量乘以由四元数组成的矩阵的结果相同,所以我相信它的正确性。
到目前为止,我已经实现了 3 种“更快”的替代方法:
#1,我不知道我是从哪里得到这个的:
v' = (q.xyz * 2 * dot(q.xyz, v)) + (v * (q.w*q.w - dot(q.xyz, q.zyx))) + (cross(q.xyz, v) * q.w * w)
实现为:
vec3 rotateVector(const quat& q, const vec3& v)
{
vec3 u(q.x, q.y, q.z);
float s = q.w;
return vec3(u * 2.0f * vec3::dot(u, v))
+ (v * (s*s - vec3::dot(u, u)))
+ (vec3::cross(u, v) * s * 2.0f);
}
#2,感谢this fine blog
t = 2 * cross(q.xyz, v);
v' = v + q.w * t + cross(q.xyz, t);
实现为:
__m128 rotateVector(__m128 q, __m128 v)
{
__m128 temp = _mm_mul_ps(vec4::cross(q, v), _mm_set1_ps(2.0f));
return _mm_add_ps(
_mm_add_ps(v, _mm_mul_ps(_mm_shuffle_ps(q, q, _MM_SHUFFLE(3, 3, 3, 3)), temp)),
vec4::cross(q, temp));
}
而#3,来自众多来源,
v' = v + 2.0 * cross(cross(v, q.xyz) + q.w * v, q.xyz);
实现为:
__m128 rotateVector(__m128 q, __m128 v)
{
//return v + 2.0 * cross(cross(v, q.xyz) + q.w * v, q.xyz);
return _mm_add_ps(v,
_mm_mul_ps(_mm_set1_ps(2.0f),
vec4::cross(
_mm_add_ps(
_mm_mul_ps(_mm_shuffle_ps(q, q, _MM_SHUFFLE(3, 3, 3, 3)), v),
vec4::cross(v, q)),
q)));
}
所有这 3 个都会产生不正确的结果。然而,我注意到一些有趣的模式。首先,#1 和#2 产生相同的结果。 #3 产生的结果与我将向量乘以派生矩阵得到的结果相同,如果所述矩阵被转置(我偶然发现了这一点,以前我的四元矩阵代码假设行主矩阵,这是不正确的)。
我的四元数的数据存储定义为:
union
{
__m128 data;
struct { float x, y, z, w; };
float f[4];
};
我的实现是否有缺陷,或者我在这里遗漏了什么?
【问题讨论】:
-
为什么需要它更快?您是否表明这是代码中的瓶颈?你能更详细地描述你在做什么吗?如果你需要计算多个独立的四元数,那么 SIMD(如果你做得对的话)可能会快得多。但是,如果您要计算依赖四元数链,那么 SIMD 实际上可能会更糟。
-
我需要它更快,因为我使用四元数无处不在,包括在 glsl 中。我现在不关心 simd 与非 simd,问题是替代算法根本不起作用。
-
我发现了一个问题,#1 和 #2 具有相同的名称,即使我想使用 #2,它也会错误地将四元数转换为使用 #1。 #2 实际上产生了正确的结果,目前是我最快的实现。现在我只需要一个可以在 glsl 中运行的版本。
-
我还能够通过更改叉积的顺序使#3 工作。
标签: c++ vector matrix sse quaternions