Real world building and scripting optimization for Roblox

First, the caveat: Don’t prematurely optimize, just use PivotTo until you’ve established that you’re moving around enough stuff for that to be a bottleneck.

To absolutely maximize perf moving non-physics-simulated objects:

  • If you have a lot of similar things which you want to move around, where the internal structure of each of those things does not change and is under your control: The fastest by far is to combine all the parts into a single assembly with Welds (root part anchored and others unanchored) and BulkMoveTo the RootParts of each of those assemblies.

  • If you have a bunch of assorted stuff whose behavior is not uniform, where you calculate the updated positions in different ways / at different times, same as above but set .CFrame on the root parts rather than spending extra effort setting up arrays for BulkMoveTo.

  • If you’re writing a tool / library, and have a model with unknown contents to move, use PivotTo on the model.

15 Likes

Anything behind the terrain in that screenshot is going to count towards the scene draw call count, as well as any ParticleEffects and Clouds (if you have a Clouds instance inside your terrain). But anything off-screen won’t be rendered.

just thought I’d let you know since the render stats you posted shows there are 26,243 other potential instances that might be rendering in your game :slight_smile:

BTW, if you wanna see exactly how much something is impacting render performance, try deleting it and noting the draw call count before and after. Also make sure you don’t have anything selected, since selections in studio impact performance rather heavily.

5 Likes

Regarding using terrain, most of the time a terrain will stay under 250 draws and 250k triangles. It just means if you’re going to use terrain, plan for it to be half your game :slight_smile:

8 Likes

Appreciate the in depth detail,
Mostly definitely learned some new techniques. :index_pointing_at_the_viewer::sunglasses:

5 Likes

Useful for beginners. Though ultimately most will come to quickly realize that no, roblox does not exactly help you with those things nor it is exactly such a bangin’ engine. While these methods can help, ultimately they pale in comparison with what you could do to optimize in like every other 3D game engine out there EXCEPT roblox. We can’t even stream textures man! Talk about keeping the memory below 1.3 gigs yet we don’t even have a decent way to yknow, not run max resolution models on 2x2x2 stud models from like 200 studs away.

I’m not sure how you expect roblox to run at max graphics on a 2 gb of ram phone just via optimizing the standard toddler casino. The roblox client alone takes like tons of memory and any optimizations you could do can barely get the memory to budge at runtime. Anything you could do in studio CAN help a bit but ultimately youre still faced with the issue that the entire game world will always be held within memory without any proper way for you to ACTUALLY stream its contents in and out.

Also, streaming enabled is in fact, not good for very large maps (unless your definition for very large maps is like MAX 2048 studs of simple geometry). Streaming enabled in fact, sucks, and it sucks hard. Yet ultimately the roblox provided streaming is our only REAL way of actually making a difference due to the fact that the thing is actually capable of not loading the entire map when the client is loading, saving most users from memory related crashes. Streaming out everything is an entirely different story though (its slow and does nothing to improve memory afterwards).

Oh and im pretty sure meshes and unions are NOT as light as BaseParts as you might have said. From my experience with them they tend to be a double edged sword when it comes to optimization. It’s true that you could replace large part volumes with a singular mesh and save tons of performance however the same cannot be said about everything else. My general idea on how to properly use meshes and actually optimize them is in cases in which you could merge at least over 10 parts while also cutting down their geometry within blender or other 3D modeling software for further performance enhancements. But for short, a block BasePart is way easier to render than a block Mesh/Union. Same goes for all the other shapes. You should be conservative with meshes.

I dont know man, but i dont think youre being honest with yourself when you constantly boast about roblox. I don’t think roblox is trash but its clearly inferior to absolutely everything else out there. I’m just sayin, you could be getting paid more if we all had actually good proper ways of optimizing our games without make-believe optimizations (such as parenting stuff to nil to simulate the streaming in and out of geometry :confused: . Trust me, this is the only way i also have of optimizing my maps at runtime and it sure is a piss poor way of really doing things and won’t save systems with low memory).

Oh little nitpick but honestly it would have been nicer if these optimizations were applied to something else and not a super basic toddler casino. Those aren’t exactly hard to not make run like crap by default.

