-
What do you want to achieve? I want to achieve an “Auto Exposure” system in my game, which means increasing exposure when a player is in a dark region and decreasing when in an illuminated place, so it simulates the eye’s comfort/adjustment to light. Because it is a backrooms horror game, I have several lights hanging on the ceiling, with different brightness and range.
-
What is the issue? The problem is that I can’t find an efficient way to capture this eye adjustment. I tried getting all lights within a range of 200 studs of the player, getting their average brightness between them, get the mouse position and player position, find the distance from light, and do some count; however, ends up the results are kinda disappointing and is not even close to what I want. The script solely makes the exposure fluctuate values between X and Y, but it does not create that feeling of adjustment to light.
-
What solutions have you tried so far? As I said before, I already tried creating a small system that gets the global lights average, but it’s complicated and certainly not the most efficient and proper way to do this, as I am looping through all lights consecutively to try to find the next light, which is bad. I already tried searching for community resources here, but all I could find was this post, using Capture Service to reach this. But I’ve just learned that Capture Service is not recommended for that, although using it would be the best way, as I could get the pixel brightness and information. Using Raycast could work, but I didn’t find a way for it, and it’s possibly not performant either, as I would need to create raycasts from all directions and with a determined length, consequently lagging up the game.
For more information, this is my current script which attempts to simulate this effect, although failing.
Please note that the script is adapted, so I could send it here. The “Auto Exposure” system is enfolded inside a camera module, which encapsulates other types of functions, which are not correlated with this matter.
type influences = {Camera : number, Player : number}
export type light = BasePart & {Light : Light, Connector : (Attachment & {Light : light})?}
local camera = {}
local plrs = game:GetService("Players")
local RpS = game:GetService("ReplicatedStorage")
local lighting = game:GetService("Lighting")
local plr = plrs.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local head = char:WaitForChild("Head")
local hum = char:WaitForChild("Humanoid")
local map = workspace.Map
local lightFolder = map:WaitForChild("Lights")
local mainBrightnessWeight = 2
local secondaryBrightnessWeight = 1
local minLightDistance = 0
local maxLightDistance = 100
local lastAverage = 0
local adaptationAmount = 0
local adaptationSpeed = .01
local maxAdaptation = .15
local lights : {[string] : number} = {}
local lightSensitivities : {[string] : number} = {}
local function getCameraAngleToLight(camCFrame : CFrame, lightPosition : Vector3) : number
local directionToLight = (lightPosition - camCFrame.Position).Unit
local alignment = camCFrame.LookVector:Dot(directionToLight)
return math.clamp(alignment, 0, 1)
end
local function getPlayerInfluence(distance : number) : number
local influence = 1 - math.clamp(distance / maxLightDistance, 0, 1)
return influence
end
local function findLightsBrightnessAverage(Lights : {Light}) : number
local totalBrightness
if #Lights == 1 then
totalBrightness = Lights[1].Brightness
else
local mainBrightness = Lights[1].Brightness * mainBrightnessWeight
local secondaryBrightness = Lights[2].Brightness * secondaryBrightnessWeight
totalBrightness = (mainBrightness + secondaryBrightness) / (mainBrightnessWeight + secondaryBrightnessWeight)
end
return totalBrightness
end
local function findLightBrightnessWithInfluence(Influences : influences, Brightness : number) : number
local cameraInfluence, playerInfluence = Influences.Camera, Influences.Player
local totalBrightness = Brightness + (playerInfluence * math.pow(cameraInfluence/1.5, .7))
return totalBrightness
end
local function findLightEmitters(lightPart : light) : {any?}
local mainSource = lightPart.Light
local secondary : Light?
local connector = lightPart:FindFirstChild("Connector")
if connector then
secondary = connector.Light
end
return {mainSource, secondary}
end
local function returnLightInfluencesIfCloseTo(headPosition : Vector3, lightPosition : Vector3, camCFrame : CFrame) : influences?
local distanceFromPlayer = (headPosition - lightPosition).Magnitude
local influences
if distanceFromPlayer >= minLightDistance and distanceFromPlayer <= maxLightDistance then
influences = {
Camera = getCameraAngleToLight(camCFrame, lightPosition),
Player = getPlayerInfluence(distanceFromPlayer)
}
end
return influences
end
local function updateLightBrightnessTable(lightPart : light) : ()
local identifier = lightPart.Name -- Each light has a different name
local lightEmitters = findLightEmitters(lightPart)
if not lightEmitters then return end
local lightnessAverage = findLightsBrightnessAverage(lightEmitters)
for _, lightEmitter : PointLight in lightEmitters do
lightEmitter.Changed:Connect(function(property)
if property == "Brightness" then
local lightnessAverage = findLightsBrightnessAverage(lightEmitters)
lights[identifier] = lightnessAverage
end
end)
end
lights[identifier] = lightnessAverage
end
local function updateLightSensitivityTable(lightName : string, calculatedLightBrightness : number, camCFrame : CFrame, headPosition : Vector3) : ()
local currentLight : light = lightFolder[lightName]
local lightPosition = currentLight.Position
local influences = returnLightInfluencesIfCloseTo(headPosition, lightPosition, camCFrame)
if influences then
local newLightbrightnessAverage = findLightBrightnessWithInfluence(influences, calculatedLightBrightness)
lightSensitivities[lightName] = newLightbrightnessAverage
else
lightSensitivities[lightName] = nil
end
end
function camera.AdaptToAmbientLight()
local totalSensitivityInEnvironment = 0
local totalLights = 0
local average
local camCFrame = cam.CFrame
local headPosition = head.Position
for lightName, calculatedLightBrightness in lights do
updateLightSensitivityTable(lightName, calculatedLightBrightness, camCFrame, headPosition)
end
for _, lightSensitivity in lightSensitivities do
totalSensitivityInEnvironment += lightSensitivity
totalLights += 1
end
average = totalSensitivityInEnvironment/totalLights
local deltaSensitivity = average - lastAverage
local targetAdaptation = math.clamp(-deltaSensitivity * .5, -maxAdaptation, maxAdaptation)
adaptationAmount += (targetAdaptation - adaptationAmount) * adaptationSpeed
lighting.ExposureCompensation = adaptationAmount
return adaptationAmount
end
for _, lightPart in lightParts do
updateLightBrightnessTable(lightPart)
end
lightFolder.ChildAdded:Connect(updateLightBrightnessTable)
return camera
Please, I need help with this. I’ve been working on this for a while, and it’s frustrating to see that I didn’t reach what I wanted. Any help is highly appreciated. If there’s a way to make it using Capture Service, tell me. If not, teach me how I could achieve this. Thanks in advance and have a great night/day!