viktor-ferenczi / LookAtNanRepro

Console application to reproduce the issue when the calculation in MyTurretControlBlock.LookAt returns NaN in the X and Y components of the Vector3 returned.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MyTurretControlBlock.LookAt returns NaN

Summary

This is a .NET Framework 4.8 Console Application to reproduce the root cause of a crash bug in Space Engineers version 1.202.066.

Root Cause Analysis

Found the root cause of the problem in the MyTurretControlBlock.LookAt method by code review.

NaN results are produced in the X or Y components of the resulting Vector3 returned from MyTurretControlBlock.LookAt when the target is parallel or nearly parallel to the Up vector of the Elevator or the Azimuthor rotors respectively, but the ShootDirection is not parallel.

Test case decoupled from the game

Please edit and run the Edit-and-run-before-opening-solution.bat script before opening the solution. It will synlink the game's Bin64 folder, so the DLL dependencies can be found.

The calculation from the decompiled LookAt method has been copied into this console application to find actual examples when the calculation fails and produces NaN results. The test varies the ShootDirection from Up to slightly rotated around the Right axis. This simple test fails in 8 out of 10 cases.

The absolute value of the dot product used in your guarding conditions varies between 0.9998 and 0.99995. Even when the absolute value is less than 0.9999 the calculation can fail and produce NaN values on the following line:

Vector3 vector1 = Vector3.Normalize(vector2_1 - up * Vector3.Dot(up, vector2_1));

Inside the Normalize method there is a division by zero, resulting in an Infinity. Multiplying X, Y and Z by Infinity results in a vector full of NaN values.

This may happen both in the azimuthor and the elevator calculations.

Test output

OK: ShootDirection=(X:0 Y:1 Z:0) => {X:0 Y:0 Z:0}
OK: ShootDirection=(X:0 Y:0.999950000416665 Z:0.00999983333416666) => {X:0 Y:0 Z:0}
FAIL: ShootDirection=(X:0 Y:0.999800006666578 Z:0.0199986666933331) => {X:NaN Y:NaN Z:0}
FAIL: ShootDirection=(X:0 Y:0.999550033748988 Z:0.0299955002024957) => {X:NaN Y:NaN Z:0}
FAIL: ShootDirection=(X:0 Y:0.999200106660978 Z:0.0399893341866342) => {X:NaN Y:NaN Z:0}
FAIL: ShootDirection=(X:0 Y:0.998750260394966 Z:0.0499791692706783) => {X:NaN Y:NaN Z:0}
FAIL: ShootDirection=(X:0 Y:0.998200539935204 Z:0.0599640064794446) => {X:NaN Y:NaN Z:0}
FAIL: ShootDirection=(X:0 Y:0.99755100025328 Z:0.0699428473375328) => {X:NaN Y:NaN Z:0}
FAIL: ShootDirection=(X:0 Y:0.996801706302619 Z:0.0799146939691727) => {X:NaN Y:NaN Z:0}
FAIL: ShootDirection=(X:0 Y:0.995952733011994 Z:0.089878549198011) => {X:NaN Y:NaN Z:0}
Total: 10
Failed: 8
LowestAzimuthorAbsDotProduct = 0.999949991703033
HighestAzimuthorAbsDotProduct = 0.999800026416779
LowestElevatorAbsDotProduct = 0.999949991703033
HighestElevatorAbsDotProduct = 0.999800026416779

About

Console application to reproduce the issue when the calculation in MyTurretControlBlock.LookAt returns NaN in the X and Y components of the Vector3 returned.


Languages

Language:C# 97.7%Language:Batchfile 2.3%