Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Does float's imprecision affect transformations?  (Read 3177 times)

0 Members and 1 Guest are viewing this topic.

vokazoo

  • Newbie
  • *
  • Posts: 18
    • View Profile
    • Email
Does float's imprecision affect transformations?
« on: September 19, 2024, 06:20:19 pm »
Hello, I'm wondering how float's imprecision affects drawing and other parts of SFML, as float is used almost everywhere.

Here are a few examples that explain what I mean and what I have doubts about:
  • If a sprite is at position (1'000'000.0f, 1'000'000.0f) and is being moved by 0.0333 pixels per frame to the right, in 90 frames, x position of will be at 1'000'005.625f meaning the sprite moved by 5.625 instead of ~3.0. If the starting x position is even higher, like 1'100'000.0f, the sprite doesn't move at all because float values become too graded.

  • -If a transformable and drawable object has many parent transforms, meaning the transformation matrix has to be multiplied multiple times in order to calculate that object's transform for drawing, the final position (or rotation or scale) could be slightly off, especially if the values are high, resulting in an object being drawn incorrectly.

  • Game physics may become less accurate and more importantly inconsistent depending on the magnitude of transformable position's value. The solution for this is to store transformation data separately of SFML for physics objects (using decimal type or double), but this solution is 'ugly' and requires constant conversion from that type to float.

Can this be an actual problem, or does SFML take float imprecision into account somehow?
What is the usual way to avoid these issues?
Thanks

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Does float's imprecision affect transformations?
« Reply #1 on: September 19, 2024, 11:52:47 pm »
SFML primarily uses floats, because that's what graphics APIs use (i.e. OpenGL). Any higher precision would not translate to the graphics APIs.

But SFML of course cannot remove the lower precision properties that float represents.
As such the general recommendation is, if you really do need high precision, you need to implement your own representation of the world (there are excellent math and physics libraries out there) and then translate into the rendering space, before drawing it.
This also allows you, if done correctly, to just stay in low floating point values, so the precision on the drawing side remains high.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

vokazoo

  • Newbie
  • *
  • Posts: 18
    • View Profile
    • Email
Re: Does float's imprecision affect transformations?
« Reply #2 on: September 20, 2024, 12:26:26 am »
Thank you for the answer,

What about the second example? In case it wasn't clear what I meant, here's an example:
struct TransformableStruct1 : public sf::Transformable, public sf::Drawable {
        sf::RectangleShape shape = sf::RectangleShape({ 100.f, 100.f });
        void draw(sf::RenderTarget& target, sf::RenderStates states) const override {
                states.transform *= getTransform();
                target.draw(shape, states);
        }
};
struct TransformableStruct2 : public sf::Transformable, public sf::Drawable {
        TransformableStruct1 ts1;
        void draw(sf::RenderTarget& target, sf::RenderStates states) const override {
                states.transform *= getTransform();
                target.draw(ts1, states);
        }
};
struct TransformableStruct3 : public sf::Transformable, public sf::Drawable {
        TransformableStruct1 ts2;
        void draw(sf::RenderTarget& target, sf::RenderStates states) const override {
                states.transform *= getTransform();
                target.draw(ts2, states);
        }
};

struct FinalStruct final : public sf::Transformable, public sf::Drawable
{
        TransformableStruct3 ts3;
        void draw(sf::RenderTarget& target, sf::RenderStates states) const override
        {
                states.transform *= getTransform();
                target.draw(ts3, states);
        }
};

In order to draw FinalStruct object, transform has to be multiplied 4 times (states.transform *= getTransform(); lines). Could the final result of those multiplications be incorrect, if there's a lot of them, as small precision errors get carried over?
Secondly, how can I ensure the values in transform matrix are low enough, as there's no way to check them as far as I know?

By the way, is there a specific math and physics library you would recommend for this case?

Thanks

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Does float's imprecision affect transformations?
« Reply #3 on: September 20, 2024, 08:22:22 am »
It's not like floats are completely unusable. As long as you don't "max out" the significant digits, you'll get good results. In the end your display is resolved on pixel level, so whether it's 0.235 or 0.234 pixels won't really be noticeable.
Additionally, you may anyways want to round to integer positions, otherwise you leave it up to OpenGL's rasterization on how sub-pixels are drawn.

