Hello Community,
at this point I would have wanted to provided the solution by myself, but as I am currently busy with my project, I need a short answer for this, so I can decide if integrating it is worth the hassle or not.
I would want to know if creating Trees (40K), Bushes (40K) and Grass (multiple million quads) over a 2048x2048 big Terrain using DOTS with Jobs and Burst would be more performant than using the default Terrain techniques and even more performant than the Nature Renderer in Unity 2022 HDRP 14? Moreover, can I use MeshColliders for the DOTS tree’s and would they interact with GameObject colliders?
Has anyone tested that already and can share the results?
That would be awesome! Thank you.
I am sorry for not having it done right in the first place, but can one forum moderator migrate this question to the DOTS area, please.
For the scope of objects you described, you need to just throw out the idea of using the terrain system. You can use it as a “modeling tool” to create your ground, but you are going to need to convert these to meshes instead of the vanilla terrains system. Also, only shows the detailed meshes for terrain up close, use lower poly versions of each terrain chunk for distant objects. Keep both variations as low poly as you possibly can.
Below are some highlights of how you can realistically achieve your vegetation goals. I don’t think any of the options you mentioned are going to get anywhere close to playable results given your specs.
For the trees:
- Make combined mesh tree groups to lower your total number of game objects. The more trees you can fit in a combined mesh group the better. So, low vertices count for each tree is important. This will get you a bunch of filler for very dense forests. YOu might also consider using “canopies” that cover the ground area from aerial views above.
- Using GPU instancing for these tree groups.
- Consider going a step farther and make LOD imposters for each tree group
For the bushes
- Cull these (and anything else) that the player can’t immediately see. If it’s not visable, then don’t render it. Use per layer culling on the camera for this. It’s the fastest.
- Above strategies for trees also applies to bushes, especially the clumping and GPU instancing.
For the grass
This is the hardest one in my opinion and the biggest thing is how far away do you want to see the grass…
- GPU instancing and clumps of grass are going to be the most realistic way to go here. Because if microtriangles combined with overdraw of transparent textures, your combined objects for grass are going to need to be smaller in size to achieve the best performance balance.
Overall, your goals are not usually considered realistic for real-time gaming with that many game objects. Uing dots or not might make a difference, but I wouldn’t view it as a perfect silver bullet solution in the current state of things especcially. Most people are going view your specs as completely unrealistic either way. That is most likely why nobody has responded to this thread, not because of what category it is in.
GPU instancing, grouping object meshes, using imposters, and culling the bushes and grass from a distance is going to be your realistic opportunity to achieve your goals here. It’s not going to be easy, so I would seriously consider compromising your specs unless you’ve found a stable DOTS solution for this. Again, your number of game objects seems like a lot, even for DOTS.
@ron-bohn Thank you very much for the detailed description! It seems like I am doing most of your advises already. At the moment I still use Unity’s Terrain trees and Terrain detail grass billboards as it has a much smaller memory impact than usual game objects.
I already used the profiler to find out what the most performance hit is and it seems not the amount of vertices or grass, but the trees LODGroup has to do a lot of work, cutting my FPS in half. So I thought using the DOTS way of a LODGroup would be much more performant here, but I can’t test it at the moment, but I will in the future, if nobody else already tested it.
@CleverAI You bet! You could also by-pass LOD groups alltogether and incorporate per layer camera culling instead of the having thousands of LOD’s constantly checking distances. I believe this would be helpful with or without a DOTS solution. If possible in the rest of you set-up, you could could use a 2 camera solution in order to cull the near distance on certain layers. It takes some adjustments and fiddling, but I really think that might be a game changer based on the current bottleneck you described without needing to add the complexity of DOTS. It’s pretty straightforward to set-up so you can most likely figure it out. I do have an example I could send you though if there’s any confusion on how to set-up something like that up, in case you haven’t done so already.
In the future, I think DOTS would be awesome if you wanted to make every single one of the trees and bushes destructible or dynamic in other ways. I have not tested the “DOTS way of a LODGrouping” personally, but everything else I’ve mentioned I have tested via several different approaches and combinations…(on much larger scale worlds too than 2048x2048).
One of the main reasons I mentioned “imposters” and grouping the meshes was lower the number of total LODGroups.
Also, exactly how much memory did mesh terrains add (or expecting it would)? Just asking because I know of a few ways to fix those issues. Is it the meshes themselves or the textures/shaders? There a couple ways that I do this that are very memory performant and the batches/cpu saving are almost always worth it for me. If you’re talking graphic memory or, VRAM, then know that I usually build pretty large worlds of 2-3gb or VRAM total (non toon real textrues etc).
@ron-bohn Multiple cameras in HDRP are horrible performance wise. That’s why I rejected all methods that utilize another camera and figured out other methods to fulfill my needs.
Yes, while my trees should not be destructible, but the trunk should have a MeshCollider instead of a Capsule one. Then I could do better interactions with them, like drawing on them.
Yes, I also figured that setting the Fade mode to None is way better performance wise than Crossfade.
I have written a script to convert all terrain trees to game objects and the Memory and VRAM raised a lot. While the performance was about the same, the Memory took over 40 GB and VRAM about 7GB more than Terrain, so for normal PC’s not useful.
40gb that’s a lot lol and there’s something going wrong out of the ordinary there. Really glad I asked :). I can’t pinpoint based on what you said, but there is absolutely something else that is causing that memory bloat. Maybe the script, the models, or something to do with the terrain, or maybe even the HDRP version or a combination therein. That amount of memory is obviously unworkable on just about any platfrom, but there’s gotta be something else going on there because that’s something I’ve tested a lot. Not as much in HDRP, but yeah that’s something with the set-up not discarding the terrain system, which is notoriously sluggish on the cpu, regardless of the pipeline.
Just to be clear I think those specs are challenging for non HDRP. All depending on art style and desired view distances of course. I am guessing at some things because I’m able to see your project directly. I am interested in seeing how this evolves for you though.
EDIT: You can still take advantage of per-layer-camera-culling to completely eradicate the LODGroup bottleneck that you mentioned. You can do this with a single camera with vegetation without the near to culling. Just put the higher poly close stuff a few millimeters on the outer edge of your trees, mesh terrain, and such.
@ron-bohn Yes, it is. But as I said only when I place trees a GameObjects. As long as they are part of the terrain, I don’t have this memory issue. I tested this as I wanted MeshColliders instead of Capsule Colliders as the Terrain only supports the last one.
You can have a look at Steam, just search for Cursed Dungeon Raider.
I can’t really figure out how to setup what you mean. Should I set trees LOD0 to Layer0 and LOD1 to Layer1 and so on? Then the camera should only render Layer0, while I update the layers of the trees to switch between the LOD levels?
Yeah something else is causing that memory issue. Async/additive scene loading is always a backup solution as a last resort, but there’s something with the prefabs, set-up maybe. It’s also possible that your texture budget is 10x larger than it needs to be based on the images and build size estimate on steam (10gb). This size could be affected greatly by something like total audio clips among other things (doing my best to guestimate here so bear with me haha.
I’m wondering if maybe there’s a tool that’s causing memory bloat in the editor. Did you profile in a dev build also? And, have you tested this outside of your main project to make sure there’s not something else causing this? Exactly what is the profiler saying is causing the memory increase?
Also, I assume mesh colliders for all of this as you’ve said a couple times.
For per layer culling you have the right idea basically. Use it in place of LOD’s. I use a simplified version based on really basic Unity boilerplate code, but this asset can give you a user friendly crash-course of setting up per layer camera culling: Per-Layer Camera Culling | Camera | Unity Asset Store …it is unironically called such lol.
This is also a tool for converting terrains to mesh: Terrain To OBJ | Terrain | Unity Asset Store that one costs $15 but is worth every penny. I’ve been using it for many years.
It makes a splatmap shader for the mesh based on the terrain textures assigned. This can get heavy, but nothing near what you mentioned. I personally like to use tri-planer world-space shaders instead of the default splatmaps…very memory friendly and performant. I know you are talking about the trees when you add them, but I re-iterate the importance of using mesh for your static ground. 256x256 OR 512x512 chunks of mesh terrain would be adequete for a PC build you are aiming for.
For the trees adding all that memory, there’s just no way. Something other than that workflow is causing it. How many materials total do you have in the scene? Are you using prefabs? Do you have hundreds of different imposters? It’s gotta be something like that.
Your game is appears to be FPS so framerate is pretty crucial. Also, in your game is the player going to always be on the ground? I generally figure on the possibility of flight among other things which makes optimization trickier, but still very doable. There are multiple ways I know how to go about making the level you described.
EDIT: Just in case you (or anybody else reading) doubts the massively superior mesh terrain workflow, here is a good thread with lots of third party corroboration of most of the things I’m conveying (yes I’m also part of that thread). Lot’s of stats and use-case studies. terrain vs mesh?
@ron-bohn Yeah, I haven’t figured much out yet what really is so VRAM hungry. My build has a moderate memory usage of 3GB though, while VRAM can take over 12GB if available. So definitely room for improvement.
Ok, I’ll give this camera culling asset a try. It’s free after all.
Yeah, I have no problem yet with the terrain itself. It is not what utilizes that much VRAM and therefore not a high priority to change it.
Did you tried it yourself? Placing 40K trees as GameObjects with MeshColliders in HDRP? Could be that I have set something up that eats too much. However, I made the trees static and GPU instancing enabled in the materials.
Yes, always on ground and mostly dark. What kind of optimizations do you have in mind for a ground based player design?
EDIT: I tried this asset already a bit and now I fully understand how it works. But this means I have to setup all my LODs again for this method… Perhaps I write a script that does this for me, so I don’t have to change all prefabs by hand. But I foresee a problem now: You can’t really fine tune for each object as you can with the LODGroup, as there are only 32 layers available.
I explained how I would go about placing 40,000 trees. I simply would not place 40,000 trees. I would put them in combined mesh groups in addition to everything else I mentioned. And, yes I’ve tested this using around 5,000 “tree clumps” to achieve the same affect, on mesh terrain. I got 120 FPS using my own OWA tree library. There’s a demo with 5,000 high poly trees with no additional optimization. This is the exact same as having 40,000 lower poly trees in clumps of 5. Many ways to go about this. But yes, I would not even discuss this if I hadn’t done this massive amounts myself. LOL
Ground based player design = everything is much easier because the total view distance does not need to be anywhere near as far. 500m can be pretty good results, but if you’re flying, you pretty much are going to be view for 2 km or more from anywhere on the map…which is more to render obviously. For desktop, I probably wouldn’t need to do ANYTHING outside of using my own custom model library to get 120 FPS in built-in. Less than 1 gb of VRAM for the nature stuff. I also make detailed, dense city environments with complete interiors…much more difficult than nature stuff. OWA City Core Kit: Open World 1900s - Urban - Steampunk - Cyberpunk - Victorian | 3D Urban | Unity Asset Store
That’s why I know it probably has something to do with your assets being used or tools causing that bloat. If you just had a view distance of 500-1,000 meters, you wouldn’t need to do any serious optimizations for desktop since modern gpu’s an handle vertices in the 10’s of millions pretty easily. Sorry for the self promotion, but yeah I’ve built all this stuff from scratch, from the ground up many times before.
Exactly wow many different prefabs do you have? If they are organized at all, you can set the layer of multiple prefabs at once in the project view/inspector. That might be the problem to some of your issues. I’d be careful jumping into just making a script for this because I believe there’s some kind of bug already in your project to yield the results you mentioned.
But yeah with the layer you can just organize simply (one way to do it) would be just make a small medium, large layers and assign everything based on the view distance you want.
EDIT: No the it’s not a problem with the process that I described. This is the best way to do it. Only 32 layers? What the heck do you need more than for…lmao…you only need a view distances to get awesome optimization results. Yeah it might take work. I don’t care in that regards either do it or don’t. lol. It’s not like it would take more than a day to straight up solve the bottleneck you said you have. That’s nothing. No offense.
Well I think I have to play more around when I have the time for that. For now I have to finish the demo for Halloween as quick as possible and let the performance be at a mediocre level for now.
Thanks for the detailed info and your time!
Timelines…understood. It will erase that bottleneck. Since you have that hard deadline, I’d just adjust the view distance. URP and built-in can get pretty good results. Personally, I’d go that route in case you are not able to get 60FPS in HDRP. That’s just me though. Let me know how it goes. Good luck!
I think as a quick solution I try to add bushes to the terrain details, where the grass is, instead of trees. As I saw that as soon as the bush had no LODComponent anymore, the terrain tries to create billboards at a distance by itself, which is cool, but doesn’t work with the used HDRP shader.
Yeah I’m not sure what you meant in your last message. I hope you are building your environment in an isolated branch or separate project from your main game 
There are so many things about your current set-up that you described that is not ideal for what you’re trying to do. If you’re going for a quick performance solution for your halloween deadline, then your best best is to cut your total number of trees drastically while keeping the illusion of a dense forest. Make lots of the trees larger and do some capopies with just tree trunks going up into them. Most importantly, you just need to export your terrains to mesh properly. This is one of the single easiest things to do to increase the performance on a nature dominant level that is 2048x2048. You should also throw some mountains and rocks around your outdoor level so you can cull stuff on the other side of it.
I’m not sure how much more input I can give at this time. I don’t mean any offense or anything like that, but I’ve already told you exactly how I would optimize your level. I could have literally just done it for you in the time we’ve going back and forth talking about it lol. Not gonna do that though. If you’re on a tight timeline, using a new tech like DOTS seems very risky to me and I don’t see how you thought that would save time. I don’t know that’s all I’ve got for now so I’m going to respectfully bow out for the time being. I have my own deadlines too
Cheers!
Yeah, no worries. You helped me a lot by giving me multiple insights. I will master this topic some time soon too. After Halloween, I will try the DOTS method myself and share my results here.
For sure! I wish you the best for your demo launch on steam. I checked out your page and it looks like an interesting concept. I look forward to seeing how it turns out!
So, I have at least “finished” converting trees to entities to present my results. I just did a simple test run with 20.000 trees with about 80 million vertices:
- As terrain, the CPU takes about 25 ms to render
- As GameObjects (GPU instancing on, static batching off, otherwise the GPU and RAM went full), the CPU takes about 20 ms to render
- As entities, the CPU takes about 5,7 ms to render
So entity trees are about about 4x faster for the CPU, at least for this simple test.
But there are some problems:
- I had to switch the material to the standard HDRP one for this test, as the custom tree shader does not render as an entity. They need to support DOTS Instancing.
- The Editor is not happy about so much game objects in the hierarchy, especially when you edit the prefab and it needs to update all its instances in the entity subscene, the RAM usage goes through the roof. Therefore, don’t put too many objects in the subscene, but create a proper Authoring, Baking and System to spawn them.
So entity trees look definitely promising and I am looking forward to terrain details as entities.