Custom 2D Light

This is a light weight solution for a custom light 2d class which is a much more efficient approach if you goal is to maximize performance or get rid of unnecesary things like extra complex calculations or shadows.

The shader can be applied to canvas items

Parameters explained:

light color: used to set the color of the light (rgb, (255, 255, 255) is default for white)

 

brightness: set the brightness of the light

 

attenuation strength: used to make darker spots less iluminated the lighter spots, a number between 0.0 and 1.0 defines its strngth (needed to created a similar or even better effect then default light 2d classes)

 

intensity: set the intensity of the light

 

max brightness : this parameter controls how bright overlapping lights or the light itself can get

Shader code
shader_type canvas_item;

uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, repeat_disable, filter_nearest;

render_mode blend_add, unshaded;

uniform sampler2D light_texture;
uniform vec3 light_color = vec3(255, 255, 255);  // Default to white
uniform float brightness : hint_range(0.0, 1.0) = 0.5;
uniform float attenuation_strength : hint_range(0.0, 1.0) = 0.5;
uniform float intensity : hint_range(0.0, 10.0) = 1.0;
uniform float max_brightness : hint_range(0.0, 10.0) = 1.0;  // Maximum allowable brightness

void fragment() {
    // Sample the light texture at the current UV coordinates
    vec4 light_tex_color = texture(light_texture, UV);
    // Sample the underlying texture color
    vec4 under_color = texture(SCREEN_TEXTURE, SCREEN_UV);
    // Normalize the light color from 0-255 to 0.0-1.0
    vec3 normalized_light_color = light_color / 255.0;
    // Calculate the brightness of the underlying pixel (using the luminance formula)
    float under_brightness = dot(under_color.rgb, vec3(0.299, 0.587, 0.114));
    // Adjust the final color by modulating the light texture with brightness, 
    // light color, and the brightness of the underlying pixel
    float attenuation = mix(1.0, under_brightness, attenuation_strength);
    vec4 final_color = light_tex_color * attenuation * vec4(normalized_light_color, 1.0) * brightness * intensity;
    // Clamp the resulting color to ensure it does not exceed the max_brightness
    float max_rgb = max_brightness;
    vec3 clamped_color = min(final_color.rgb, vec3(max_rgb));
    
    // Use additive blending with the background
    COLOR = vec4(clamped_color, light_tex_color.a);
}
Tags
light, lighting
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

UCBC’s Stylized Light with Light Masking

Pixelate into view (Custom Resolution)

Infinite custom texture scrolling with modifiers

Subscribe
Notify of
guest

7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
warsawdag
14 days ago
The luminance formula made the trick for me. Spent hours trying to achieve a similar result to pointlights2d due to the 16 limit restriction, but never get close to it, the luminance tweak improved the cloud-bubble-alike light I already had by 100%. ThanksSSS!!!!
reid
14 days ago

cool

CrayonApe
CrayonApe
7 days ago

Is it possible to make this shader produce better results in very dark environments?

Jojo
Jojo
2 days ago
Reply to  CrayonApe

i already achieved better results with it instead of default light2d instances when i was working with lighting in a dark cave environment. With some tweaking you can achieve a realy good ilumination effect in dark evironments. So yes it definetly is. You can for example lower the attenuation_strength parameter which determines the ilumination strength of darker spots (simple explanation tho) and play around with the brightness and intensity parameters

Last edited 2 days ago by Brakatuta
CrayonApe
CrayonApe
1 day ago
Reply to  Jojo

Thank you for your reply! I’ve tried this shader several times and found that it works well if I apply it to small objects like colored light bulbs. But if I try to use it to light up the environment, it doesn’t work so well. The player inside the light seems to be covered by a mask and not transparent enough like Light2D. For my situation, I currently use Light2D with a large texture for the parts that need to be illuminated, and then use this shader to add small lights to the scene.
If I’m doing something wrong and this shader can be used to light up the whole environment, please let me know. Thank you very much, I love this shader.

Last edited 1 day ago by CrayonApe
CrayonApe
CrayonApe
10 hours ago
Reply to  Brakatuta

Thank you very much! I replaced most of the small lights in the game scene with this shader, and now the light rendering part takes only 0.3 milliseconds per frame, which is a huge performance improvement. I’m still new to Godot, so I never knew BackBufferCopy could be used anywhere other than the tutorial shader overlap, I’ll give it a try.