Hello, I was (as it seems many others too) enthralled when I saw Elttob’s recent work with Global Illumination. I decided to take a crack at it. While I haven’t yet gotten it to the point he got it, I have gotten what I think to be a good spot for baking the effect. I have created a test place in which you can see the effect in action:
Note: Your performance may vary from mine. Also, leaving the game results in the client locking up (I’m unsure why)
My Specs:
CPU: Intel i7 9700
GPU: AMD Radeon RX 6600 XT
The best part is, it runs at 60 FPS:
I am using the same method which Elttob and many others have used, which is to create a grid of probes, and using Ray-Tracing, determine an approximate color for that point. While I am unsure of the limitations of other’s system, I know that the system which I have created can do a lot. In the test game, there are 57K+ probes.
How I did it
The major difference between my method and Elttob’s is that instead of using individual parts, I used a single part, and the probes in the grid consist of attachments.
Picture of the place in studio:
Within each attachment, I have a pointlight, and an Actor containing a Ray Tracing script.
The Ray Tracing script is taking advantage of Parallel Lua to more quickly and efficiently determine the color of each node. To prevent script-timeouts, I have the baking process happen over a series of steps with a buffer to store information.
Buffer Module
local RayBuffer = {}
local bufferFuncs = {}
function RayBuffer.new()
local self = {}
self.Color3s = {}
setmetatable(self, {__index = bufferFuncs, __newindex = nil})
return self
end
function bufferFuncs:GetAvgColor3()
if self then
local col = Color3.new()
local b = 0
for _,v in ipairs(self.Color3s) do
local c = v.Color
col = Color3.new(col.R + c.R, col.G + c.G, col.B + c.B)
b += v.Brightness
end
local l = #self.Color3s
return Color3.new(col.R / l, col.G / l, col.B / l), b / l
end
end
function bufferFuncs:AddColor3(C:Color3, brightness:number, frame:number?)
if self then
local ColorVal = {}
ColorVal.Color = C
ColorVal.Brightness = brightness
ColorVal.Frame = frame
table.insert(self.Color3s, ColorVal)
end
end
function bufferFuncs:ClearFrame(frame:number)
if self then
for i,v in ipairs(self.Color3s) do
if v.Frame == frame then
table.remove(self.Color3s, i)
end
end
end
end
return RayBuffer
Ray Tracing Script
local a = script.Parent.Parent
local l = a:WaitForChild("PointLight")
local RS = game:GetService("RunService")
local WS = workspace
local LS = game:GetService("Lighting")
local R = Random.new()
local RB = require(game:GetService("ServerScriptService"):WaitForChild("RayBuffer"))
local rayCount = 8
local numRays = 0
local skyColor = Color3.new(1,1,1)
local sunDir = game:GetService("ServerScriptService"):WaitForChild("SunDirection")
local rayBuffer = RB.new()
local frame = -1
local bufferLength = 16
local updateTime = 0.5
local function canPointSeeSun(point:Vector3)
local result = WS:Raycast(point, sunDir.Value * 500)
if result then
return false
end
return true
end
local function calculateFalloff(lightPower:number, dist)
return lightPower / (1 + (dist))
end
local function updateNodeColor()
frame = (frame + 1) % bufferLength
rayBuffer:ClearFrame(frame) --Clearing the frame before adding anything to it
task.desynchronize()
for i = 0, rayCount, 1 do
local rayResult = WS:Raycast(a.WorldPosition, R:NextUnitVector() * 500)
if rayResult then
if canPointSeeSun(rayResult.Position) then
rayBuffer:AddColor3(rayResult.Instance.Color, calculateFalloff(10, rayResult.Distance), frame)
else
end
end
end
task.synchronize()
l.Color, l.Brightness = rayBuffer:GetAvgColor3()
return
end
for i = 0,bufferLength,1 do
updateNodeColor()
task.wait(updateTime)
end
I would love for people to try out the place and let me know of any performance issues, or inaccuracies. I’ve never created a Ray Tracing script before, and I don’t think I calculated the probe colors exactly correctly, it does look good though.