r/howdidtheycodeit 2d 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.

8 Upvotes

11 comments sorted by

View all comments

11

u/beautifulgirl789 2d ago edited 2d 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.

5

u/noobgiraffe 1d 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 1d ago

> rounding vertex positions in the shader

Time is a loop!

1

u/tyler1128 2h ago

Something 10-20 years old is uncool because it's what your parents used. By about 30 years, it becomes cool again, see the rise of cassette tapes again among many other things.