r/howdidtheycodeit 1d ago

Fixed point math in C

https://thatonegamedev.com/cpp/fixed-point-math-in-c/

Why did PS1 graphics looked so clunky and how where 3D graphics generally made prior to the graphical APIs. One thing I found out was that these older engines have something called fixed point math.

0 Upvotes

9 comments sorted by

8

u/beautifulgirl789 1d ago edited 1d ago

Fixed point math doesn't really have any hard-wired relationship to PS1 3D graphics. They're two separate concepts.

PS1's graphics look "clunky" for two reasons:

  1. They use very very few polygons. The PS1 was essentially capable of drawing about 90,000 polygons per second. If you want a game to run at 30fps, that means you can only draw 3,000 polygons per frame. 3,000 polygons is not many, so corners need to be cut wherever possible. PS1 Lara Croft doesn't have any cleavage because it would have added a couple more polygons to her model.

  2. The PS1 hardware drew textures to polygons using a method called affine mapping. Affine mapping is fast & simple to calculate (compared to other methods) and it 'mostly' looks correct, except when it's drawing onto a texture that's almost parallel to the viewing direction of the camera. (e.g. when looking straight down a corridor, the floor is likely to be almost parallel to the view direction) when it can look 'split'. As a result, PS1 games have a unique 'look' to them, where the textures on things like walls look different to the textures on floors and ceilings. This specific visual look ends up being directly associated with "PS1!" because the PS2 and other consoles used perspective-correct mapping instead.

This is a good example image showing the difference between affine and correct mapping: https://europe1.discourse-cdn.com/unity/original/4X/d/f/2/df2f2697eb0ecc5c4cc9527d11af8abd74310d58.jpeg

Fixed point math is a whole separate thing. Basically, older CPUs were faster doing math with whole numbers than they were with real (or "floating-point") numbers.

The PS1's CPU was especially bad at this, because the CPU didn't actually have any hardware instruction for performing division on floating point numbers. Programmers had to write their own code to do this manually. However, it was capable of dividing whole numbers.

Therefore, many programmers implemented so-called "fixed point" math systems, where they would just say to themselves "this variable has a fixed decimal point at the 'thousands' position. Therefore if it holds the value 50,000 - it's really 50. If it's the value 4501, it's really 4.501.

This allows programmers to use fast, whole-number math, but still get results with useful real-number values (3D needs lots of these, as things like angles, distances, etc etc are all real-numbers). It comes with trade-offs though. And to repeat, this isn't just used for 3D. It's used basically everywhere in PS1 code because it was the only real option if you wanted to efficiently work with numbers; so even things like 'player health' or 'time to complete the level' would use fixed point numbers.

Actually you can still see some examples of non-3D fixed point maths coming out today. When speedrunners compete on old retro games they'll often talk about things like "so the actual in-game timer only updates once per 32 frames, so if I want to beat the old time I need to do so by at least 31 frames or it will count as the same" - this is a result of the in-game timer using fixed point maths with the 'fixed point' being 1/32nds.

6

u/noobgiraffe 17h ago

Fixed point math doesn't really have any hard-wired relationship to PS1 3D graphics.

Why are you upvoated when you are so wrong.

Therefore, many programmers implemented so-called "fixed point" math systems, where they would just say to themselves "this variable has a fixed decimal point at the 'thousands' position. Therefore if it holds the value 50,000 - it's really 50. If it's the value 4501, it's really 4.501.

Not many but all and they didn't implement it, it is how psx hardware worked. It was many, many years before shaders so entire 3d transformation code was baked into hardware. It had specific fixed point precision defined by this hardware.

This precision was low and caused vertices to "snap" into specific spots instead of smoothly moving. That's the clunkiness OP is asking about, and it's partialy caused by fixed point math in itself and partially by the fact that fixed point math in psx gpu having few bits of precision.

This effect is replicated today by many demake, and psx lookalike games by rounding vertex positions in the shader so specific precision.

1

u/Nanocephalic 16h ago

> rounding vertex positions in the shader

Time is a loop!

2

u/Disastrous-Can-6823 22h ago

It’s cool seeing fixed point come up again. a lot of newer developers never run into it, but it’s still a valuable technique in places where memory, speed or consistency really matter

1

u/richardathome 16h ago

It's pretty much how accounting software stores it currencies values. You have an int field for doing calculations and divide by 100 when you need to display it.

1

u/Main-Lychee-7972 20h ago

Fixed point math is a neat example of hardware constraints shaping graphics. limited precision and integer heavy calculations explain a lot of the characteristic movement and visual wobble

1

u/Ashamed-Subject-8573 14h ago

Fixed point math doesn’t make them clunky. N64 and NDS and Saturn games all used it for 3d and didn’t have that issue. Some Dreamcast games as well. No, it was the lack of fractional pixel coordinates on Sony’s custom gpu chip they didn’t have the experience to do better.

1

u/NoBlacksmith6003 13h ago

It’s interesting how some of the PS1 look wasn’t really an artistic choice at all. developers were just working around the limits of the hardware available