How do I make Occlusion Culling?

Hello World!

So I am currently making an optimization module. And I’m pretty confused on how I could make “Occlusion Culling” effectively and efficiently.

Most of the time, it uses way to much memory if the CPU is optimized enough. And then then it uses was to much CPU if the memory is optimized enough.

I tried raycasting if the parts are occluding the object behind it. I also tried the Camera:WorldToViewportPoint(–Corners of object) and then raycasting or comparing the z-depth of the vectors.

I also tried optimizing it if the object was visible last frame and then if it is visible now. I’m so confused on how to do this. Does anyone have any ideas?

Thanks.

1 Like

I got a few updates, I got a few things to work and then it pretty much failed a few minutes later.

1 Like

Late answer, and not sure if it is possible and if it would help.

Try “refreshing” the raycast less times and making it less precise(basically casting less rays)

I’m not a professional scripter or something but that’s what I got on my mind

Wait I have an idea, just a sec.

Roblox should add Occlusion Culling as a built-in feature. Well, it might be possible to do it manually, but there are games that are struggling with framerate and need heavy optimization.

4 Likes

I wanna be honest here, Occlusion Culling might make the game slower if there the map is really huge, so maybe Roblox should make Occlusion Culling baked in which people would have to bake the map first before occlusion culling is enabled.

That would probably be a better solution.

Or use the z-depth buffer. Ehh, who knows.

To do this, you want to construct the 6 planes that make up the view frustum of the camera (left, right, top, bottom, near, far) and dot your given world position with each plane. If the dot products are all negative you know the position is contained within the shape, and you can render whatever object you have.

1 Like

I did actually make a working way to do this, which is by having a function that returns the position of each corner in a geometrical object, then using :WorldToViewportPoint(), I checked if any of the corners can be seen, and if not, then somehow not render it (I don’t know how to do it, but to just check, I made it transparent)

That technique is not occlusion culling, it’s frustum culling.

That was my solution out of 5, it was the laggiest one out of them all, laggier than the raycast one.

I gave a more performant alternative to the WorldToViewportPoint function.
For actual occlusion culling, you want to get the corners of the bounding box that makes up an instance, project it to the near z-plane (making it 2D), then construct the largest 2d rectangle possible with the 6 given points. If any of the points are actually within the bounding box of the near plane z, you know its on screen. Anything else don’t render it and ignore it.
Then, once you’ve done this for all instances on screen, sort the list of rectangles from nearest z-depth to farthest. Then, for each rectangle, loop over all other rectangles that are both at higher z-depths and intersect with the current rectangle. and check if all the points are contained within the current rectangle. If they are, don’t render that object associated with that rectangular bounding box and remove it from the list.


In the picture, the red x’s symbolize the 2 points out of the 6 that are contained within the largest rectangle that can be constructed, making them extraneous. The brown box is an instance outside the frustum, and the yellow instance is an instance that can be occluded due to the red box.

I want to add that this is not true occlusion culling since its instance-based rather than triangle based, and that its probably going to be impractical (the performance of the script increase frame time more than the culling improves it). There is a reason Roblox does not do it themselves! You’re better off doing some sort of level-of-detail system, like what is used with Streaming Enabled.

Yeah I already gave up on this project a long time ago, as I could not improve the game’s performance at all.

I think it depends on how many parts you’ve got in the workspace. This method also tends to not render UnionOperations properly.