Each object in scene uses a texture. Each texture uses a shader.
Thus every scene geometry item has a shader.
A million trees using the same texture can thus be one shader, or one million shaders, even if the texture is common!
Every time a shader is called to be rendered, it is batched. The CPU is involved in that task too. It gets all the stuff ready, from geometry, to shader to textures, and passes it all on to the GPU to render. That is a costly process and one of the biggest costs to overall rendering speed.
Think of it like a trip to go shopping. Ideally we want to go shopping once and do as much as we can in that trip, because it's inefficient to go back for each item.
However, items do eventually get split between the bakery and butchers and green grocers, so there is no avoiding making several trips at some stage.
In the shopping example, it's better to go shopping three times, than once for each item.
So having things that can all go together means we can 'buy' them all together... and that means less trips.
So even if we atlas all our trees up into one big atlas, but still use thousands of DOF for the trees, there will be thousands of batches processed and even though they are small, it is still the same kind of CPU cost as if it were one big batch with thousands of trees in it.
The travelling to the shop analogy works because the batch method is designed to do BIG jobs less frequently than lots of small apparently easy jobs quickly.
The travelling is the most time consuming bit, and that is state/texture changes for the GPU as the CPU sends the new batch to be rendered!
So in practice, atlas textures to save on shader count. Then optimise geometry so you don't see too much at once (no point batching trees/buildings you can't see as it takes up GPU memory to store the data).
But at the same time you don't want to draw things that can all be seen at once in more than one batch if you can help it. Ie, a street of houses that can all be seen at once may as well be always done in one batch.
Obviously this does all take time and practice to achieve, so as I said I'm not beating any one up over not doing it.
It'll take some time to work out good ways to do it, especially on already made content you are trying to convert!
I just want to make it clear that there IS a big benefit to be found by atlas/batch optimisation. As said, ideally we might be looking at about 50-75 batches for this track and about 100fps vs 25fps on my machine!
It is REALLY well worth persevering over playing with making an atlas, even if you just start with the trees (easy usually) and then combine ALL the tree geometry for the whole course... then chop it up into blocks about 400m long, then add an LOD range of about 800m.
Suddenly you will be rendering about 2-4 batches tops for ALL the trees, rather than maybe 30-40.
That might be 10fps right there, and in practice because trees are so basic in UVW mapping it might only take you 2hrs to do it!
Trees are easy I will admit, but as you start to understand the principle it will make sense and it may even become a fun task to optimise and work out the best ways to do stuff.
Batch optimisation is the only way to get good performance unfortunately... but it's great because it's relatively easy... it's just a task that needs to be done.
I'm busy right now in real life working a Sunday haha, but I will help with making these tracks faster running and help show how to think about batching optimisations for Racer a bit more!
No slur on anyone's work or skills here, just purely an optimisation task that does need to be done and trudged through to get the very best FPS
Dave