I have been playing a lot in the terrain system the past few days, trying to understand the limitations. At first I implemented some terrain using TerrainComposer + RTP, and it looked great, but there were constant, subtle spikes in the FPS that I could not understand, so I put together a smaller project to test it.
I have a used a fairly simple single terrain from a height map that I post-processed with terrain composer (without RTP/AFS). Adding grass at any decent constant density with a detail range of 80m will noticeably cause the spikes as you move (presumably as you arrive at the next visible patches) and it just gets worse as you increase the detail distance (presumably because more patches are viewable). Keep in mind that the frame rate when not spiking is at ~250-300fps so clearly it is not a rendering issue as the draw calls/tris are quite low. However, as you move around the world, the spikes seem to occur at frequent intervals - in some cases every few seconds, and in the profiler they come up ~100ms in Terrain.Data.BuildPatchMesh, which is awful. Note: I have tested all of this with standalone builds to remove that as a potential variable as well (still occurs).
I have played around with all of the settings I can think of (while maintaining a similar grass density), and nothing mitigates it to any major degree (and I wouldn’t expect it to as the cost likely scales against the density rather than the patch sizes).
So the question is - am I missing something? Is no one else seeing this?
After much discussion with Unity there was a checkbox added to the terrain settings called “Collect Detail Patches”.
If unchecked, this makes all the terrain grass precache so that there’s nothing being built at runtime. It’s worth mentioning however that depending on your terrain size it will consume quite a bit of memory.
Yeah, on my mobile game with decent size forest terrain with lots of details it wouldn’t be the best most likely… oh well, I’ll just have to optimize everything the best I can then as usual!
Your best option is to create custom textures that use 2-3 individual grass pieces to make a wider detailed one. This way you can make your detail meshes wider to cover a larger area and use a much smaller density. The less detail density you have the smaller the build patch mesh hitch.
The only “gotcha” is that details look noticeably worse on hills. Would be nice if Unity gave the option to make detail meshes angle to terrain normal direction.
Do you know the specifics as to what exactly happens?
What’s the correlation between the number for “Detail Resolution Per Patch”, patch collection while walking around, the number or density of billboard grass/detail meshes I paint, etc?
Detail resolution per patch - the higher the number, the more meshes that will be combined into a single mesh. This saves drawcalls but will spike your profiler the larger the mesh it has to build.
Detail density is how many meshes are closely placed next to each other. The higher this number, the bigger your profiler spike will be.
Setting both numbers to a high value can be troublesome because unity has a 64k vert max which means that it will break and leave big open holes of details that failed to draw because they couldn’t be added to the chunk without exceeding the limit.
It’s actually a really bad implementation. It doesn’t even take into account distance per say, if you pan around it’s loading and unloading the same stuff over and over while not even moving. If they fixed that, which is a silly easy thing to do with a fast spatial hash, this problem would largely disappear.
So I got around to actually fixing this in my game. It’s the tree colliders that are the main culprit not rendering. I had a fast 2d spatial hash in java that I’ve used a lot so I did a quick port to C#, and am using it to dynamically place/remove colliders on trees as I move around.
I went from 40fps and constant 200ms+ stutters to 100+ fps and zero stutters.
I just posted on this subject in the physics forum and posted the spatial grid I used, minus the code that actually checks the grid every second or so, but that’s application specific and not the hard parts.
Note that the spatial grid might have a bug I haven’t found. It’s pretty much a direct port of a java implementation I’ve used for around a year that I know works, but there might be a couple of edge cases as accessors are different so a bit of the flow changed.