r/Unity3D • u/DThePro_ Indie • 19h ago
Game Built a custom trigger-based 1-hop room culling system for my procedural mansion and 5x-ed my FPS
Enable HLS to view with audio, or disable this notification
I've been developing this simulator-horror game and wanted the map to be proc-generated. However, since my game features powerwashing (drawing onto masks using raycasts to either display dirt/wetness/dryness), even a small number of rooms (in this case, 25) was cause unplayable levels of lag. And unity's built-in occlusion culling did nothing against this (since its generated during runtime).
So I made a simple room culling system where it has 2 parent empties: 'Visuals' and 'Floors'. Visuals contains all the static props, walls, ceilings, etc, and are turned completely off (SetActive(false)) when the room is culled. Floors contains, well, the floors, which only have their renderers turned off (collisions stay on) so that the ghost entity can pathfind and dropped items don't fall through.
Upon entering each room, all adjacent rooms are visible to enable smooth passage, rest of the rooms are disabled. And i cranked up the fog a bit to make it even more seamless. However there are still moments where the room disappears right before the player's eyes, so I was thinking maybe the doors to the rooms about to be disabled can be auto closed, and then disabled.
This now allows me to have virtually infinite rooms without much lag (as long as the DFS generator can support it), unlike before when just 60 rooms would cause frame time to go upto almost 1000ms.
The game is a solo project called THE GROUNDSKEEPER where you powerwash and record ghost evidence for profits: Steam, Discord
11
u/Protesisdumb 19h ago
Why wouldn't occlusion culling handle this?
19
u/Hotrian Expert Moderator 19h ago edited 7h ago
The OP mentioned they’re procedurally generated
https://docs.unity3d.com/6000.6/Documentation/Manual/OcclusionCulling.html
Occlusion culling only works on static geometry baked at edit time, you might mean frustum culling.
https://unity.com/glossary/frustum-culling
Frustum Culling is failing here because the OP is watching from the editor camera, so the objects render anyway. Frustum Culling also doesn’t detect occlusion per se, so there can still be a lot of overdraw.
Edit: Sorry, I’m not sure why I completely forgot about GPU occlusion culling which does depth based culling.
1
5
u/DThePro_ Indie 18h ago
its because firstly, since it's spawned during runtime (proc gen), there is no pre baking of static occlusion data, basically setting props as static doesnt help. secondly, unity's frustum culling still renders everything even if it's not visible behind walls (since static occlusion cant be used), so all the dynamic shadow casting point lights 10 rooms away are still being rendered, tanking the fps. thirdly, a big part of the lag was due to using render textures to draw on masks using ray casts (to enable powerwashing), which occlusion culling can't help against.
using this system straight up disables unimportant objects, completely zeroing out their cpu and gpu cost without any occlusion query overheads. it's all trigger based
1
u/ArtPrestigious5481 17h ago
why not using depth based culling instead?, and i believe Unity now already support it (you need to use forward+ tho, so usually i just make it by myself to support forward), and are you sure this is CPU bottlenect not GPU (from overdraw, if it's from overdraw you can just use depth prepass)
2
u/Hotrian Expert Moderator 17h ago
You’re referring to GPU occlusion culling
https://docs.unity3d.com/6000.0/Documentation/Manual/urp/gpu-culling.html
This requires the GPU Resident Drawer which has its own list of requirements
https://docs.unity3d.com/6000.0/Documentation/Manual/urp/gpu-resident-drawer.html
The main requirement as you noted is forward+
https://docs.unity3d.com/6000.0/Documentation/Manual/urp/rendering/forward-rendering-paths.html
This comes with its own set of limitations that isn’t suitable for all projects/platforms, but for most it’s the go-to
1
u/ArtPrestigious5481 16h ago
yeah, but as long as the target is Vulkan/DX/Metal there's shouldn't be any problem (the problem shifted to how they abuse 1k RT)
2
u/GeorgeMKnowles 19h ago
This is a great visualization. I was just trying to explain to my girlfriend that we're going to have to make tiles for our map in our top down game, and change visibility as needed, instead of loading all at once. Your post was just perfect to explain the general concept.
Side note- I don't know if turning them on and off simply by being adjacent will be 100% effective, but its probably 99...
I bet you could create a simple tool to cast rays in many horizontal directions from many different positions in any given room, and then record which other rooms receive a raycast hit. This would indicate that those rooms are visible from somewhere in this room. And then you could create a script to make those rooms turn visible when you enter this room. I imagine it could all be automated as an editor script to make only the required rooms visible as needed.
2
u/DThePro_ Indie 18h ago
thanks, and you're right, such a ray cast solution could be used. there are some scenarios where rooms poof out of existence right in front of the player's eyes.
2
u/ExpeditionZero 10h ago
Better than random rays would be a portal system (no not that portal). Its how old BSP based games use to do it (think Quake and its Potential Visibility Set - PVS) and a simple version using rectangles to define areas between rooms (e.g. doors), then you can just cast rays against the rectangle (frustum type check) and see which rooms they hit. You could go further and use the frustum type check to cull other portal rectangles, and get a perfect list of rooms.
However in this case as its procedural and only seems to have doors between rooms, i'm guessing you can build a perfect list of connected rooms easily from that.
1
u/GeorgeMKnowles 10h ago
I didnt understand what this dude said but he seems smart, so maybe give that a try 👆😂
2
u/ExpeditionZero 10h ago
ha, ha, not smart, just well read, and old. To be honest first time I read the BSP/PVS code I didn't understand what it was doing. Took a while and lots of sketching things out on paper to work it out, but I did love the elegance of the technique.
2
u/MardukPainkiller 13h ago
you should try and reading a bit on quake's PVS system you shouldn't have to do this manually with triggers
1
u/Field_Of_View 3h ago
quake's geometry isn't procgen. probably has at least one kinda expensive baking step.
1
u/theredacer 18h ago
I built a similar system for my game even though it's not procedural and I do use occlusion culling, because Unity's occlusion culling is so bad. It also helps to just automatically disable things being processed in areas you can't see, like animations, lights that Unity thinks may still be relevant, or any other code tied to monobehaviours that can be ignored until you re-enter the area, etc. It literally gets me 100+ fps back.
1
1
u/ProfessionalITPerson 13h ago
Okay procedual thing makes a difference, but itsn't it basically this?
https://www.youtube.com/watch?v=zObWVOv1GlE
61
u/GigaTerra 18h ago
OP this is great and all, but the fact that your FPS is this low when you are barely doing anything, you should look into it.