In short, yes errors will accumulate, that's the nature of floats.
In practice, for the visual representation, this shouldn't matter as much.
If you need a mathematical/physical accurate representation to a specific amount of significant digits, then you'll have to use a separate math layer of your own.

Eigen is a very well-known math library.
Box2D is the standard physics library in C++
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

vokazoo

  • Newbie
  • *
  • Posts: 18
    • View Profile
    • Email
Re: Does float's imprecision affect transformations?
« Reply #4 on: September 20, 2024, 04:01:13 pm »
Are decimals deciding factor in 'half pixels'? For example when drawing RectangleShape with size (9, 9) on view that's zoomed x2, will it draw as (4, 4) or (5, 5)? If they are, could float imprecision affect the size for that one pixel?
How does it affect anti aliasing?

Thanks

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Does float's imprecision affect transformations?
« Reply #5 on: September 20, 2024, 04:47:24 pm »
I assume by zoomed 2x, you mean zoomed out.

That's up to the rasterizer to decide.
Depending on the situation and the enable AA level, it may drop the pixels or draw them or change colors for one line and the other.

You can think of it like a grid. Every grid cell represents a pixel. Now if a grid cell isn't fully filled, you now have to decide what you're going to do with that cell. You can fully color it. You can color it with some gray color. You can color it with a semi-transparent color. You can leave it blank.
That's the rasterization step and it usually comes from decimal positions indeed.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

kojack

  • Sr. Member
  • ****
  • Posts: 343
  • C++/C# game dev teacher.
    • View Profile
Re: Does float's imprecision affect transformations?
« Reply #6 on: September 20, 2024, 10:12:27 pm »
For really large worlds, I'd use fixed point maths for all positions. That gives a consistent precision over the entire range. Then get the different between the fixed point objects and the camera and convert to a float, anything on screen will have a small float value (well, a few thousand depending on resolution) and it's purely the visual side, the simulation itself is still in fixed point.
For example using 64bit integers as 48:16 fixed point and a world where 64 pixels represents 1m (that's what I use normally), you'd have a consistent precision of 0.000000238m over an area 29 astronomical units across (over 280 trillion pixels).

I've never used SFML's transform hierarchies, but as far as I remember it's just matrices. So there's going to be float error in there. If the matrices accumulate error for too long, they won't even stay orthogonal.
It depends on what you are doing with the transform hierarchy as to how to avoid it.



vokazoo

  • Newbie
  • *
  • Posts: 18
    • View Profile
    • Email
Re: Does float's imprecision affect transformations?
« Reply #7 on: September 21, 2024, 12:02:55 am »
I assume by zoomed 2x, you mean zoomed out.
Yeah, zoomed out so the image appears two times smaller than it actually is.

That's the rasterization step and it usually comes from decimal positions indeed.
Does that mean that AA could look different for the same image (and same conditions like view, scale, rotation etc.) depending solely on the position, due to decimal points being different?



Then get the different between the fixed point objects and the camera and convert to a float, anything on screen will have a small float value (well, a few thousand depending on resolution) and it's purely the visual side, the simulation itself is still in fixed point.
If I understood this correctly, you're saying I should't move the camera (that is view), but instead keep track of camera's position separately with fixed point type, then subtract every game's object position with the camera position, and set the sf::Transformable's position to the result of the subtraction (after converting to float). In other words, move the entire game map to fit into the right part of camera frame, instead of moving camera. Did I get this right?

It depends on what you are doing with the transform hierarchy as to how to avoid it.
I'm making objects that have multiple parent transforms, meaning position relative to another transform. For example let's say I have a class GUI that has TextBox object as data member and TextBox that has sf::Text as member. All 3 classes inherit from sf::Transformable and sf::Drawable, so when drawing GUI object transform matrix will be multiplied 3 times. That way I can place TextBox as a part of GUI, so when moving GUI, TextBox moves with it. Those hierarchies can get pretty big, so I figured transform multiplications may become inaccurate.


Thank you for your time