upvote
Modern games look samey because they all want the same result - photorealism - and aren't fussy about using an off-the-shelf solution - i.e. UE5 and Unity. We have absolutely insane levels of control over the rendering pipeline and almost everything is programmable; the GPU is an endless fountain of parallel programming. But in order to take advantage of any of that you have to actually start changing engine code, or write your own renderer, and games don't care because the default UE5 look is "good enough".

There is some standardization in that, if you issue geometry and sample textures normally, you will be relying on hardware units for rasterization and texture sampling, and those do have a relatively limited set of options for how they work. However, those options encompass most if not all of what 3D engines could ever want or need, even the early 3D ones that had all sorts of hacks. The kinds of things GPUs can't actually rasterize in hardware are things like NURBS or metaballs, but this doesn't matter because the industry settled on triangles[0] as the medium of real-time 3D really early on.

A lot of the look of old 3D games comes down to them doing things the lazy way, and I'm proud to say the lazy way is still very much supported - so long as you turn off features that didn't exist later on and limit yourself. I'm not as familiar with old DOS games, so I'll use the PS1 as an example. The "PS1 look" is very much a result of its incredibly limited rasterizer, whose limitations can be trivially emulated in modern hardware:

1. Don't allocate or bind a depth buffer. You will need to Z-sort your geometry every frame. Part of the "PS1 look" is that some games did it wrong; if you do it correctly you'll be burning performance for no visual benefit. Pick a scheme that breaks in a visually interesting way. Likewise make sure to not allocate any multisampling since the PS1 didn't anti-alias either.

2. Restrict the precision of vertices in your vertex shader by rounding them. The PS1 did vertex math with incredibly low precision and it makes vertices wobble.

3. Restrict the precision of UVs in your fragment shader. PS1 UVs were 0-255, so you want 1/256 precision.

4. Aggressively discard geometry that clips the edge of the viewport. The PS1 did not have proper polygon clipping; you just couldn't render off the end of the viewport, so games had to discard geometry and subdivide polygons to avoid things disappearing. This is another "if you do it well, nobody will notice" thing.

5. Turn off perspective-correct attribute interpolation; this will make your UVs warp and distort at certain angles. You do this with the `noperspective` attribute in GLSL.

6. Disable bilinear filtering when sampling textures.

7. Allocate and render to a low-precision color buffer. Lots of games would change the color depth to match the available VRAM. This is probably the hardest aspect to emulate unless you are actively counting VRAM usage and sticking to realistic values.

8. Bitcrush your textures before uploading them. The same reasoning applies here. Also, don't upload any mipmaps.

9. Lighting was done through vertex colors, which were calculated on the CPU. You don't have to limit yourself to CPU lighting but you do have to make sure lighting is done in the vertex shader.

10. Optional: implement the early model PS1 texture banding bug in your fragment shader.

This will give you a rendering pipeline that is good for basically all purposes except bit-accurate PS1 emulation. Of course, if you were doing bit-accurate emulation, nothing stops you from issuing a screen-filling quad and writing a GPU shader that does software rasterization on the GPU. Or launching a compute shader that accesses the framebuffer arbitrarily - although you do have to worry about memory coherency across warps and workgroups. Texture sampling can also be done "in software" if you so wish - i.e. by doing unfiltered reads to the texture which are glorified array lookups, and then filtering those reads as you wish.

[0] There was a brief moment where quads might have been able to win - artists like to work with them, and Nvidia was shipping quad hardware. But the advantage died very quickly, and quads can be easily converted to triangles - not so much the other way around.

reply
However well intentioned your post may be in explaining this, it misses my point.

There's no single oldschool look, as people writing software renderers didn't have a sanctioned way of doing so - a lot of them weren't even using triangles, or were using a mix of techniques.

You are describing how to make a game look like the PS1 games, but the PS1 actually had a - somewhat flawed, but unique - GPU which kind of forced the limitations you outlined here, and forced a singular way of rendering.

That wasn't really true with Quake or Duke3D or the PC in general. You just drew to the screen with whatever technique you chose, which resulted in a unique look for each game.

reply