Hi, I need to control the shadow casting of the movable lights based on player distance from them. My idea was to make a component and add it to the lights I want to control. But as I am not well experienced in stuff like that (which is advanced for me) I need help with this.
I’ve had an idea to make a closed tick and cast system that will check only lights that contain the light component within the system so the tick would not be that expensive. If there is a more efficient way than this please let me know. Now I will share the screenshots of what I did
-
I’ve made the variables that I would use and made 2 functions - one to find the light component and the second one to measure distance from the player
-
Find Light Component function uses casting and looks like this:
-
Get Distance To Player function looks like this (I didn’t use Target Actor because I am not sure how):
-
And the event graph in the end that is using those functions is this:
I know that something here is wrong because it doesn’t work
I am not sure if this is even a good and optimized approach, so any input would be appreciated. Thanks
Edit: Needs to be multiplayer friendly and player based
Hi there,
Yes you can make this much more optimized.
So just to clarify and re-state the problem.
- You want to control lights and stop casting shadows if the player is far far away.
So this is a bit like a LODLightsComponent.
- You can actually control that distance by shadow max distance. This is, in some terms, integrated already. Dynamic Shadow Distance / CSM distance you can control these knobs already.
- If you want this component, that is also ok. However, there are some architectural changes you need to make to start having some performance upgrades and scalability.
Upgrades to LODLightsComponent
-
Searching lights in your owner actor every tick is not necessary, unless you have lights added/removed all the time. Even for that, you can use events. To start with, on component BeginPlay just find the LightComponent ONCE and store it as CachedLightComponent.
-
Put a Gate node in your Tick, start it closed and add a custom event “OpenGate”. Once on your BeginPlay the CachedLightComponent is found (is valid), additionally call your OpenGate.
Even one step further, if this is not a core gameplay mechanic, just use a timer with 0.5–1 second so it’s much less loaded.
-
For distance checking DistanceSquared is much faster use that.
-
Now actually the main part: Rather than this component making its own ticks etc., you can have a manager LODLightsManager. When your component on its owner at BeginPlay finds a CachedLightComponent, you simply register this at your manager.
Create a function in the manager which checks an array of lights. If it is not already registered inside this array, add it to the pool/array (since streaming can overwrite counts). Let’s call this CurrentLightsArray.
-
Manager Logic: After the manager notices the array is not empty (there are some registrars), each client’s timer makes its batch process to check distance from the light to itself. Foreach in the array you run your distance check logic.
So your logic becomes from Light Check → Player (client) to Player (client) → Light Check. Since this is on client and batch processed, it would be much faster.
-
Manager Logic - State LightGrading: Make an enum as you wish, like off, very low, low, medium, high for the states of lights. Let’s call this LightLODState.
In your batch process, after checking distances to each light, convert distances to LightLODState. If between 0–100, LightLODState is High.
Implement this enum also in the component, and if your batch state of that light is not equal to the component state, call a function to SetLightState.
SetLightState should change the enum and also SetCastShadows or other settings if you like so change is made when necessary not every time. This enums and multiple states would be better since bool is 2 state / binary, since maybe resolutions of shadows also can change rather than on off or some other settings that you think should be changed. You will have more granularity and control.
If you are making this for really big scale 500+ Lights, there are more ways even workarounds to lower costs like threadding, processing, memory allocation etc. However besides that in that kind of scenario this component becomes crucial then states of lights can effect rate of check. More relevant lights distance checks become faster, further away ones becomes slower. If player teleports to somewhere in the world you can ReInit the manager (throttle batch process) to overcome latency at that moments. Ofcourse the more we talk about the performance we come closer to C++, these last memory allocation etc will require it anyway however just running 1-6 in C++ would be faster too thus more efficient/neat.
Let me know if it helps and you have questions around it.