Open bulsatar opened 1 year ago
I think I identified where the floating point errors come into play but I have no idea how to fix them. code path: core => math => node_2d.cpp -> set_rotation_degrees (transforms degrees to radians) -> set_rotation -> _update_transform => core => math => transform_2d.h -> set_rotation_scale_and_skew
that last function does matrix transformations on the radians that were converted and looks like applies a standard box transform while adjusting for scale and skew. The cos/sin * scale is probably where the floating point errors are being introduced as there doesn't seem to be a constraint on the resulting floats.
I am not sure if it is possible as matrix transformations are definitely not my wheelhouse, but what would the ramifications be if those calculations were rounded to some nth decimal? Looks like floats are guaranteed to 7 digits and doubles to 15. Maybe that could be the default clamp size? I am just getting into game development so not sure what locking that down would affect.
Would it be worth a setting at the project level for maths accuracy? passing a constraint all the way down that tree would probably introduce too much change at such a core level.
void Transform2D::set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew) {
columns[0][0] = Math::cos(p_rot) * p_scale.x;
columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
columns[0][1] = Math::sin(p_rot) * p_scale.x;
Godot version
v4.1.1.stable.mono.official [bd6af8e0e]
System information
Godot v4.1.1.stable.mono - Linux Mint 21.1 (Vera) - Vulkan (Compatibility) - NVIDIA GeForce RTX 3060 Ti (nvidia; 525.125.06) - AMD Ryzen 7 5800X 8-Core Processor (16 Threads)
Issue description
When rotating Node2d and Sprite2d objects with addition or subtraction and whole numbers, floating point errors occasionally occur and accumulate over time. After the floating point errors start to accumulate, explicitly setting the rotation value to a whole number does not eliminate the floating point error. It appears that the decimal value is retained to the new rotational value.
Because the rotational values are off just slightly, positional values of child nodes are also off just slightly. This will cause errors with subsequent calculations, like intersects.
Steps to reproduce
create a main Node2d scene create a new scene Node2d scene and add a couple of child sprites In the main scene, rotate the new Node2d scene by 90 degrees. At the same time counter-rotate the child sprites so they maintain orientation to global
After a couple of rotations, you will start to see accumulated floating point errors. It does not seem to matter if the rotational value is incremented or explicitly set to a whole number as floating point errors creep in either way. In the same way, using any of the math conversion functions on the rotational value doesn't matter. Tried using these when setting rotational values:
Minor Workaround: there is a slight workaround that will work while the accumulated floating point errors stay below the required threshold and that is by using snapped values for calculations, such as intersects. However once the accumulated threshold is too high, that calculation work around will also fail
Minimal reproduction project
link to project: https://github.com/bulsatar/godot_rotation_float_error
Also attached zip with linux and windows exports rotation_error.x86_64.zip rotation_error_win.zip