How could I improve my 3D Raycast Renderer GUI code?

So, i have this old 2012 3D Raycast Renderer, and iv’e been trying my best to improve it, but. I’m not that experienced with raycasting. Also this thing drops your FPS like crazy when its running. So i need some feedback on this code, and how i can improve it, and make it less laggy.

local player = game:GetService("Players").LocalPlayer
local rs = game:GetService("RunService")

repeat wait() until player.Character

local Char = player.Character
local Head = Char:WaitForChild("Head")
local HRP = Char:WaitForChild("HumanoidRootPart")
local Torso = Char:WaitForChild("Torso")
local RightArm = Char:WaitForChild("Right Arm")
local LeftArm = Char:WaitForChild("Left Arm")
local RightLeg = Char:WaitForChild("Right Leg") 
local LeftLeg = Char:WaitForChild("Left Leg")

wait(0)
local Ambient = script.Parent:WaitForChild("Ambient")
--local LightRange = script.Parent:WaitForChild("LightRange")
local pixels = script.Parent:WaitForChild("Pixels") --the pixels to be generated and rendered
local size = pixels.Value / (pixels.Value * pixels.Value) --pixel size
local sky = script.Parent:WaitForChild("Sky")
local ViewDistance = script.Parent:WaitForChild("ViewRange") --view range
local Debug = false --if true the script will handle with the old pixels rather than creating new ones
function tint(col,rat) 
	r = 1-col.r
	g = 1-col.g
	b = 1-col.b
	return Color3.new(r*rat,g*rat,b*rat)
end
function shade(col,rat)
	r = col.r
	g = col.g
	b = col.b
	return Color3.new(r*rat,g*rat,b*rat)
end
function color3add(col,col2)
	return Color3.new(col.r+col2.r,col.g+col2.g,col.b+col2.b)
end
function interpolate(col,col2,rat)
	return Color3.new(col.r*(1-rat) + col2.r*rat,col.g*(1-rat) + col2.g*rat,col.b*(1-rat) + col2.b*rat)
end
function interpolateT(col,col2,rat,val)
	return col*(1-rat) + col2*rat
end
function reflect(vector3,norm)
	norm = norm or Vector3.new(0,1,0)
	return vector3 - ( 2*norm*vector3:Dot(norm))
end



function GeneratePixels()
	for x=0,pixels.Value-1 do
		wait()
		for y=0,pixels.Value-1 do
			local fr = Instance.new("Frame")
			fr.Position = UDim2.new(x*size,0,y*size,0)
			fr.Size = UDim2.new(size,0,size,0)
			fr.BackgroundColor3 = Color3.new(x,y,0)
			fr.BorderSizePixel = 0
			fr.Name = x .."/".. y
			fr.Parent = script.Parent.p
			fr.ZIndex = 3
		end
	end
end
if not Debug then
	GeneratePixels()
end

