Rendering 300 or 1000 characters is possible.
To get a general idea, lets say all are animated, 10k tris each. for 1000 chars that would be 10M tris. Now, not all of your characters are visible at the same time, well unless you’re viewing them from far. But let’s say all are visible in the camera. 10M animated tris is quite a lot.
One optimization is Level of Detail, characters that are far away do not need the full 10k tris, since a lot of tris will be even smaller than a single pixel and not at all visible. A character at a certain distance will use let’s say, eg 5k mesh, at further distance 3k mesh and really far away 1k mesh.
Thus, let’s say 95% characters are far away, from 10M tris, we are down to 1450K tris.
You can make even smaller mesh for more distant characters and get even less and tweak the distance/number of tris so that the decrease of visual quality is not apparent.
Another optimization is to reduce number of draw calls. 1 draw call for 1k chars = 1k draw calls.
Do some characters share meshes? share animations? If yes, instanced drawing can be used to render multiple characters with a single draw call.
Are the distant characters not moving at all or are some moving in sync? Billboarding can be used for very distant ones.
Here is some video showing animated billboards (https://www.youtube.com/watch?v=2-queKkSVnw). 16k animated billboards are rendered.While the animation in the video is not smooth, nothing is stopping from making it so.
If you make a good billboard system, you can get plenty of chars showing, 100k chars should be no problem.
In the end its about using your resources wisely, use more for close objects, since these need to be detailed and use less for the further ones.