首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DirectXMath向量运算精度

DirectXMath向量运算精度
EN

Stack Overflow用户
提问于 2013-02-11 21:25:18
回答 1查看 1.3K关注 0票数 1

我得到了XMVector3AngleBetweenVectors函数的奇怪结果。考虑下面的代码:

代码语言:javascript
复制
float angle = XMConvertToDegrees(XMVectorGetX(
        XMVector3AngleBetweenVectors(GMathFV(XMFLOAT3(0.0f, 100.0f, 0.0f)), 
        GMathFV(XMFLOAT3(0.0f, 200.0f, 0.0f)))));

它寻找两个3D矢量之间的角度,由XMFLOAT3结构描述。GMathFV是用户定义的函数,用于将XMFLOAT3转换为XMVECTOR,如下所示:

代码语言:javascript
复制
inline XMVECTOR GMathFV(XMFLOAT3& val)
{
    return XMLoadFloat3(&val);    
}

其他的都是directxmath.h库。这里一切都很好,结果角度是0.00000,正如预期的那样。

但是对于y轴值为负的其他向量,例如:

代码语言:javascript
复制
float angle = XMConvertToDegrees(XMVectorGetX(
        XMVector3AngleBetweenVectors(GMathFV(XMFLOAT3(0.0f, -100.0f, 0.0f)), 
        GMathFV(XMFLOAT3(0.0f, -99.0f, 0.0f)))));

结果是0.0197823402,我很难称之为零角度。

请谁来帮我弄清楚这个问题。它是负数精度,矢量坐标太接近还是其他什么?

UPD:太棒了,但它为a(0.0f, 100.0f, 0.0f) x b(0.0f, 99.0f, 0.0f)提供了0.0197823402,而为a(0.0f, 101.0f, 0.0f) x b(0.0f, 100.0f, 0.0f)提供了0.000000

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-05-14 00:32:57

DirectXMath是为32位浮点数学设计的。你看到的是floating point error升级。下面是XMVector3AngleBetweenVectors的定义。

代码语言:javascript
复制
inline XMVECTOR XM_CALLCONV XMVector3AngleBetweenVectors(FXMVECTOR V1, FXMVECTOR V2)
{
    XMVECTOR L1 = XMVector3ReciprocalLength(V1);
    XMVECTOR L2 = XMVector3ReciprocalLength(V2);

    XMVECTOR Dot = XMVector3Dot(V1, V2);

    L1 = XMVectorMultiply(L1, L2);

    XMVECTOR CosAngle = XMVectorMultiply(Dot, L1);
    CosAngle = XMVectorClamp(CosAngle, g_XMNegativeOne.v, g_XMOne.v);

    return XMVectorACos(CosAngle);
}

在第一个示例中,CosAngle等于1.000000000

在第二个示例中,CosAngle等于0.999999940

XMVectorACos(0.999999940) = 0.000345266977

这个大的误差来自于ACos的多项式近似。一般来说,只要有可能,你就应该避免三角求逆。他们很慢,而且很吵。下面是它的定义,这样你就可以了解它的大小了。

代码语言:javascript
复制
inline XMVECTOR XM_CALLCONV XMVectorACos (FXMVECTOR V)
{
    __m128 nonnegative = _mm_cmpge_ps(V, g_XMZero);
    __m128 mvalue = _mm_sub_ps(g_XMZero, V);
    __m128 x = _mm_max_ps(V, mvalue);  // |V|

    // Compute (1-|V|), clamp to zero to avoid sqrt of negative number.
    __m128 oneMValue = _mm_sub_ps(g_XMOne, x);
    __m128 clampOneMValue = _mm_max_ps(g_XMZero, oneMValue);
    __m128 root = _mm_sqrt_ps(clampOneMValue);  // sqrt(1-|V|)

    // Compute polynomial approximation
    const XMVECTOR AC1 = g_XMArcCoefficients1;
    XMVECTOR vConstants = XM_PERMUTE_PS( AC1, _MM_SHUFFLE(3, 3, 3, 3) );
    __m128 t0 = _mm_mul_ps(vConstants, x);

    vConstants = XM_PERMUTE_PS( AC1, _MM_SHUFFLE(2, 2, 2, 2) );
    t0 = _mm_add_ps(t0, vConstants);
    t0 = _mm_mul_ps(t0, x);

    vConstants = XM_PERMUTE_PS( AC1, _MM_SHUFFLE(1, 1, 1, 1) );
    t0 = _mm_add_ps(t0, vConstants);
    t0 = _mm_mul_ps(t0, x);

    vConstants = XM_PERMUTE_PS( AC1, _MM_SHUFFLE(0, 0, 0, 0) );
    t0 = _mm_add_ps(t0, vConstants);
    t0 = _mm_mul_ps(t0, x);

    const XMVECTOR AC0 = g_XMArcCoefficients0;
    vConstants = XM_PERMUTE_PS( AC0, _MM_SHUFFLE(3, 3, 3, 3) );
    t0 = _mm_add_ps(t0, vConstants);
    t0 = _mm_mul_ps(t0, x);

    vConstants = XM_PERMUTE_PS( AC0, _MM_SHUFFLE(2, 2, 2, 2) );
    t0 = _mm_add_ps(t0, vConstants);
    t0 = _mm_mul_ps(t0, x);

    vConstants = XM_PERMUTE_PS( AC0, _MM_SHUFFLE(1, 1, 1, 1) );
    t0 = _mm_add_ps(t0, vConstants);
    t0 = _mm_mul_ps(t0, x);

    vConstants = XM_PERMUTE_PS( AC0, _MM_SHUFFLE(0, 0, 0, 0) );
    t0 = _mm_add_ps(t0, vConstants);
    t0 = _mm_mul_ps(t0, root);

    __m128 t1 = _mm_sub_ps(g_XMPi, t0);
    t0 = _mm_and_ps(nonnegative, t0);
    t1 = _mm_andnot_ps(nonnegative, t1);
    t0 = _mm_or_ps(t0, t1);
    return t0;
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14812925

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档