【问题标题】:Bullet Physics quaternion sse implementation doubtsBullet Physics 四元数 sse 实现的疑惑
【发布时间】:2013-10-03 12:14:58
【问题描述】:

我正在研究四元数 SSE 实现以了解它们是如何工作的(因为我正在实现自己的)并且我遇到了这个用于四元数乘法的 Bullet 实现:

VECTORMATH_FORCE_INLINE const Quat Quat::operator *( const Quat &quat ) const
{
    __m128 ldata, rdata, qv, tmp0, tmp1, tmp2, tmp3;
    __m128 product, l_wxyz, r_wxyz, xy, qw;
    ldata = mVec128;
    rdata = quat.mVec128;
    tmp0 = _mm_shuffle_ps( ldata, ldata, _MM_SHUFFLE(3,0,2,1) );
    tmp1 = _mm_shuffle_ps( rdata, rdata, _MM_SHUFFLE(3,1,0,2) );
    tmp2 = _mm_shuffle_ps( ldata, ldata, _MM_SHUFFLE(3,1,0,2) );
    tmp3 = _mm_shuffle_ps( rdata, rdata, _MM_SHUFFLE(3,0,2,1) );
    qv = vec_mul( vec_splat( ldata, 3 ), rdata );
    qv = vec_madd( vec_splat( rdata, 3 ), ldata, qv );
    qv = vec_madd( tmp0, tmp1, qv );
    qv = vec_nmsub( tmp2, tmp3, qv );
    product = vec_mul( ldata, rdata );
    l_wxyz = vec_sld( ldata, ldata, 12 );
    r_wxyz = vec_sld( rdata, rdata, 12 );
    qw = vec_nmsub( l_wxyz, r_wxyz, product );
    xy = vec_madd( l_wxyz, r_wxyz, product );
    qw = vec_sub( qw, vec_sld( xy, xy, 8 ) );
        VM_ATTRIBUTE_ALIGN16 unsigned int sw[4] = {0, 0, 0, 0xffffffff};
    return Quat( vec_sel( qv, qw, sw ) );
}

我比较关心的是这两行:

l_wxyz = vec_sld( ldata, ldata, 12 );
r_wxyz = vec_sld( rdata, rdata, 12 );

宏实现:

#define _mm_ror_ps(vec,i)       \
    (((i)%4) ? (_mm_shuffle_ps(vec,vec, _MM_SHUFFLE((unsigned char)(i+3)%4,(unsigned char)(i+2)%4,(unsigned char)(i+1)%4,(unsigned char)(i+0)%4))) : (vec))

#define vec_sld(vec,vec2,x) _mm_ror_ps(vec, ((x)/4))

如果我理解正确,对于一个不能被 4 整除的数字(3 不是 [12/4 = 3]),vec_sld 宏将简化为:

l_wxyz = ldata;//vec_sld( ldata, ldata, 12 );
r_wxyz = rdata;//vec_sld( rdata, rdata, 12 );

实际上什么都不做。

如果该值能被 4 整除:

q = vec_sld( x, x, 16 );

宏将缩减为:

q = _mm_shuffle_ps( x, x, _MM_SHUFFLE(3,2,1,0) );

同样,这就像什么都不做,因为 _MM_SHUFFLE(3,2,1,0) 将 x、y、z 和 w 留在当前位置。

如果 vec_sld 什么都不做,它的目的是什么?

我错过了什么吗?

编辑:这是源代码来自的两个文件

【问题讨论】:

  • 你能告诉我们你在哪里找到这个代码吗?
  • 我已经编辑了帖子,其中包含指向子弹物理相关源代码的链接。

标签: math x86 sse simd quaternions


【解决方案1】:

我认为您在这里感到困惑的是,当i 不是 4 的倍数时,((i)%4) 的计算结果为 TRUE,因此您会得到一个非 4 的倍数的 _mm_shuffle_ps,否则你只会得到原始向量(因为旋转 4 的倍数是无操作的)。

一些可能有用的背景:

vec_XXX 宏表示此代码最初是从 PowerPC/AltiVec 移植的。 vec_sld 是一个 AltiVec 内在函数,它将一对向量移动给定数量的 字节。在这种情况下,vec_sld 似乎被用于旋转单个向量,因为两个输入向量是相同的,并且似乎 12 作为 byte 移位传递(即旋转3 个浮点数)。

所以vec_sld(v, v, 12) 被翻译成_mm_ror_ps(v, 12/4) = _mm_ror_ps(v, 3) 然后扩展为:

_mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 1, 0, 3);

所以它看起来好像代码在做正确的事情。

【讨论】:

  • 没错!事实上,我对((i)%4) ? 感到困惑。我正在手动进行一些测试,但我忽略了它实际上对所有正确的情况都进行了评估。谢谢!
【解决方案2】:
猜你喜欢
  • 1970-01-01
  • 2016-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
  • 2013-01-07
相关资源
最近更新 更多