About the stability of matrix inverses in DirectX9

Started by
9 comments, last by galop1n 7 years, 1 month ago

D3DXMatrixInverse(&worldInv, NULL, &l_transform->getWorldMatrix());

When I calculate the above math using matrix inverses,
even though the world matrix is at identity,
the outcome is still a bit off from standard 1.0,
looks like some floating point errors....
0.9999 on the diagonal or something

How do I eliminate those instabilities? does the determinant play a role in there?
Thanks
Jack
Advertisement

How do I eliminate those instabilities? does the determinant play a role in there?

There's something you're supposed to never do, due to floating point inaccuracies. Unfortunately, i don't recall exactly what it was, transpose, inverse - don't think its determinant. think it was inverse.

The workaround is you don't use it, you use something else. i know - rather vague.

I just don't remember my Linear well enough. Transpose swaps elements (?), determinant results in a scalar (?), and invert has rounding errors (?). something like that...

Alvaro or somebody will know what the answer is.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

I don't know how D3D implements the inverse. I think every implementation of matrix inverse I have worked with would give you the identity matrix exactly as the inverse of the identity matrix.

However, your code should probably be robust enough to withstand this difference. What are you using the inverse of the world matrix for?

Ok, now you've got me curious...

I know i heard somewhere that one of them had issues. One that i don't use.

Let me do some googling.


well, i found this, but that's not where i heard about it....

https://www.johndcook.com/blog/2010/01/19/dont-invert-that-matrix/

not finding much else.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

In computer science 1 == 0.9999 because you never compare two floating point value unless you use an epsilon isequal( float a, float b) { return abs(a-b) < epsilon; }.

What is important is to not accumulate rounding error over time, this is the only metric that matters, and if in an application you care about precision that much, you move to fixed point math, but this is not what you want here.

Hi there, I am hashing the local position, that is, I had multiple objects in my scene,

when I query the navigation system, I give the world position to it and the object's world matrix,

I multiply the position to the inverse of the world matrix give me the base of the hash, however,

the ground is extremely thin and sensitive, when it is off by 0.1, the hash gives me back a null pointer.

You can just quantize the position, if you rely on floating point value to match, you fall exactly in the case i describe, equality of floating points need an epsilon

Looks like dx9 probably uses Gaussian elimination to invert a matrix. And that means floating point division, and that means rounding errors.

As you can see, using a floating point value as a hash key is probably not a good idea.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Direct3D 9 changes the floating-point mode to single-precision and round-to-nearest unless you specify D3DCREATE_FPU_PRESERVE in IDirect3D9::CreateDevice().
By passing this flag and setting your own floating-point mode in the compiler options you may get different results here.

But as mentioned you should never write code that relies on that level of precision as it will never be robust.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

In computer science 1.0 == 0.9999 because you never compare two floating point value unless you use an epsilon isequal( float a, float b) { return abs(a-b) < epsilon; }.

That is entirely dependent on the size/precision of the floating point numbers being used.

With the following code:


int _tmain(int argc, _TCHAR* argv[])
{
    float test = 1.0f;
    if( test == 0.99999999f )
    {
        printf( "Test One!");
    }

    if( test == 0.9999f )
    {
        printf( "Test Two!");
    }

    return 0;
}

Will output:


  Test One!

The second 'if' statement will fail to execute the contained code.

You can definitely use an epsilon to mitigate the problem, but you have to keep in mind that the epsilon needs to scale with the floating point numbers you use... the larger the 'real' component of the float, the larger the required epsilon.

This topic is closed to new replies.

Advertisement