1
\$\begingroup\$

Maybe it'll be a super beginner question but can someone explain me why do we have to use a fractional numbers (floats, doubles) in the graphic engines (2D/3D)? Couldn't be all the calculation results just rounded up to an integers values or even such constructed not to use fractions at all?

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Some older graphics systems did indeed round to a fixed precision (eg. PS1). You can see the impact this had on the image and animation quality. ;) \$\endgroup\$
    – DMGregory
    Aug 27, 2020 at 20:20
  • 1
    \$\begingroup\$ If you'd like to get more up-votes, consider editing your question to flesh it out in more detail - make it less "super beginner" and show the research or experimentation you've done so far to understand this topic. \$\endgroup\$
    – DMGregory
    Aug 27, 2020 at 20:31
  • 2
    \$\begingroup\$ You might get better answers if you told us why you would think writing a game's graphic engine without floating point math would be a something to achieve. Why would you want it? Did you try it? What results did you get and what were you expecting instead? \$\endgroup\$
    – Vaillancourt
    Aug 27, 2020 at 20:32
  • \$\begingroup\$ Useful reading: stackoverflow.com/questions/2550281/… \$\endgroup\$ Aug 27, 2020 at 20:41

2 Answers 2

3
\$\begingroup\$

Vaillancourt's answer covers why we need to provide floats to work with our graphics acceleration APIs, but I think we can go a bit deeper into why do our graphics acceleration APIs expect floats in the first place.

So why do we even have graphics acceleration APIs?

It's important to remember that one of the big reasons hardware graphics acceleration came about was to support 3D rendering and 3D games. If all you want is pixel-perfect 2D sprites, you can already get a very long way with the CPU alone, working all in integers or any other data type you like. Even back in the days when 3D accelerators were still new and CPUs were far less powerful than today, we had beautiful and fast 2D games.

But 3D brings with it an order of magnitude more complexity, and several aspects that require or benefit from fine-grained fractional representation, including...

  • Perspective projection: the closer something is to my camera in 3D, the bigger it looks on my screen. That means even if I choose a suitable integer position grid based on a particular viewing distance, any time objects get closer to my camera than that, I'm going to start to see rounding errors, because those gaps between integer positions are now bigger than a screen pixel.

    You can see this in old PS1 games, where meshes often had a noticeable distortion or vibration, as vertices snapped to representable positions in the fixed-point coordinate system the console used.

    Floating point has an additional advantage over integer/fixed point solutions here, in that while it also has rounding, the rounding error is proportional to the magnitude of the value. So vertices close to the camera, where errors would be most noticeable, have the highest precision available and experience the least rounding error. Further away, the rounding error can eventually get worse than an integer-based system, but at that distance the errors end up smaller than a pixel on-screen if we've done our work right.

  • Texture mapping: computing which pixel of a texture to draw on a skewed polygon in a perspective-correct way requires dividing by the depth from the camera. If that depth is measured as an integer, many possible output ratios won't be representable as an integer, making the texture appear to crawl or slosh across the surface rather than track it perfectly.

  • 3D animation: if I have a character built out of connected bones, snapping in the allowable positions and rotations of a parent bone cascades down to its children and their children. Allowing fractional values in the orientation lets even long bone chains play and blend-together smooth animations without visibly snapping from pose to pose.

All of these features include at their heart being able to divide something into small parts, and even though floating point division is slower than addition/multiplication/subtraction, integer division is often even slower. So floats fill this role pretty well.

So, there are very good reasons to make a fast floating point path in 3D graphics acceleration hardware, to handle these common use cases where CPU rendering just wasn't enough.

And once you have a fast float path, you might as well make that the only path: a 32-bit float can represent all the integer values from negative to positive 16 million - plenty of range to uniquely address every pixel on your screen if all you need is pixel-perfect 2D with integer snapping. So there's not a big demand to complicate the hardware or the graphics APIs with a separate all-integer solution.

\$\endgroup\$
-1
\$\begingroup\$

Your graphics API expects this. I'll quote a site that will explain it better that I would (emphasis mine):

OpenGL expects all the vertices, that we want to become visible, to be in normalized device coordinates after each vertex shader run. That is, the x, y and z coordinates of each vertex should be between -1.0 and 1.0; coordinates outside this range will not be visible. (Source)

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .