Performant volumetric lighting system

Hey. I just wanted to say that this looks like a really phenomenal resource. Can I ask what your computer specs are and what type of FPS hit you take when using these lighting effects?

Also, have you gathered any data on other machines to test performance across different specs? Thanks a ton in advance. Well done. This thread is one of the best resources I’ve found on this topic.. I’ll be messing around with this soon and update you on any improvements I may find in my scripting..

how does the script work because when I looked at it there doesnt seem to actually be anything related to light

Hello, well I’ve provided videos before of the fps I’m getting. But if your wondering what specs I’m using
GPU-Gforce RTX 3080 founders edition
CPU- ryzen 7 7800X3D
32Gb of ram (can’t exactly remember more, but I think those first 2 are the most important ones)

1 Like

the lighting is based on the parts it spawns in

ok but why does it use inverted planes as well as regular planes

inverted planes add the facing camera effect of the volumetrics, you could have light shinning on the camera before

1 Like

so what are the regular planes for then

throwing my coin in the jar


local Settings = workspace:FindFirstChild("CameraPlaneSettings")
if not Settings then
	Settings = Instance.new("Configuration")
	Settings.Name = "CameraPlaneSettings"
	Settings.Parent = workspace
end

if Settings:GetAttribute("PlaneCount") == nil then
	Settings:SetAttribute("PlaneCount", 25)
end
if Settings:GetAttribute("PlaneSpacing") == nil then
	Settings:SetAttribute("PlaneSpacing", 0.5)
end

local CamPart = script:WaitForChild("CameraPart")
local PlaneTemplate = CamPart:WaitForChild("Plane")
local InvertedTemplate = CamPart:WaitForChild("InvertedPlane")

local Container = workspace:FindFirstChild("CameraPlanesContainer")
if not Container then
	Container = Instance.new("Folder")
	Container.Name = "CameraPlanesContainer"
	Container.Parent = workspace
else
	Container:ClearAllChildren()
end

local YawRight = CFrame.Angles(0, math.rad(90), 0)
local InvertedYaw = CFrame.Angles(0, math.rad(180), 0)

local Pool = {}
local CFramesList = {}
local IsInvertedCache = {}
local OrigXCache = {}
local PoolSize = 0

local PlaneSpacing = Settings:GetAttribute("PlaneSpacing")
local Camera = workspace.CurrentCamera
workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
	Camera = workspace.CurrentCamera
end)

local function UpdatePlaneSizes()
	if not Camera or PoolSize == 0 then return end
	local fovRad = math.rad(Camera.FieldOfView)
	local tanHalfFov = math.tan(fovRad * 0.5)
	local vs = Camera.ViewportSize
	local aspect = vs.X / math.max(1, vs.Y)

	for i = 1, PoolSize do
		local p = Pool[i]
		if p then
			local dist = i * PlaneSpacing
			local height = 2 * dist * tanHalfFov
			local width = height * aspect
			p.Size = Vector3.new(OrigXCache[i], height, width)
		end
	end
end

local function SetPlaneCount(count)
	count = math.max(0, math.floor(count or 0))

	for i = count + 1, PoolSize do
		if Pool[i] then
			Pool[i]:Destroy()
			Pool[i] = nil
			CFramesList[i] = nil
			IsInvertedCache[i] = nil
			OrigXCache[i] = nil
		end
	end

	for i = PoolSize + 1, count do
		local isInverted = (i % 2 == 0)
		local template = isInverted and InvertedTemplate or PlaneTemplate
		local p = template:Clone()
		p.Anchored = true
		p.CanCollide = false
		p.CanQuery = false 
		p.CanTouch = false
		p.CastShadow = false
		p.Parent = Container

		Pool[i] = p
		IsInvertedCache[i] = isInverted
		OrigXCache[i] = p.Size.X
	end

	PoolSize = count
	UpdatePlaneSizes()
end

SetPlaneCount(Settings:GetAttribute("PlaneCount"))

Settings:GetAttributeChangedSignal("PlaneCount"):Connect(function()
	local v = Settings:GetAttribute("PlaneCount")
	if type(v) == "number" then SetPlaneCount(v) end
end)

Settings:GetAttributeChangedSignal("PlaneSpacing"):Connect(function()
	local v = Settings:GetAttribute("PlaneSpacing")
	if type(v) == "number" then
		PlaneSpacing = v
		UpdatePlaneSizes()
	end
end)

local LastFOV, LastVSX, LastVSY, PrevCamCF

local function RenderPlanes()
	if not Camera or PoolSize == 0 then return end
	local camCF = Camera.CFrame
	local fov = Camera.FieldOfView
	local vs = Camera.ViewportSize

	if fov ~= LastFOV or vs.X ~= LastVSX or vs.Y ~= LastVSY then
		LastFOV, LastVSX, LastVSY = fov, vs.X, vs.Y
		UpdatePlaneSizes()
	end

	if PrevCamCF and camCF == PrevCamCF then return end
	PrevCamCF = camCF

	local camYawCF = camCF * YawRight
	local spacing = PlaneSpacing

	for i = 1, PoolSize do
		local dist = i * spacing
		local offsetCF = camYawCF * CFrame.new(dist, 0, 0)
		CFramesList[i] = IsInvertedCache[i] and (offsetCF * InvertedYaw) or offsetCF
	end

	workspace:BulkMoveTo(Pool, CFramesList, Enum.BulkMoveMode.FireCFrameChanged)
end

RenderPlanes()
RunService.RenderStepped:Connect(RenderPlanes)```

proper settings (load in workspace)
removed task.spawn
bulk move to
stopped updating size every frame unless screen or fov is changed
cache attributes
can touch query also disabled due to slight overhead.
1 Like

I would explain- but just experiment with the system and find out for yourself, it would be a better explanation

I recreated the entire system before under the observation that you alternate between inverted and regular and it worked but I still dont know the purpose of the regular planes