11 Likes

The Iphone 6s came out in 2015.

This is a photo of my iphone 6s running this project at max quality graphics. It runs at a stable 60fps. It does warm up, but it doesn’t thermal out.
Notice you can see to the horizon.

Same phone, memory usage here is about 780MB.

(Sorry had trouble getting the fps counter on exactly 60, my fps counters a little twitchy)

18 Likes

Great guide!

What’s a good way to budget your CPU? The problem is that if you don’t have an older device it is hard to test. Is there any other good practice around CPU usage or benchmarking? Is 16ms on the CPU a lot? What about 5ms? How can I find the optimal?

7 Likes

Useful for beginners

Cut out the downplaying. This is useful for all developers of different skillsets, not just beginners. I’ve been developing on here for 16 years now and there’s stuff I learned.

I’m not sure how you expect roblox to run at max graphics on a 2 gb of ram phone just via optimizing the standard toddler casino

Oh little nitpick but honestly it would have been nicer if these optimizations were applied to something else and not a super basic toddler casino. Those aren’t exactly hard to not make run like crap by default.

If all you got out of this article was how to optimize a “toddler casino”, then you missed the entire point of it and you’re again downplaying/belittling a very well thought out and useful community resource from someone who’s likely been making and optimizing games since before you were in diapers.

The techniques discussed here apply to any game of any style and scope. Every huge AAA open world game uses a lot of the high level stuff discussed here(even though specifics here are of course Roblox related)

If you can’t extract useful information out of it fine, but it’s more of an issue with your ability to comprehend and apply the information - and not an issue with the scope of the article.

Also, streaming enabled is in fact, not good for very large maps (unless your definition for very large maps is like MAX 2048 studs of simple geometry). Streaming enabled in fact, sucks, and it sucks hard. Yet ultimately the roblox provided streaming is our only REAL way of actually making a difference due to the fact that the thing is actually capable of not loading the entire map when the client is loading, saving most users from memory related crashes. Streaming out everything is an entirely different story though (its slow and does nothing to improve memory afterwards).

Streaming enabled isn’t perfect, but it is most certainly helpful for large maps especially with terrain - and saying it does nothing to improve memory is comically wrong, it kinda sounds like you’re just saying stuff without any real data backing it

i dont think youre being honest with yourself when you constantly boast about roblox. I don’t think roblox is trash but its clearly inferior to absolutely everything else out there. I’m just sayin, you could be getting paid more if we all had actually good proper ways of optimizing our games without make-believe optimizations

Where in this article is he just “boasting about roblox”? None of the stuff here are “make believe optimizations”, it’s all very well documented here with data and performance stats to back it up. Something you haven’t done with absolutely anything you’ve said

36 Likes

It’s rough without being able to test on device.

As a general rule, my iphone 6s is about 3x-4x slower than my PC in terms of CPU, meaning if I take 4ms of cpu on my pc, my phone is taking 12ms-16ms. Which may or may not be useful for you.

… and I know it’s no help, but a refurbished old iphone will set you back about $50 :slight_smile:

7 Likes

This tutorial is really useful for experienced developers!

I managed to keep my mobile budget below 2GB using many of these techniques in my current project. On mobile I’m reaching not even 800MB despite making heavy use of textures, meshes and other ‘traditionally expensive’ features.

Certain features like Roblox’s level-of-detail system for meshes (and I believe they have also experimented with lowering texture quality dynamically recently) may also be helping me out quite a bit here - though I haven’t found a great way of measuring this yet.

Kitbashing is also very underrated. My maps reuse a lot of meshes in creative ways, like how I’m reusing grass sprouts as sea weeds. I’m also using custom MaterialVariants in many places so I can get away with lower texture resolutions given their tiling behavior.

image

I think a lot of people are being dishonest about how well-optimized Roblox actually is, considering Roblox runs on an interpreted language (Lua) and cannot make assumptions for optimizations. At any moment a developer could run some code in the developer console to unanchor whole buildings, waking up the physics engine and requiring the rendering engine to suddenly update many shadows and lights. Roblox’s engine is arguably the best engine out there in these cases and makes Roblox development very approachable for new users.

