I am designing a large scene that has millions of polygons and a lot of objects in it. It bogs down my viewport a ton, and also greatly increases render times. Obviously, I turned to LOD systems to optimize my scene. But I couldn't find any, unlike Unreal Engine or Unity (which are all automatic)! I know there are paid add-ons out there, but is there a way to do it for free? (Also don't want to use Adaptive Subdivision because I want to use it in EEVEE, too; is that even possible?)
I added a comment about how the question was asked, but I'll give an actual answer here: sort of, via geometry nodes (won't work earlier than 3.1, as it relies on a specific node):
Use the "Merge By Distance" node, and have the distance adjust based on - well, whatever you want. I have it taking the distance between the object and the camera, use a map range to clamp to good values (0, 100, 0.001, and 1 worked nicely for Suzanne). I have done a concept where it takes the pixel size into account, but that's a lot of math that honestly will slow the nodes down to a crawl.
Here's an example of it:
And you want this to be applied to multiple objects at once? Use the "Copy Attributes" addon, free and already included in Blender, to copy and paste modifiers between objects. You may still need to set parameters manually though, haven't checked.
Note: this is recalculated whenever the frame changes, so this will slow down Blender during playback, especially for your big scene case. And geometry nodes, in my tests at least, tend to not scale very well with dense meshes.
Is it automatic LOD? Yes. Is it going to improve performance to what you want? Maybe not (and this may mess up your UVs or other mesh-related data, I have not tested this).
Frankly, I'd mark this as "not yet implemented in Blender." The fastest, best way this should be done is within the source code, accelerated by Blender, in the background. I trust the developers to look into that, if they think it's the best way to go about it. Game engines like Unreal and Unity can optimize a lot because they can assume a lot, and assets are (more or less) locked down. The Blender viewport must be dynamic and exactly represent what users expect it to be, so there's less developers can assume about any given project file and scene. You may expect the mesh to be an optimized version of itself, but other users may expect to see the full mesh even if far away.
There are addons built around viewport performance (like my nView addons - I won't post links here unless solicited, you can look them up) that may help as well, if you find LODs not to be your ideal solution.
There is in fact a way to do so, using drivers. You create a driver setup that decimates a mesh the farther it gets from a camera and subdivides it slightly as it gets closer. This is all automatic and only needs you to briefly copy and edit the driver for the mesh in choice.