Jump to content

[SOLVED] Behaviour of getIntersection() on x64 platform


Recommended Posts

Just a quick question: is there a difference in the accuracy of engine.world.getIntersection() in the x64 version of Unigine compared to the 32bit version? I wouldn't really have expected there to be, but it seems as if a ray I'm casting is "slipping between the cracks" of two adjacent triangles (i.e. getIntersection() fails) when using the x64 version, but the same data on the x86 build returns a successful intersection.

Link to comment

There is no explicit difference between x86 and x64 32-bit float precision, but compiler-specific implementations (data type conversions, rounding modes, etc) of math libraries might lead to very small numerical differences for your calculation results.

 

The effect that some raycasts (e.g. height above terrain/laser range in simulation context) on triangle edges do not hit any of both triangles is some ugly numerical issue, but more or less unavoidable. One way of ensuring stable results is to cast more than one ray (e.g. up to 3 or some configurable maximum) with very small angular jittering in case the previous ray didn't hit anything. If all rays give no hit result than there is really no hit with your world geometry.

Link to comment

Hi, Can you please explain these compiler/SSE assumptions? As someone who has worked on a multitude of platforms (SGI, PS2, Xbox, GC, GBA, DS, etc etc etc) and a truckload of compilers as well I do not understand your statement - "Can be caused by x64 compiler using SSE instructions, which decreases precision.". A simple code example would be ideal.

 

As far as I know by my own experience and what IEEE spec tells me. Single and Double precision floating point numbers will be consistent no matter what IEEE hardware you use (this is the reason for the spec). The compiler for X64 and SSE are IEEE 754 spec and this means the maths for the double arithmetic cannot deviate (based on the spec). If you are using something OTHER than standard doubles or single floats then YES you will have a multitude of problems. But I hope this isn't the case. If you are referring to internal hardware precision, then read the link below - yes there are internal precision problems if you use certain types of NON spec types. But as the author states below, you should be fine if you use Single and Double precision standard formats.

 

Additionally you will obviously run into troubles if you are casting between 32 and 64 bit - but that is a design problem not a hardware one.

 

Detailed breakdown of floating point problems on different hardware and compilers.

http://www.christian-seiler.de/projekte/fpmath/

 

"Using single or double precision for floating point calculations seems to be the only portable alternative without using an entire library."

The author provides code on how to ensure your double precision is maintained. If you are using external libs that are causing your problems, then I would highly recommend replacing them, or contacting the authors to fix it.

 

Btw I think the above external lib problem is what ulf.schroeter was referring to with "compiler-specific implementations (data type conversions, rounding modes, etc) of math libraries". But again, I would hope the math libs being used are robust and double compliant? I know even one little double->float cast can cause exactly these problems.

 

Back to solving the problem, If casting multiple rays is a suggested solve, I think this may be limiting (Classically vehicle wheel raycasting will need to be accurate and fast to match our CarSim model) - if the casting point is very close to the object (we cannot _know_ where the object is, since this is why we are doing a raycast), then the cast will still fail. By making the raycast spread too wide will make the detection incorrect (especially for force and friction simulation). Are there any other suggestions to improve this issue? Is there a way you can 'fatten' your polygon collision routines? What collision system are you using to do this (poly soup, structured.. etc) can it be patched to improve the correctness?

 

Is this behavior expected on a mesh strip? This is where it is happening.

Link to comment

By default I would've expected both the x87 FPU and SSE2 to use double precision (not extended double), which should give deterministic behaviour on both platforms (I'm assuming you've enabled SSE2 instructions in your 32bit build)?

Link to comment
  • 3 weeks later...

Also, can you recommend some compiler settings (for MSVC++) that we can use with our libraries to ensure we don't mess with the floating point behaviour you're expecting?

Link to comment
  • 3 weeks later...

You can rebuild the engine with different /fp: flags. We are using /fp:fast flag because of substantially higher performance. You can try to use /fp:precise or /fp:strict flags in your custom builds. But usually /fp:fast flag grants enough precision, so we didn't have any stability problems with physics while using it on x86 and x64 windows builds.

Link to comment

just coming back to the initial problem of sporadic failing intersection test on triangle edges: different fpu precision settings might reduce probability of this problem, but still it will happen due to the nature of floating point precision/inprecision.

 

If you really want to avoid it you will need the described small jittering (e.g. +/- 1cm max) of your test ray origin in case of an initial test failure. Even this approach is a best-effort test from a formal point of view, but in practice it solved all our intersection problems. Of course there should be an upper limit for jittered ray casts (e.g. 3) in case there is really no intersection. While this first sounds bad from a performance perspective, in practice it isn't, as most intersection testing (e.g. for wheels) will stop after the first test.

 

BTW intersection testing on a single ObjectTerrain instance does not suffer from this problem by design (though it can happen in your case at edges of multiple adjacent ObjectTerrain instances) and is also very fast compared to triangle mesh intersection testing.

 

If intersection testing really gets a performance bottleneck in most cases its possible to spread testing over several frames and/or doing it in world::flush() in parallel to rendering. If even this reaches a performance limit than a different specialized approach for more efficient intersection testing (e.g. optimized for large-number nearby wheel intersection testing required for tank track simulation) can be implemented, but this will require source code modifications.

Link to comment
×
×
  • Create New...