Simple question:
I have a huge map (I don’t want to worry about efficiency in this question so just know I have that all figured out). What is the best way to store all the data needed for the world.
For texture: Should I use a huge texture that includes all things like rock, dirt, grass, paths, etc… Or should I use a shader which samples normals for rock sides and grass top, then sample vertex color channels for paths and other stuff.
For mesh: Should I keep the map a whole mesh (again ignore optimization, I would cut into cell portions) or separate things like mountains, paths, grass areas, rocky cliffs, and dirt areas.
For grass: How should I handle millions of Vector3 determining each grass blade position? This would be way too slow to generate these at runtime, but storing a huge array of points like that would kill my memory and Editor Save times.
Feel free to just give thoughts or advice. Even just maybe on one of these topics (or all of them ). Anything is greatly appreciated
This is a pretty open ended question, all of which are greatly affected by a per use basis. But I’ll give my initial thoughts:
- Using a splat map or similar technique is definitely a good idea if it fits your design. Assuming it’s a game where you can look at the ground closely, you’d need massive textures to achieve a good looking terrain if you had it just be a straight up texture. But this is sort of dependent on your game.
- Having individual meshes is good, because they can be culled, have different shadow settings, and be affected by different lights. And of course each object can have its own materials. Repeated meshes only need to store a single mesh in memory, but a merged mesh needs to be a big ol boy.
- Agreed, storing a location for every single grass blade would be way too far. Assuming you actually want to do blades as opposed to full sized grass patch meshes like most games, one option would be to store patch locations, then generating blade locations during runtime, using jobs. There are also ways to reduce data, depending on your circumstances. You can compress it, drop what you don’t need (will grass scale in all directions, or does each patch need a single scale value? Does grass rotate in all directions, or just on the y axis?), and if you wanted to make the grass always stick to the terrain surface, you could even drop the y position, and sample the terrain at runtime. This of course is a tradeoff of cpu time during runtime versus storage space.
Good luck. Sounds like you’re planning on building a lot of tech on your own, which is a ton of work.
I have been trying to get open world (many many terrains basically) to work with Unity for few years now. And here are my thoughts
-
Modern hardware actually bails Unity’s outdated system, and with some third party integration, there is no need to come up with a new system. Textures, meshes and other details eventually play little role, provided that it is a full scale game, as the only option to render all those is basically a form of GPU instancing.
-
The real issue, is that when the game world is fully populated, it is very hard to mitigate the lag that occurs when a new area is loaded, it really doesn’t matter whether you keep the chunks small, async etc. The sudden increase of new data loading, and the related scripts and rendering required is just a bit much to do. So, while your decisions regarding won’t matter as much as most people think (textures, mesh and grass, as they would most likely be instanced, hence pretty much all solution leads to one way) there is also no way currently to swiftly load and unload a new area without a significant frame time issue. The lag is very little, and I have seen AAA games do much worse, so it is debatable whether the current limitations are “good enough”
-
So, the issue in rendering Open World in Unity is not really performance, but mitigating lag spikes between loading and unloading terrain chunks (to put it in simple terms).
-
So, in my personal opinion, to really mitigate this issue, there are two solutions
-
keep the chunks really small, like 25 x 25 or 50 x 50…and only load or unload one at a time. Theoretically, this should minimize the issue, except the data handling of terrain is going to be really painful. I am actually working with 64 1000 x 1000 terrains right now, and I will convert it to 1280 50x50 terrains before release. This may or may not work out, and I may have to just stay with 1000m terrains. There are always a “gotcha” to a theoretical solution. The issue of lag spikes mentioned above will still be there, but I am just hoping that it drops to a minimal level. It might, and it might not.
-
Clipmap terrains. Basically it projects a large mesh that forms itself to a heightmap on the GPU side. The only issue is that there is no way to have collision info, so some form of redundant CPU side data has to be handled. I have only tinkered with this briefly, and rendering wise, it is very promising. But there are no known Unity system that supports this, so all related system has to be made by you (detail, grass etc). The upside to this tech is probably that you only need one terrain mesh (as it forms to the heightmap like a decal) and that it doesn’t need chunks (so no loading and unloading) but the average fps might not be as good as option 1. Also, as the terrain mesh moves there might be visible “jiggle” due to how the clipmap works in the distance. So a sufficiently distanced tessellation is sort of required.
Hope my 2 cents helped.