3

私はクォータニオン 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 ) );
}

少し気になるのは、次の 2 行です。

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が何もしていない場合、その目的は何ですか?

何か不足していますか?

編集:ソースコードの元となった2つのファイルは次のとおりです

4

2 に答える 2

3

ここで混乱したのは、が 4 の倍数でない場合に TRUE と評価されるため、4の倍数((i)%4)以外の場合は を取得し、それ以外の場合は元のベクトルを取得するだけだと思います (4 の倍数による回転は no であるため) -op)。i_mm_shuffle_ps

役に立つかもしれないいくつかの背景:

vec_XXXマクロは、このコードがもともと PowerPC/AltiVec から移植されたことを示しています。指定されたバイトvec_sld数だけベクトルのペアをシフトする AltiVec 組み込み関数です。このコンテキストでは、2 つの入力ベクトルが同じであるため、1 つのベクトルを回転するために が使用されているように見えます。また、12 がバイトシフトとして渡されているように見えます (つまり、3 つの float による回転)。vec_sld

したがって、 =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);

そのため、コードが正しいことを行っているように見えます。

于 2013-10-03T12:41:31.227 に答える
1

参照用に Eigen の実装を調べることもできます。

https://bitbucket.org/eigen/eigen/src/671989a04734c8e34065d800a89c0d518c8b1821/Eigen/src/Geometry/arch/Geometry_SSE.h?at=default

于 2015-07-31T14:12:24.827 に答える