So I am someone who loves goofing around and I saw a video on youtube by Byteblox where they created something that allowed them to make the game look like its being rendered on a different framerate!
So I decided to make my own! And here it is!
features
There are a couple of features that this thing has so I am going to go over them.
The renderer contains a module, you can change the properties their!
CustomRenderingOn: With this enabled the renderer will actually do stuff!
framerate: This is how fast the renderer well, renders! Very exciting!
renderLocalPlayer: When enabled render the local player
renderOtherPlayers: When enabled render the other players, that meaning this wont render the local player
renderWorkspace: When enabled this will render whats going on in the workspace, such as parts moving or um, thats all I can think of.
UseOGTransparency: When enabled it will save the original transparency of parts that it renders, without it on parts will be limited to either having the transparency of 1 or 0.
Extra
SomeVideos
PS: with the other multiple players due to ping this effect is kinda there to begin with so it may look about normal
Notes
Note that the framerate only effects the things you see, so it will not change when sounds play, things actually moving around, things taking damage, etc.
Get it!
Due to roblox being silly I am currently unable to upload it as a model and/or package
I made a renderer myself using this zone module and I have some code that might be a good starting point.
local function IsInView(object,cameraViewportSize)
--if math.abs(object.Position.Y-localPlayer.Character.HumanoidRootPart.Position.Y)>50 then return false end
--print(object.Position)
local objectPosition = camera:WorldToViewportPoint(object.Position)
-- Check if the object is within the camera's viewport
--print(objectPosition)
if objectPosition.X >= 0 and objectPosition.X <= cameraViewportSize.X and
objectPosition.Y >= 0 and objectPosition.Y <= cameraViewportSize.Y and
objectPosition.Z > 0 then -- Z > 0 means the object is in front of the camera
return true
else
return false
end
end
local minRenderDist = 20 -- Minimum render distance
local fpsThreshold = 30 -- FPS threshold below which render distance decreases
-- Calculate adjusted render distance based on FPS
local function calculateAdjustedRenderDist(maxRenderDist,fps)
return maxRenderDist - (maxRenderDist/2) * (math.max(fps, fpsThreshold) - fpsThreshold) / (60 - fpsThreshold)
end
--lower fps shorter render distance
local function checkobjects(pos)--check if object is in view and
local cameraViewportSize = camera.ViewportSize
local fps=playerGui.CharacterSelect.FPS.Value
local adjustedarray={}
for i,v in DistanceArray do
adjustedarray[i]=calculateAdjustedRenderDist(v,fps)
end
for i,reference in objects:GetChildren() do
if reference:IsA("BasePart") then
local renderdist=adjustedarray[reference.Name] or nil
if renderdist and (reference.Position-pos).Magnitude<renderdist and IsInView(reference,cameraViewportSize) then
reference.CanQuery=true
else
reference.CanQuery=false
end
end
end
end
Very cool! I’m actually going to use this to not cull but lower the render time of objects far away from the player as well as some other things!
I’ll let you know when I’m finished with it
Going to the following modules to do this.
Part cache
Zone (good one)
Xenon streaming engine
Instance editor
I’m messing around with it again, this isnt public yet but I’ve created a noir shader:
Anyhow currently Unions are broken sadly, I had to lower the framerate due to lag so now I am using your idea @Magus_ArtStudios , It defiantly needs a render distance now lol
Render distance almost works, it looks a little off considering what it does, so Im going to create something to fix the problem
(I have created a module that allows me to loop through all properties in a basePart. Ik pretty cool, This is also works for MeshParts and BaseValues. When I’m done with this module I’ll probably release it)
I recently wrote a new Renderer becuase the method I mentioned earlier using the Zone module was redundant because I’m using occlusion culling calculations. In short this renderer has caused an increase of about 5-13 FPS in my use case. A good way to reduce calculations is to create a part object in place that is the result of the object not being in view, then just check the part objects if they are in view and unpack them when necessary. That’s how mine works and it saves calculating the distance of objects. Also, multi-threading your renderer to like 4-8 may increase its performance. I handle all caching on the server with 3 different actors and like 8 object categories with different rendering distance. They never exceed about .15-.25% CPU usage on the server and this section can be done very slow because rendering out is lower priority than rendering in which is handled on the client in my case. Using this code snippet which may provide some hints for your project.
-- This creates a zone for every ambient group, then listens for when the local player enters and exits
task.wait(.6)
--local Zone = require(game:GetService("ReplicatedStorage").Zone)
local localPlayer = game.Players.LocalPlayer
local playerGui = localPlayer:WaitForChild("PlayerGui")
local Remote=game.ReplicatedStorage.GlobalSpells.ZoneRemote
local zonearray={}
local id=0
local payloadarray={}
local DistanceArray = require(game:GetService("ReplicatedStorage").Zone.RenderDistance)
local camera=workspace.CurrentCamera
local objects=workspace.TouchBox
local function payloadcache(container)
table.insert(payloadarray,container)
end
-- Calculate adjusted render distance based on FPS
-- Example usage:
local fps = playerGui.CharacterSelect.FPS.Value
--local adjustedRenderDist = calculateAdjustedRenderDist(fps)
local function IsInView(object,cameraViewportSize)
--if math.abs(object.Position.Y-localPlayer.Character.HumanoidRootPart.Position.Y)>50 then return false end
--print(object.Position)
if object.Name=="FurnitureRender" or object.Name=="PlantRender" then
return true
end
local objectPosition = camera:WorldToViewportPoint(object.Position)
-- Check if the object is within the camera's viewport
--print(objectPosition)
if objectPosition.X <= cameraViewportSize.X and
objectPosition.Y <= cameraViewportSize.Y and
objectPosition.Z > 0 then -- Z > 0 means the object is in front of the camera
return true
else
return false
end
end
local minRenderDist = 40 -- Minimum render distance
local fpsThreshold = 30 -- FPS threshold below which render distance decreases
-- Calculate adjusted render distance based on FPS
local function calculateAdjustedRenderDist(maxRenderDist,fps)
return math.max(minRenderDist,maxRenderDist - (maxRenderDist/2) * (math.max(fps, fpsThreshold) - fpsThreshold) / (60 - fpsThreshold))
end
local Tick=game.ReplicatedStorage.GlobalSpells.Tick
local writetime=Tick.Value
local arrays={}
local refresh=6
local function getobjects()
if Tick.Value>writetime+refresh then
arrays=objects:GetChildren()
writetime=Tick.Value
end
end
--lower fps shorter render distance
local RefreshRate=.6
local function checkobjects(pos)--check if object is in view and
local payload={}
local cameraViewportSize = camera.ViewportSize
local fps=playerGui.CharacterSelect.FPS.Value
local fpstiming=playerGui.CharacterSelect.FPSTiming.Value
local adjustedarray={}
for i,v in DistanceArray do
adjustedarray[i]=calculateAdjustedRenderDist(v,fps)
end
getobjects()
--local arrays=objects:GetChildren()
local amnt=math.max(1,#arrays)
local throttle= RefreshRate/amnt
local increment=math.max(1,fpstiming/throttle)
local state=function(reference) if reference.Position.Y<-16 then return adjustedarray[reference.Name] or nil else return nil end end
if pos.Y>-16 then
state=function(reference) if reference.Position.Y>-16 then return adjustedarray[reference.Name] or nil else return nil end end
end
local current=0
task.wait(throttle)
for i,reference in arrays do
current+=1
if current>increment then
task.wait(throttle)
current=0
end
if reference:IsA("BasePart") then
local renderdist=state(reference)--adjustedarray[reference.Name] or nil
if renderdist then
local lengthvector=(reference.Position-pos).Magnitude
if lengthvector<renderdist and IsInView(reference,cameraViewportSize) then
table.insert(payload,reference)
--reference.CanQuery=true
table.remove(arrays,i)
elseif lengthvector>math.min(300,renderdist*2.5) then
table.remove(arrays,i)
--reference.CanQuery=false
end
else
table.remove(arrays,i)
end
else table.remove(arrays,i)
end
end
--arrays=nil
state=nil
return payload,amnt
end
local function RegisterLoop()
spawn(function()
--one payload per second
local prevpos=localPlayer.Character.HumanoidRootPart.Position
while true do
if camera.CFrame~=prevpos then
prevpos=camera.CFrame
local payload=checkobjects(localPlayer.Character.HumanoidRootPart.Position)
Remote:FireServer(payload)
else
task.wait(RefreshRate)
end
end
end)
end
RegisterLoop()
I did some optimizations with the array handler for the objects and conditions to remove objects from the array as well as increasing the Arrays refresh rate which tripled the performance of the renderer. When running this script uses .05%-.15% CPU usage on the client when using the array handler and .3-1.1% without it
I also want to share this easy to use Parallel luau solution which demonstrates how to invoke a bindable function and create a thread handler that evenly spreads the load to all the actors.
I apologize for certain aspects of the code such as FPSTiming not being defined.
This is the code that I use to calculate Frames per second and the time it takes to render each frame (FPSTiming)
local RunService=game:GetService("RunService")
local TimeFunction = RunService:IsRunning() and time or os.clock
local LastIteration, Start
local FrameUpdateTable = {}
local GlobalFPS=1/30
local function HeartbeatUpdate()
LastIteration = TimeFunction()
for Index = #FrameUpdateTable, 1, -1 do
FrameUpdateTable[Index + 1] = FrameUpdateTable[Index] >= LastIteration - 1 and FrameUpdateTable[Index] or nil
end
FrameUpdateTable[1] = LastIteration
local FrameRate=tostring(math.floor(TimeFunction() - Start >= 1 and #FrameUpdateTable or #FrameUpdateTable / (TimeFunction() - Start)))
--Bars.Parent.CharacterSelect.FPS.Value=FrameRate
--Bars.Radar.FrameRate.Text="FPS:"..Bars.Parent.CharacterSelect.FPS.Value
GlobalFPS=1/FrameRate
--Bars.Parent.CharacterSelect.FPSTiming.Value=GlobalFPS
--FPS
end
Start = TimeFunction()
RunService.Heartbeat:Connect(HeartbeatUpdate)
i am not going to lie this is getting to advanced for me
I am abandoning my idea (sadly) to work on my game for now…
Thank you for taking interest however!
It’s fine! although the two things I recently shared are generally very important. Calculating the time it takes to render each frame as a variable that is used for a variety of tasks. Also, I’ve been using the parallel luau solution for like everything lately to make easy to use and efficient tools for my game. But yeah a custom renderer may not be neccessary I only did it because I could compress all the objects not in view to a reference of their source object because I am doing procedural generation. Which reduced memory usage significantly and allows the worlds to be much larger.
i might start using that threader then!
If you do not mind sharing what is the game you are working on?
I have high hopes for it since you are developing it!
Currently, I am working on Prelude:Prelude - Roblox
Game might have bugs but Its just my first 2 months of scripting so bear with me lol!
This is a link to the testing server for my game Epic RPG with AI +Optimized Performance - Roblox
The main menu currently doesn’t have all the options enabled. so please select the custom character option to enter the game.
this is a link to a previous version of the game which features the story mode. Lumina & Darkness: V 0.9 - Roblox
My old account got hacked so my game doesn’t really get traffic Yet. Gogeta - Roblox
I still consider it incomplete but I plan on a full release soon.
I’ll check out your game too! Some good hints for early scripts is to try to be as organized and efficient as possible and make tools that you want to work with and build up later on.
Also your game is very cool but I’m getting very low FPS sometimes the camera glitches out. But it’s very atmospheric and cool! I couldn’t figure out how to use the sword but I was able to use an electric spell. Definitely keep up the good work and try to create some organized and efficient systems that will allow you to make unlockables or an inventory use the same code for your weapon and use variables to change their behavior
Yea the low fps is the raytracing I put in, I’m trying to figure out how to make it togglable.
Camera Is fine on my side but ill do a double check.
I really dont know what direction to take this game currently lol
Your game reminds of eve online for some reason.
Would love to play it when its done however… systems sound very intricate