Auto Exposure (CaptureService)

Hello everyone! Today I made a script for anyone to use. I made some customizable Auto Exposure that uses EditableImage and the CaptureService.

Roblox Model
(Put in either StarterCharacterScripts or StarterPlayerScripts)

OR

Source Code:

local screenshotAPI = game:GetService("CaptureService")
local asset = game:GetService("AssetService")
local screen = Instance.new("EditableImage")
local lighting = game:GetService("Lighting")
local tween = game:GetService("TweenService")

screen.Size = Vector2.new(1024,1024)

local updateRate = 2

local resolution = 50

local targetEV = 10
local calibrationConstant = 5
local adjustTime = 1

local difference = {} --no touchy!
local ogExposure = lighting.ExposureCompensation

function log2(x: number)
	return (math.log10(x)/math.log10(2))
end

function CalculateNewExposure(brightness: number)
	local luminance = brightness*100
	local ev = log2(luminance)+calibrationConstant
	local compensation = targetEV-ev
	return compensation
end

function GetAverageBrightness()
	local brightness = {}
	local total = 0
	
	for x=1,screen.Size.X,resolution do
		for y=1,screen.Size.Y,resolution do
			pcall(function()
				local pixel = screen:ReadPixels(Vector2.new(x,y),Vector2.one)
				if pixel then
					local color = Color3.new(pixel[1],pixel[2],pixel[3])
					local h,s,v = color:ToHSV()
					total+=v
					table.insert(brightness,v)
				end
			end)
		end
	end
	
	return total/#brightness
end

function UpdateScreen()
	screenshotAPI:CaptureScreenshot(function(capture)
		screen = asset:CreateEditableImageAsync(capture)
		local brightness = GetAverageBrightness()
		tween:Create(lighting,TweenInfo.new(adjustTime),{ExposureCompensation = CalculateNewExposure(brightness)}):Play()
	end)
end

local last = tick()

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

Variables:
targetEV the target exposure (default is 10)
calibrationConstant the calibration constant (default is 5)
adjustTime time taken to adjust to the new exposure, in seconds (default is 1)

Performance:
The most FPS I lost was 2, and that was in studio on future lighting.

Showcase:

(not sure why the video was laggy, I had over 230 fps while recording…)

Enjoy!

16 Likes

The model isn’t public…

keystrokesssssss

1 Like

Fixed it, never realized it! Thank you!

3 Likes

Very cool and well made!! Very impressive.

2 Likes

Looks good, but the exposure does not need to be updated every frame, and also you could split the work load across multiple frames to squeeze back in that extra lost framerate.

2 Likes

I’m very surprised nobody thought of this, I never thought that a performant non-native implementation of this could’ve been possible.

I noticed one feature (Watch the video). I use the factory settings that were set in the script. In such dark places, fluctuations are often observed.

Overall, this is a very useful resource. I hope that in the future it will improve and become completely user-friendly. Although it is already usable now, but I am confused by these fluctuations.!

does this actually work in game? afaik EditableImages is still a Studio Beta and CaptureService is Mobile/Tablet only

EditableMesh ans EditableImage were released to be able to be used outside of studio a while ago. CaptureService works on all devices.

Biggest problem with this method is very likely memory leak.
You’re constantly saving screenshots to the memory.
I don’t know if capture service deletes screenshots after some time but if it doesn’t, the game will crash after some time.

where did you find this information from? I don’t see any new announcements confirming your claims


okay, CaptureService now works on Desktop

I was testing this in the actual experience itself in the video, I would assume that it works

I believe that is caused by always going based on the screen with the exposure compensation. A dark area would go bright, and then it would become dark to smoothen out. A light area is always bright so that it would darken with slight fluctuations. I’m not sure why this happens, I could probably add something that reduces the observed pixel brightness so that it would use the original screen brightness at that point.

1 Like

Hello! Great resource. Thanks. I made a fork of this. I refined, fixed, optimized, and modified it.