Custom renderer | by frodev

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


Current Version: 1.0

FrodevsCustomRendering.rbxm (8.0 KB)

All Versions

1.0
FrodevsCustomRendering.rbxm (8.0 KB)

If you have any feedback I would appreciated!
Also know I made this in an hour so their are probably some bugs

Enjoy!
~ Frodev

7 Likes

How about some render distance options! :slight_smile:

Actually thats a good idea. Dunno how I’d pull it off but Ill try (eventually lol)

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

1 Like

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

Dunno if itll exactly lower rendering time (considering it doubles the part count) but beats me I wouldnt know.

Anyhow good luck and have fun!

Yea that’s what I’m using part cache for to quickly delete the part to simulate render time

1 Like

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

great to see people expand on my video lol. i do wonder if its possible to make an entire game that does calculations from just viewports

2 Likes

Well do I have something for you…,
( it’s not finished)
(It’s not even working)
But I’m using this to do almost that!

1 Like

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)

Small problem…
Too much calculations…
Ima abandoning this but I might come back to it later

1 Like

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

1 Like

Wow! This is very VERY nice!, thank you truly.

1 Like

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 :sweat_smile:
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. :slight_smile:
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