[ODE] Accuracy / FPU stuff

Pierre Terdiman p.terdiman at wanadoo.fr
Tue Jul 8 03:42:01 2003


>    Is there some good reason for this, or is this just that OPCODE uses
> single internally and doesn't have a switch (i.e., will OPCODE break if
> I make it "use double and memory use be damned"?)

Let's make it clear....

There are two different issues here :

1) Using "float" instead of "double", mainly OPCODE vs ODE :

OPCODE really doesn't need double precision :

- if you're using quantized trees, nodes don't even contain a single
floating-point value. So you won't "damn the memory use" by using "double".

- if you're using non-quantized trees, nodes contain floating-point values
for bounding boxes. However those are only bounding boxes which are *not*
supposed to be accurate in the first place. Using "double" here will indeed
increase memory usage, *and be totally, definitely useless*.

- the actual client mesh is *not* stored in OPCODE's structures, I'm only
using indices to get those back. So I don't really care how you store your
meshes (floats or doubles) as far as computations are concerned. The only
thing that needs fixing if your meshes are stored in "double", is the
MeshInterface, because it expects float pointers in return. This is probably
where all the problems are coming from : if you cast your double-precision
points to float in OPCODE's callbacks for example, it obviously won't work,
and collisions won't be detected indeed.

Using callbacks, a possible fix would be to convert each requested triangle
to floats on-the-fly, and return pointers to the converted triangle to
OPCODE. As long as you don't use multiple threads doing simultaneous
collision queries, it should work fine.

Now I seriously doubt you need double-precision meshes. In particular,
they're probably single-precision to begin with, out of your favorite
modeling package (3DSMAX, etc). So you should keep them single-precision,
use OPCODE's pointers (possibly with a stride), and convert the floats to
doubles for ODE's computations, if needed. But even this is probably dubious
: doubles are useful in big and intensive matrix computations, but that's
about it. My own rigid body code uses plain floats all the way without
troubles, for example.

I'm also using D3D, which brings up the second issue :

2) the *internal* FPU accuracy and D3D's D3DCREATE_FPU_PRESERVE

The nature of your floating-point values ("float" or "double") is only half
the story. Using "float" for example, you still have multiple choices
regarding the *internal* FPU precision. This is controlled by the FPU
control word, and can't be accessed / modified through C.

The D3D flag only changes this internal accuracy as far as I know. They
don't use "double" inside, that would be ridiculous, especially since :

- you only store 32-bits floats in your vertex buffer anyway
- the hardware certainly doesn't have two code paths for two different
pipelines, it would be twice as much gates for nothing !

I believe this flag only changes only very few things, and mainly related to
the software rendering mode. There have been a number of threads about this
on the DXML in the past.

Now I've seen cases where *internal* FPU precision was modified by D3D init
*even* with that flag on. It might also change the FPU rounding mode, which
is a problem when you compile with /QIfist on VC++ 6 (for fast float-to-int
conversions).

On top of this, D3D *isn't* the only thing changing the FPU settings
silently. A classical other example is LoadLibrary.

In summary, assuming the FPU is correctly setup is a recipe for disaster.
(Never assume anything, as always)

What I do then is very simple :
- initialize D3D the normal way, without the FPU flag
- explicitely reset the FPU control word to what I want, each frame (it's
very cheap, no problem)

For what it's worth, my rigid body simulation uses "floats" all the way with
the smallest internal accuracy, and renders the scene with D3D or GL just
fine.

Pierre