Allow developers to customize light attenuation

As a Roblox developer, it’s currently too difficult to simulate realistic light emitters without the ability to modify the emitter’s attenuation distance.

In real life, light begins to lose its intensity the further it travels from its source - this is called attenuation. Currently, it appears the engine has a fixed roll-off distance for lights. Lights could be much more versatile if developers could adjust this behavior.

In this example, both emitters have nearly identical brightness and range - but the attenuation light has a much more gradual brightness roll-off when compared to the current default lights.

The potential applications of this feature would be broad, including realistic flashlights, room lighting, or any light that a developer wishes to make photorealistic.


Currently, an approximation of the above effect is possible using multiple emitters - however, this is not performant at scale. If engineers were to address this missing functionality, developers could easily customize each light to fit their needs.

To preserve backwards compatibility with existing experiences, this could potentially be a property similar to Unreal Engine’s Attenuation Radius - developers could modify a Attenuation property for each emitter [perhaps a range of 0-1]

In 2016, @zeuxcg mentioned variable attenuation during his lighting Hackweek project (the early prototype of Future Lighting). Many of the above points have since been addressed. However, customizable attenuation remains missing.

74 Likes

Honestly I’d be perfectly happy with this just being forcefully enabled one day if it means that large lights won’t look as awful as they currently do.

8 Likes

I think this would be a really good change, lights look very weird on their own. You can get good results with multiple lights but its a lot of work for something that should just be in the engine by default.

2 Likes

This would be really good feature, achieving photorealistic lighting is difficult with awfully low light range and no way to control attenuation. I have experienced this issue with my friends a lot of times and its really bugging me out.
If Godot, Unity, UE have this, why can’t Roblox have it? We’re not in 2015 anymore, this is 2023.

7 Likes

This. And being unable to set the range greater than 60. It would be nice if it was a number sequence as well.

It would be one step in the right direction for Roblox to move towards the current game engine standard. Graphics are important in every game. Control over them gives the developer more ways of expression.

12 Likes

I am all for this, but considering they aren’t increasing the maximum range for lights, I’m doubting they’ll do anything about this.

1 Like

On the relevant feature request for this issue, an engineer mentioned that staff were investigating solutions for implementing a higher range limit for lights. Hopefully we see this limitation changed soon.

In the case of light attenuation, I’m hoping that this ticket is filed internally - perhaps a lighting update sometime in the future will include this and the above issue. :eyes:

2 Likes

In Blender, this feature is called ‘Blend’ and works like a mask feather. I find that the lights on Roblox are currently too limited to make aesthetically pleasing and physically accurate light sources without using tricks like OP mentioned (multiple lights).

I’d love to see this become a feature and allow developers to improve the visual quality of their scenes. Lighting is an important pillar that keeps visual quality up high.

4 Likes

this would be extremely useful for making ambient light as i could make lights extremely soft without having the middle part be annoyingly bright also useful for lamps and literally any other kind of light

1 Like

Bump! This would be insane as of 2023, this is something we REALLY need! It would make achieving incredible lighting so much easier for everyone! :+1:

Today I decided to look into Roblox’s shaders, thanks to Vulkan and NVIDA Nsights Graphics I was able to decompile and modify shaders mid runtime, letting me modify the lighting for point lights.

Now what I have found is that Roblox already does use inverse square root for the light fall off, however this square root is so large, that it exceeds the lights radius. So what they did is that they clamped the light to not exceed the lights radius, then subtracted -1 which gives us that very ugly falloff.

I’m gonna continue and try to fix this, it’s a bit annoying because each material has its own fragment shader.

Here is an image from me trying it out for a test but it’s not great.
image

The left is the unmodified fragment shader of the smooth plastic material, the right is a modified fragment shader for the ceramic tiles material, I disabled specular lighting in this example because I had some *problems with it with it :grin: (funny broken specular lighting)


image

6 Likes

This will probably take a while because I don’t have access to the shader source files and I doubt roblox will ship them inside of the client ever again :sob: + I suck at GLSL so reading the code with hundreds of unnamed variables is not fun

I can see how Roblox’s backwards compatibility mindset has a role here… they can’t realistically change the engine default falloff without breaking a lot of game appearances.

Add a light falloff property to lights, literally just use the UI they use for UIGradients

2 Likes

dunno what you did for modifications but I could replicate this except with speculars working perfectly

Original:

Modified:

I changed a single line and it looks wayyy better whilst retaining the look Roblox has maintained so far.
I DID manage to get proper inverse square (mostly) working but that obviously changes the look drastically.

edit:
this is my current hyperfixation so I toyed around with it some more

I got the realistic falloff working at all light ranges, with the ability to control how “steep” it is as well using an exponent, multiplied by the modified falloff I showed off above to make sure it’s still properly range limited

1 (Full realistic)

0.75 (Less realistic)

0.4 (More flat)

0 (Full flat)

honestly would be really simple for them to implement considering I could do it with unnamed variables, less than an hour of my time and only a single line changed

if you’re wondering what I changed if you wanna do it yourself using Nsight, this is bit of code is specific to the SmoothPlastic/Plastic fragment shader but you’ll find it in the other shaders as well, just with different variable names

Original: (at line 305, which appears to be the variable that defines the attenuation)

float _734 = (clamp(((_41._m0[_679]._m1 * _704) * _704) - 1.0, 0.0, 1.0) * ((_41._m0[_679]._m5 == 0.0) ? 1.0 : (_721 * _721))) * clamp((_704 > 1000.0) ? 0.0 : (dot(_705, _271) + (sqrt(_41._m0[_679]._m6.w * _41._m0[_679]._m7.w) * _704)), 0.0, 1.0);

Modified: (still at line 305)

float falloffexponent = 0; //0 - 1, with 0 being entirely flat and 1 being entirely realistic minus the range limit falloff
float _734 = (clamp(pow(_704, falloffexponent) * clamp(1 - (dot(_701, _701) / _41._m0[_679]._m1), 0.0, 1.0), 0.0, 1.0) * ((_41._m0[_679]._m5 == 0.0) ? 1.0 : (_721 * _721))) * clamp((_704 > 1000.0) ? 0.0 : (dot(_705, _271) + (sqrt(_41._m0[_679]._m6.w * _41._m0[_679]._m7.w) * _704)), 0.0, 1.0);

(yes that’s not actually one line but it essentially is with how the exponent would be an external variable)

edit 2:
the inverse square root function they have right now is actually really vampiric on the light brightness and I’d like to change it to a more conserving one, but I pretty much can’t do anything about that with my current knowledge and the extremely limited info I can glean from the SPIRV-Cross generated shader code

4 Likes

Hey, this is really awesome!

I’m still a very big newb when it comes to writing GLSL and in general more low level graphics stuff. I do conceptually understand a few principles of this stuff but still have a long way ahead of myself for this.

But either way, this is really sick that you got this to work. I wish there was a way nsight graphics could be used to apply these memory patches to some sort of patch directly so I could load them again. But the other issue also is that DX11 is so hard for this exact same thing since only Vulkan gives you even remotely readable code. DX11 is literally just like reading direct assembly at that point :sob:.

The only thing I managed to do once with a C++ assembly patch was to upscale the env map resolution from 128x128 to 2048x2048! I made a thread about it here.

https://devforum.roblox.com/t/high-quality-reflections-in-studio-2k/3246210

But besides this, would you be interested to talk more about this? I’ve been working on a small side project which is a C++ AOB patcher for Roblox studio that enables certain graphical features to render at a MUCH higher resolution/fidelity!

5 Likes

I’d love to talk more about this! I’m currently out away from home for a few days but I can talk once I get back

1 Like