The issue with custom culling systems is that they use replicated storage which still costs memory, this issue is not present with Streaming Enabled. Correct me if I’m wrong.
I know this is kinda late but uh do you still recommend using this service? Or is this outdated
It depends on your use case.
If you want precise control over which assets are streamed/culled, at what ranges, how that looks, etc. then yes, I would recommend this. To further expand, the biggest overall advantage of CullingService is complete control while still getting performance benefits from streaming/culling. This can be essential for very ambitious projects where StreamingEnabled’s more-or-less one size all implementation either blocks you from being able to fully realize what you are trying to create or may possibly cause an impediment with future updates that are rolled out indiscriminately. With CullingService, you control everything.
If that does not apply to you and you want a fire and forget method, then I’d recommend utilizing StreamingEnabled. Roblox is investing lots of time into this and its default engine behavior which allows for better under the hood optimizations and performance (at the expense of less control by the creator).
Hello it doesnt seem to be working for me I tried to compare my file to the demo file and im not sure what I did wrong
My discord is zirdic if you want to communicate there
test.rbxl (144.2 KB)
This doesn’t really “replace” StreamingEnabled
directly. A quick look at the source code reveals that this module only removes a copy of the model from the workspace when culling it, and still stores a copy in the ReplicatedStorage
.
This module actually adds overhead as models need to be constantly cloned and destroyed, and also doesn’t reduce the memory usage (rather increases it as two copies of the whole map are kept on the client - one in the workspace and one in ReplicatedStorage
.)
StreamingEnabled actually streams the model’s info from the server to the client so that the client doesn’t need to store it when its far away, reducing memory usage.
Yes, it does provide developers with more flexibility.
Yes, it does reduce rendering load. But it doesn’t really help with memory usage reduction, which is one of the biggest use cases for StreamingEnabled
I wonder what lead you to create this, would love to hear from you
Debug Steps
Name all of your models something unique (unless they are duplicates, in which case they can have the same name)
https://i.vgy.me/eB4hSh.png
Use the plugin (link in the original post) to add Anchor Points (you don’t put the actual models in there).
Before
https://i.vgy.me/Nc9LfK.png
After
https://i.vgy.me/2vuoyE.png
Create folders in all of your models that correlate to the Range Folders in Culling Service’s settings
https://i.vgy.me/evPb4a.png
Either set ‘AutoStart’ to true or call CullingService:Resume manually in your code
https://i.vgy.me/f3nRmX.png
Fixed place file: Debugged test.rbxl (143.8 KB) [I moved the spawn to make it easier to test, so don’t be alarmed that the house spawns in very close - it is where you originally had it placed]
The biggest issue is that AutoStart (in Settings) was set to false and the example code does not explicitly call CullingService:Resume()
. The code in the Roblox Library model and GitHub has been updated to default set AutoStart to true, which is also consistent with backwards compatibility checks that set AutoStart to true if not detected in the user’s settings
Correct, philosophically CullingService and StreamingEnabled approaches are completely different in how they aim to optimize a place.
I believe I’ve made this pretty clear here: CullingService V2 - Custom Client Sided Culling/Streaming Module
and as recently as earlier today (there may be other posts also on the thread): CullingService V2 - Custom Client Sided Culling/Streaming Module - #43 by https_KingPie
Incorrect, although I can see why you came to this conclusion if you just peaked at code alone. Only one reference model is kept in ReplicatedStorage (ModelStorage). This gives you the advantage of allowing a large forest of say, 10 tree variants each with 100 copies (total 1,000 trees), to be stored as only 10 models and then selective cull in the necessary number of trees based on the player’s location (ex: only 35 are loaded at any given time). While I haven’t personally done performance benchmarking of what this would look like (either standalone or compared to StreamingEnabled), conceptually I don’t think anyone would assert that you wouldn’t see a significant performance increase.
Yes, CullingService is entirely client sided. The server does not need to be concerned about tracking what every player ought to see and ought not to see - clients can determine this for themselves (any worry of exploiting is somewhat small, given that map deletions/additions (ex: btools) can be difficult to detect in the first place without relying on client sided detections and any serious concerns or mechanics that depend on this should already be verified by the server). Of course, there are some exceptions to this (ex: when the server needs to determine whether two players are in actual line of sight of each other — this could be tricky if buildings and obstructions only appear on the clients themselves. That’s an example of a use case where StreamingEnabled might be preferable, unless the developer wants to get creative)
I designed CullingService to support a large RPG project that necessarily required streaming optimizations, but at the same time I wanted more control than Roblox inherently gave me (ex: specifying which assets get streamed and which don’t, controlling what ranges certain things appear [and giving player’s the ability to adjust these themselves to tailor their own load], aesthetically make streaming elegant by implementing custom visuals when assets streaming in or stream out, etc.) Pretty much every feature within CullingService was designed for my own project, but I decided to open source it because the initial effort was superbly annoying and I wanted to save other people the hassle if they wanted to create something similar.
StreamingEnabled is a great tool, but it’s inherently inconsistent. That’s not from the standpoint of gameplay reliability — Roblox is doing a good job of dedicating more time and effort into StreamingEnabled which is awesome — but more so from the standpoint that if an update is pushed tomorrow that suddenly breaks StreamingEnabled or causes it to perform weirdly, you more or less have to take that and then do damage control from there. CullingService is one of many examples of developer created alternatives to maintain exact control of what is going on in the game, mostly independent of engine behavior. It’s not going to be perfect for all games or all games that use StreamingEnabled, as mentioned before it is not at all a 1:1 replacement and the philosophy is entirely different.
Thank you
so besides me not setting the autostart to true did I do anything else wrong?
Is it possible to create your own custom regions, and dictate what models are culled based on the player being within them, as opposed to using the built-in regions?
It’s not possible to change the regions (culling service creates those automatically), but you retain full control over which models will be culled in and which are not.
When I install the plugin, it doesn’t appear in the toolbar.
Hi @https_KingPie, is there a how-to video on how to install CullingService V2? If there is, please link it here.
Many thanks! A video will help us a lot with the setup.
Do you mind making a youtube video, I got stuck on step 6…
So confused where I should put the localscript, and how can I call CullingService if its not a global variable?
Please make a video tutorial.
I’ve been having an issue with this, the assets load perfectly fine on some phones and some pcs but for others they don’t. How could i troubleshoot this?
Are you players getting an errors or warnings in their output? Feel free to hit me up in private messages or via the community Discord as well.
Omg this is so useful! I’m working on a game where the playerbase is 90% mobile so this will definitely improve the performance.
I just need quick question answered though. Where do I put or create the Short, Medium, Long folders? I tried putting them in ModelStorage with the models inside and the same thing for AnchorPoints. I’m not a scripter so sorry if it’s a dumb question.
They go inside the models themselves.
For a good reference, check out: CullingService Testing - Roblox which is uncopylocked and shows the whole set-up. You can customize the ranges that models appear within CullingService > Settings
is this still useful now a days ? I plan to make a building rendering system and I am planning to make one like yours that can help with the task I have. however mine will allow me to use some other systems I’ve already made. but is it worth it still or would other stuff made by roblox studios be a better option like streaming enabled.
Hey there and great question, this is something that I’ve been meaning to address for a while, especially with occlusion culling on the roadmap. Bear with the long answer.
TL;DR: It depends on what you value; below it is broken into key points.
Control ‘what’ is streamed in and out
CullingService (CS) was sparked because in 2021 StreamingEnabled was really restrictive. Everything was streamed in/out or nothing was. The main point of CS was control of what streams in and what does not. StreamingEnabled has this to a degree with ModelStreamingMode
. If that is all you are concerned about, then StreamingEnabled may be the better choice.
Control ‘how’ streaming works
CS does offer model streaming ranges, which is another way of approach level of detail. Roblox does not natively support this through either StreamingEnabled or the LevelOfDetail
property in models. This is because CS allows you to specify at which ranges certain instances within a model will appear on the client, so you can precisely the visuals of your game versus working around auto handling. If that is a concern for you, consider CS.
CS also offers signals to know when things are culled in/out (to include whole models or parts of models culled in/out at certain ranges). That’s a major plus if the alternative is connecting to workspace.DescendantAdded
or workspace.ChildAdded
. If that is an advantage, consider CS.
Control how streaming ‘looks’
CS offers aesthetic controls for models and it is very easy to create your own. What this means is that you can build streaming into your game as an aesthetic. For example, you could run through the a low poly cartoon style forest and see trees springing up around you. That’s a cool aesthetic that’s very easy to accomplish with CS (and included as an animation preset) and basically turns an optimization technique into a feature of your game’s identity. You can’t do that with StreamingEnabled - stuff will just blink in/out. If that is an advantage, consider CS.
Support for motion and other possible edge cases
None of my experiences have really worked with motion + StreamingEnabled too much, so I’m not sure how much of an issue this still is (I believe it used to be one). With CS, you can stream in/out moving parts without desync across clients or issues with Roblox physics. For example, you could build a busy city street with car-to-car moving/dynamic traffic and comfortably stream everything without issue. That might not be an issue any longer with StreamingEnabled, but having a streaming solution that you can write to and change does let you handle weird edge cases that emerge with how Roblox features interact with games. If that is an advantage, CS might be a good choice.
Overall Performance
Neither has been benchmarked against each other and to be honest, I’m not sure a great way to do it. StreamingEnabled will benefit from being built into Roblox’s engine, so it can make use of things that CS simply can’t. With that said, CS is scrappy in the sense that what I’ve been able to optimize, I have. For example, if you had a forest of 10,000 duplicate trees - CS would only save one of the trees in ReplicatedStorage and simply clone it in as necessary. StreamingEnabled might save 10,000 trees internally. That’s not fear mongering or an indirect push to CS, we just don’t have visibility on how StreamingEnabled really handles that stuff on the backend, unless an engineer on the team for that feature can comment. CS might have the edge there, it might not. Similarly, I’m not sure how the two systems compare in a forest of 10,000 unique trees. StreamingEnabled might win out, it might not. CS also doesn’t cull in those instances on the server - only the client. That probably complicates a thorough benchmark/comparison, because that significantly reduces the load on the server’s end, especially for things concerning physics (for those who haven’t used CS, the perspective from the server could potentially be an empty baseplate with players running around, whereas for the players they would have a whole world culled in/out around them)
However, I can say that both solutions will help your game. It’s probably just a factor of how much and how your project is set up that might specifically inform those results.
Hope that helps in breaking down (what I see as) some of the key factors in deciding what to go with. If I can clarify anything, let me know.
That’s okay And also, thanks for making the module a lot of way its structured is how I’m making my own just slighting different tho due to it having a slightly different task. Also one thing I did notice is that a we could make a steaming enabled like system for objects that are only seen on the client, and it should work the same way as Streaming Enabled by Roblox, the only difference is no signal firing. ( the server sends signals to the clients telling them to load/unload that stuff ) . If you look bellow all its apparently doing to unload them is setting there parent to nil. and then some other stuff that make sures the server knows that players object is streamed out.
Quote
“When an instance streams out, it is parented to nil so that any existing Luau state will reconnect if the instance streams back in. As a result, removal signals such as ChildRemoved or DescendantRemoving fire on its parent or ancestor, but the instance itself is not destroyed in the same sense as an Instance:Destroy() call.” Signals related to destruction do not fire on stream out.
So if Streaming Enabled sets the stuff to nil and doesn’t do something else with them other then tell the server. A client-sided Streaming Enabled for client sided objects only that sets them to nil to stream them out , I believe would work the same way as a roblox one and there wouldn’t even be any network data signals being fired its not even on the server.
But the only reason my system should work like this is because these objects don’t get affected by the server. For other games that require the object to be interacted with by many people and move, the thing I’ll be working on would NOT work. But for client-only objects, like the ones I’m working with, the way your system loads/unloads—and me adding a few stuff to allow it to work for my things I believe would work well. Lastly this system could work with streaming enabled while streaming enabled handles the server sided objects this handles client sided.
Also I have a question about your system the only problem I don’t know (and haven’t tested) is: Does the client still get network data increases if that object is streamed out by your system and the server starts doing stuff with the part?
( also sorry if spelling is bad I’m trying to type this on mobile )