Making a lighting effect change based on a player's position and rotation relative to an object

I’m working on an effect that uses color correction due to the (very limiting) limit of point lights, but I’m currently stuck on how I can change the properties based on the player’s properties, to give off the illusion that the lighting effect is coming from the effect itself. After some research, I figured out that I could probably use both magnitude for distance and ToObjectSpace + WorldToScreenPoint to see if the player is looking at the object. One issue with ToObjectSpace, though: I can’t figure out how to find the max (the point where the Z value is at its highest) as it is different with distance. Below is the current script I have:

local part = workspace.Test --This is just a basepart in workspace 
local cam = workspace.CurrentCamera
local lighting = game:GetService("Lighting")
local blur = lighting:WaitForChild("FXBlur")
local CC = lighting:WaitForChild("FXCorrection") --color correction
local maxDist = 500

--The color correction properties when closest
local ccTowardsBrightness = 1
local ccTowardsContrast = 0.5
local ccTowardsTintColor = Color3.fromRGB(94,185,255)
local ccTowardsSaturation = 0

local ccAwayBrightness = 1
local ccAwayContrast = .5
local ccAwaySaturation = 1
local ccAwayTintColor = Color3.fromRGB(123, 220, 255)

--The color correction properties at max distance
local ccMinBrightness = .1
local ccMinContrast = .8
local ccMinSaturation = .1
local ccMinTintColor = Color3.fromRGB(165, 197, 255)

local c = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
local HRP = c:WaitForChild("HumanoidRootPart")

game:GetService("RunService").RenderStepped:Connect(function()
	local dist = (HRP.Position - part.Position).Magnitude
	local relativeSpace = HRP.CFrame:ToObjectSpace(part.CFrame)
	local PartX = relativeSpace.Z
	local _, OnScreen = cam:WorldToScreenPoint(part.Position)
	if dist > maxDist then
		CC.Enabled = false
		blur.Enabled = false
	else
		CC.Enabled = true
		blur.Enabled = true
	end
	print(PartX)
	if OnScreen then
		if (PartX < 0) then
			print("in front")
		else
			print("Not in range")
		end
	else
		print("Not on screen")
	end
end)

The towards and away properties are the maximum properties for that direction; so for example, if you are facing to the left of the part where you are neither facing it nor have your back turned, the properties of the color correction would be in between both of the direction properties. Additionally, the minimum properties (based on the max distance) are the lowest the properties can be, which is at the maximum distance of 500 studs away from the part. Basically, I need to know how to find the maximum and minimum ToObjectSpace and how to adjust the color correction properties based on the player’s position and orientation relative to a part (using magnitude and ToObjectSpace). I am writing this while tired and I know for a fact that I did not explain it that well, so sorry in advance; if there is any more information needed I will try to elaborate on it further.

2 Likes

Hi!
I’m not sure if I get the question right, but maybe you are looking for something like this?

local part = workspace.Test --This is just a basepart in workspace 
local cam = workspace.CurrentCamera
local lighting = game:GetService("Lighting")
local CC = lighting:WaitForChild("FXCorrection")

local ccTowardsBrightness = .8
local ccAwayBrightness = .3
local ccBrightnessDiff = ccTowardsBrightness - ccAwayBrightness

local c = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
local HRP = c:WaitForChild("HumanoidRootPart")

game:GetService("RunService").RenderStepped:Connect(function()
	
	local pVec = (HRP.CFrame.Position - part.CFrame.Position).Unit
	local hVec = HRP.CFrame.LookVector
	
	local angle = math.acos(pVec:Dot(hVec))/math.pi
	
	print(angle)
	CC.Brightness = ccBrightnessDiff * angle + ccAwayBrightness

end)

It calculates the angle of the relative position of the part, compared to the direction that the character is looking at, scaled between 0 (looking away) and 1 (looking at the part). Then it simply interpolates the color correction settings between the given values, based on the angle. If you don’t care about height, you may wanna remove the Y components of the vectors hVec and pVec.

Hope this helps, good luck!

1 Like

Thank you! It was honestly starting to give me a headache. Any idea how I could also incorporate color?

There are different ways to interpolate between colors. You can just interpolate between the individual RGB values. Or you can convert to HSV and use those values instead to interpolate between. The linear interpolation can be done the same way, (a-b)*angle + b, where for example ‘a’ is the Hue value of the towardColor and ‘b’ is the Hue value of the awayColor.

To do a linear RGB interpolation, you can also just use color3:Lerp(). But it may look nicer to do non-linear interpolation, for example taking the power of 2 for each value, interpolating, and then taking the square root. I’m not an expert on the subject, but I think experts use a non-linear HSV interpolation, with different hue, saturation and value interpolation formulas.

You can start off by trying something like:

CC.TintColor = ccAwayTintColor:Lerp(ccTowardsTintColor, angle)
1 Like

I was stuck on this topic for a while, thank you.

1 Like

I should probably have added that the ‘hue’ property of a HSV color is circular, which means that color 0.001 is very close (similar) to color 1.

If you were to interpolate normally between 0.001 and 1, it would go ‘the long way around’: it would traverse all the colors to end up with a color similar to what you started with.

To prevent this, if the difference between the starting hue and the final hue is more than 0.5, then you would probably want to interpolate in the other direction. The modulo operator would probably come in handy here: first interpolate using the highest of the two hue values - 1, then when creating the resulting color3 value do %1. Always make sure the H, S, and V values that you put into fromHSV() are in the range 0 to 1 or buggy things may happen.

Also remember that the HSV values are a ‘cone-shaped’ color space. This means that anything with ‘Value’ 0 is a black color. So Color3.fromHSV(X,Y,0) will always give the same color black for any X and Y.

In summary, HSV interpolation is a bit trickier but usually looks more pretty. There are probably also libraries out there to help you do this. But a simple implementation may go a long way already. Good luck, let me know if you need more explanation on any of this.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.