I think this example project is a perfect choice as a demonstration as well because many developers will start out making such projects, yet they contain very common performance pitfalls:

  • Many active physics objects
  • Large open worlds
  • Many objects that may not batch into a single drawcall

Amazing article, great work!

22 Likes

I love you chicken man. I really do, I love you so much

6 Likes

I’m not downplaying anything, I’m just thinking that while the stuff here can help and is useful, nothing here is anything too crazy to be honest. It’s things i believe most more experienced developers have seen already with some added new things and some additional explanation.

My point isn’t that the entire article was written to teach people how to optimize those sorts of games, I’m just saying that the standard simulator (toddler casino!) isn’t exactly a good example for what optimizations can really change. Hey a open world game for example would have been way better to use as an example instead! Or at least something with a scope higher than a casino for toddlers.
Also while its true that every huge AAA open world (along with most AAA games) uses most of these techniques. However you cannot deny the sheer gap in efficiency between roblox and those AAA games. AAA games actually allow for way higher levels of optimizations which in turn allow for pretty massive and detailed open worlds but not roblox. On roblox all we have when it comes to really pushing the bar and trying to create a massive open world is hoping that the roblox provided streaming will save people loading up the client in said games for the first time from crashing and that’s it.

Streaming only really works on smaller maps. Again i have to ask, what’s the definition of a large map?
As for the memory related issues then here. I got a pretty simple example. I can provide more if you’d like. I don’t claim to be the master of streaming enabled but do believe i at least know how bad it is and how little it does to improve things memory wise.

The example i will give you has in TOTAL 51240 BaseParts.
Standard Part Count: 41610
Union Count: 1850
Mesh Count: 7192

Here is 3 instances of the same spot. Each instance has 3 images showcasing the scene, the client provided memory usage and the task manager provided memory usage. Did 3 instances so i know memory usage dosent magically fluctuate on one instance:

As you can see, all 3 examples provided are very similar. Now lets finally get into testing out streaming enabled.
These are the settings i will be used for streaming:
image
The overall view distance of streaming is set to pretty high values due to the fact that the map itself is actually unplayable if you use standard numbers. With normal way lower settings you could barely see in front of you and would actually take away from gameplay.
Even right now i believe low but it IS playable.
StreamOutBehavior is set to Opportunistic because LowMemory will actually not stream out anything.

Here i will do yet another 3 instances of 8 images each. The first image will display the memory usage within the default spawn area. Second image will display the task manager memory usage. Third and fourth images are going to be the same except i will be traveling to the other side of the map. Fifth and sixth will be the same except i will come back from the other side of the map to the spawn once more. The seventh and eight will showcase memory usage from the spawn AFTER i had visited every area of the map.

As you can see, as i’ve said before the ONLY TIME streaming enabled really does something is when you first join a game and THATS IT. Even THEN it struggles quickly loading everything as i travel across the map. In half of the examples i had to even wait a good few seconds to get the map to stream out. It can even increase overall memory usage after i had explored the entire map even though everything should be streamed out!
Lets not ignore the fact of how streaming enabled seems to magically also ignore/skip some of the parts from the map as you can see from the images. I had MADE SURE everything is set to CanQuery = true before doing all these tests yet nothing.

As another example, you can see in all these examples i have a menu called “Geometry LOD Control” which is basically my own personal solution for streaming enabled. It’s worlds above what streaming enabled can do! Worlds faster! Worlds more efficient! Worlds more customizable! Nearly EVERYTHING better! The only down side is that of course, it does not have the benefit of not loading the entire map when the client initially loads. (Oh and to be transparent it also suffers from the same part ignore issue streaming enabled does, this is something i need to iron out).

As ANOTHER example. Here i have actually TRULLY massive map:


This map is currently unfinished however i do have its general size calculated. Its around a rough 200kx200k studs in size. At max graphics you can only render HALF of it at once. That’s how big it is. So with that, here’s memory usage without any streaming within roblox studio. (Task manager numbers are nearly identical so i wont show those)

It’s using a massive 10 gb of ram! And of course it does use way less memory in a real game instance.
Here’s memory usage within a real game instance! (This is of course without any streaming)

And the task manager memory usage:

Absolutely massive memory values still! So the solution is streaming enabled, right? No!
Well this is how my studio looked like for around 10-30 or so minutes trying to load that magical streaming:

I am not kidding, it took ages for studio to load up the play test. But after a long while it did finally load, and this is the memory usage:

Considering the playtest alone takes 10 gb, it would mean streaming enabled added a whole 35 gb of memory. Very usable for my large map i know.
Now what about an actual game client? Can’t test because the server crashes when trying to load.
Streaming enabled is actually useless for this sort of map and its why i have my own solution for streaming (which ultimately again, does not have the benefit of not loading the entire map at once yet its the only thing i have)

I’m just pointing out how Chicken says how Roblox helps you out a lot with magical automatic quality scaling (which is pretty mid at best). Or how roblox is such a “bangin’ engine” which is clearly not. The reality is that roblox pales in comparison to any other game engine due to how limited, restrictive and full of magical automatic features. I don’t think roblox sucks, i like it but ultimately i cannot lie to myself and say that roblox is amazing and how good it is. I only wish for roblox to become better all day every day man.

Low blow, pretty mean actually. I can also be mean about those sorts of things but i won’t because its not nice. This isn’t a battle between 12 year olds about who’s cooler than who. Him doing this for way longer than me doesn’t instantly mean he can just invalidate everything i have to say or do instantly. Hey in fact i believe he was wrong about the point in which he said meshes are as light as parts. I had even done testing using the same geometry on both standard parts and meshes and quickly found out meshes are way more demanding than standard parts. As said before, meshes CAN help you optimize however you cannot use them as standard part substitutions. Meshes only help when you can convert a large sum of parts into a single mesh WITH ALSO cut down geometry.

Regardless, i will not believe for a second you can properly optimize a roblox game when the primary way of streaming maps is either using streaming enabled (which feels like parenting geometry to nil after initially loading it) or parenting geometry to nil. I do believe a lot of the explained methods to optimize things around a map could help but ultimately on roblox there is just so much you can do to optimize before you’re entirely forced to cut down your game (or not make anything crazy by default) just to have something that runs reasonably well. This is not an issue anywhere else and only on roblox.

8 Likes

Thanks for this very handy article!

I’m wondering if there’s a specific reason for the custom non-physics pet movement.
Would having a client-side physics simulation for the pets (using bodymovers) have noticeably worse performance?

In my eyes, using roblox physics seems easier/faster to implement, though ultimately a custom solution would give you more control.

1 Like

BodyMovers are pretty bad for perf due to the fact that they force crank up the physics sim rate to 240Hz to themselves and any assembly attached to them.

2 Likes

Very nice read, I might look into that pet system in detail… unfortunately I don’t think I can use much of anything else in the article, as my games have procedurally-generated maps and very high-part-count physics objects getting blown to bits as a regular occurrence. Still good to know, regardless…

1 Like

hi!! amazing resource, i will definitely put some of this to use in my game! two things i noticed however while working with the distance culling script is that it’s very finnicky out of roblox studio. in roblox studio it works perfectly fine, however in an actual server there seems to be two issues. first thing i noticed was that increasing the culldistance above 300 seems to somehow mess something up, as nothing is culled after that (even if the distance is only, say, 20 higher), and even when it’s working correctly when the culldistance is set to 300, the distance of objects being culled is vastly different in a server compared to in studio (objects are culled much closer compared to in studio). any idea on why these issues might be coming up?

EDIT: the issue was that i was using folders to group my tagged objects instead of models with assigned primaryparts.

2 Likes

i should clarify that i was testing this script in my own game, not the one you provided, however i changed next to nothing about the script so i’m unsure why there’d be any differences. it works as intended inside of studio testing.

1 Like

If you’re using it with streaming enabled you should probably set the culled models to atomic

1 Like

I’m not using streaming enabled, streaming enabled breaks my game due to how the camera works : P

1 Like

Let me know if you work it out!

5 Likes