Improvement to a custom render distance system

I’ve created a render distance system for a game I work on that has shown to improve GPU performance a decent bit on higher graphics settings. It’s especially useful for Xbox which seems to have Roblox’s built-in render distance maxed out, so it saves a lot on performance in that regard.

I was wondering if anyone knew of some good ways to improve it. Right now, it runs on BindToRenderStep, but waits a certain number of frames before checking the distance of every single object that applies to the render distance system. This is what I think is the worst about it when it comes to performance.

Pretty much all I want to do is have it run faster. I was thinking it’d be possible to do it by using Region3 somehow, or disabling the system entirely for lower graphics setting users, but I’m not entirely sure yet. A place file demonstrating it and how it works is attached, with the script in StarterPlayerScripts.

tl;dr: How to make my render distance system (attached) more performant?

EDIT: For those who don’t want to look at the place file:

local renderRadius = 100 -- Render distance radius
local refreshFrequency = 10 -- Amount of frames to wait before checking the distance of objects

local renderFolder ="Folder", game:GetService("ReplicatedStorage"))
renderFolder.Name = "RenderCache"
local localchar = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
local localhrp = localchar:WaitForChild("HumanoidRootPart")

local treeParts = {}
for i,object in pairs(workspace:GetChildren()) do
	if object:IsA("Model") and object.Name == "RenderTree" then
		object.Parent = renderFolder

local irfs=0
local function updateRender()
	if irfs>=refreshFrequency then
		if localhrp then
			for i,v in pairs(treeParts) do
				local startPart = v:FindFirstChildWhichIsA("BasePart")
				if startPart then
					local partDistRender = (startPart.CFrame.p-localhrp.CFrame.p).magnitude
					if partDistRender>renderRadius then
						if v.Parent==workspace then
						if v.Parent==renderFolder then

game:GetService("RunService"):BindToRenderStep("RenderSys", 1, updateRender)

RenderSystem.rbxl (22.4 KB)


This does not directly answer your question, however I will point out that you should not be trying to optimize the performance for this if your game is not experiencing any performance issues.
Micro-optimizations only become useful in a situation where you’re noticing performance drops in the game, where improving the performance would have a tangible benefit. If your current system works well, then you shouldn’t be worried about micro-optimizing it as it is simply a waste of time.

Now to directly answer your question, you could render in ‘chunks’ instead of individual parts. Each map in your game could be divided into different “chunks”, or sections. You could then check which chunk the player is in, and render that one. The number of chunks that are rendered could vary on the render distance setting.

Your code currently gathers all parts in a circle around the character. You could only gather those within sight of the camera and cut down on half of your operations.


Wouldn’t that mean if the user quickly did a 180 degree turn of their camera, a significant lag spike would occur?

Also, I’m not sure why this version of the code snippet uses the HumanoidRootPart instead of the camera, it now uses the camera position instead.

You can avoid that by using some sort of space partitioning data structure. One commonly used in games is octrees. Here’s a tutorial, however it’s in the context of collision detection and uses C# rather than Lua.

Using such a structure puts every object into a “bucket”. You can then check the distance to each bucket, which can hold any number of objects depending on how exactly you implement your data structure, instead of checking the distance to each individual object.


A* Node Placement With Octrees might be of help here.

@Smeers can you tell me where BindToRenderStep stay, i can’t find it?
and can you tell me step by step how to make the player see from a distance with low graphics?
I still not understand wdym