rs.RenderStepped:Connect(function() --start the camera loop
	--wait(0.1)
	local c = CFrame.new(game.Workspace.CurrentCamera.CoordinateFrame.p,game.Workspace.CurrentCamera.Focus.p)
	for x = pixels.Value-1,0,-1 do
		for y = pixels.Value-1,0,-1 do
			local dir = c*CFrame.new((pixels.Value/2-x)*(20/pixels.Value*.1),(pixels.Value/2-y)*(20/pixels.Value*.1),-1) --with default 20 pixels .1 step
			local TransparentRay = Ray.new(c.p,(dir.p - c.p).unit * ViewDistance.Value) --view ray
			local TransparentPart, point = game.Workspace:FindPartOnRayWithIgnoreList(TransparentRay, {Head, Torso, HRP, RightArm, LeftArm, RightLeg, LeftLeg})
			local ray = Ray.new(c.p,(dir.p - c.p).unit * ViewDistance.Value) --view ray
			local part
			if TransparentPart and TransparentPart.Transparency >= 1 then
				part,point = game.Workspace:FindPartOnRayWithIgnoreList(ray, {Head, Torso, HRP, RightArm, LeftArm, RightLeg, LeftLeg, TransparentPart})	
			else
				part,point = game.Workspace:FindPartOnRayWithIgnoreList(ray, {Head, Torso, HRP, RightArm, LeftArm, RightLeg, LeftLeg})	
			end	
			local r,g,b = 0,0,0 --brickcolor
			local rr,rg,rb = 0,0,0 --reflection color
			local r = 0 --reflection ratio
			local shade = 0
			if part then
				local color = part.Color
				if part == HRP then
					r,g,b = r+color.r,g+color.g,b+color.b
				end
--				local ray2 = Ray.new(point,(HRP.Position-point).unit * LightRange.Value) --light ray to view point
--				local part2
--				if TransparentPart and TransparentPart.Transparency >= 1 then
--					part2 = game.Workspace:FindPartOnRayWithIgnoreList(ray2, {HRP, Head, Torso, HRP, RightArm, LeftArm, RightLeg, LeftLeg, TransparentPart})
--				else
--					part2 = game.Workspace:FindPartOnRayWithIgnoreList(ray2, {HRP, Head, Torso, HRP, RightArm, LeftArm, RightLeg, LeftLeg})
--				end
				local ratio = (HRP.Position - point).magnitude/ViewDistance.Value
				if part then
					shade = 0
				end
				if ratio > 1 then
					ratio = 1
				elseif ratio < 0 then
					ratio = 0
				end
--				if part.Name == "Water" then --add reflection values
--					ref = reflect(dir.lookVector)
--					ray3 = Ray.new(point,ref*length.Value)
--					local TransparentRay = Ray.new(c.p,(dir.p - c.p).unit * length.Value) --view ray
--					local TransparentPart, point = game.Workspace:FindPartOnRayWithIgnoreList(TransparentRay, {Head, Torso, HRP, RightArm, LeftArm, RightLeg, LeftLeg})
--					if TransparentPart and TransparentPart.Transparency == 1 then
--						part3,point3 = game.Workspace:FindPartOnRayWithIgnoreList(ray3,{part, TransparentPart})
--					else
--						part3,point3 = game.Workspace:FindPartOnRayWithIgnoreList(ray3,{part})	
--					end
--					if part3 then
--						color2 = part3.BrickColor.Color
--						rr,rg,rb = rr+color2.r,rg+color2.g,rb+color2.b
--						r = part.Reflection.Value
--					end
--				end

				if shade == 0 then --light wasn't blocked
					if rr~=0 and rg~=0 and rb~=0 then --add the reflection to the final color
						r = interpolateT(color.r*(1-ratio),rr,r,"r")
						g = interpolateT(color.g*(1-ratio),rg,r,"g")
						b = interpolateT(color.b*(1-ratio),rb,r,"b")
					else --no reflection
						r = color.r*(1-ratio)
						g = color.g*(1-ratio)
						b = color.b*(1-ratio)
					end
				end
			else 
				if sky.Value == 1 then -- Default sky
					r = 0 
					g = 153/255
					b = 204/255
				end
				if sky.Value == 2 then -- Black sky
					r = 0 
					g = 0
					b = 0
				end
			end
			local r = r * Ambient.Value.r
			local g = g * Ambient.Value.g
			local b = b * Ambient.Value.b
			
			--script.Parent.p[(pixels.Value-1)-x .."/".. y].BackgroundColor3 = Color3.new(r,g,b)
			
			local PixelTable = {}
			
			if PixelTable[x] == nil then
				PixelTable[x] = {}
			end

			--Insert each pixel in the generation table
			PixelTable[x][y] = script.Parent.p[(pixels.Value-1)-x .."/".. y]
			
			--Accessing said pixel
			PixelTable[x][y].BackgroundColor3 = Color3.new(r,g,b)

		end
	end	
end)


--Originally written by su8
--July 2012

--Patched up and improved by Ethanthegrand14
--May 2020

Instead of doing this multiple times or maybe less times per frame, use RenderStepped:

game:GetService("RunService").RenderStepped:Connect(function()
    --Code
end)

While true do: Will repeat infinitely with a very small wait()
RenderStepped: Will repeat infinitely per frame.

Yes, i suck at explaining

2 Likes

Thanks, someone else also told me to do this. Also have any idea what i can do for performance?

Try to merge the pixels with same color into a single frame with double the width/height(if they share same color over y axis too), so it reduces the amount of new frames being created. Something like Greed-Meshing but with 2-d

My game is 3D. that won’t work. But thanks for suggesting!

Oof. I think i mis-understood that part lol Hope you find a better solution :smiley:

1 Like

I also forgot to say, that you’re doing a bad practice here!:

Instead, use this:

local Character = player.Character or player.CharacterAdded:Wait()

And also implementing a wait(0) wouldn’t be useful here: