Screen Space Lens Flare – On Emissive Material

Hey there,
this is Marcel aka WuotanStudios.

I wanted to share another version of my lens-flare shader
i am using in my project RIAD (Reborn in a dungeon).


Godot Version:

4.3-stable, Vulkan-Forward+

It is simple to use:
Step 1: create a new canvas shader and copy-paste the shader code.
Step 2: Create a Color-Rect node which is visible in the game (best make it a child of the player camera)
Step 3: Make sure that the Color-Rect node is in Full-Rect mode.
Step 4: assign a new material for the Color-Rect and use the shader as material.
Step 5: it already should work
Step 6: play with the value until you have the results you are seeking for.

 

 

Shader-Konzept:
It takes the rendered screen, and projects the material-emissive parts of the render into the color-rect.
You can adjust the FlareThreshold and the EmissionThreshold values. 

Another important parameter is blur and Thresholdsmoothness, to make the flare “round” and less sharp. You need to play around with all values a bit depending on your worldenvironment/light setups.

 

 

Note:
This is a prototype shader.
There are still things i am not happy with.
Feel free to modify or improve the shader code further, and upload a better version here 😉

 

For more infos follow me on:

Twitter: https://x.com/WuotanStudios

Bluesky: https://bsky.app/profile/wuotanstudios.bsky.social

Striked: https://striked.gg/app/space/29-riad/news-about-riad

www.wuotanstudios.com

Shader code
//////////////////////////////////////////////////////////////////
//by Marcel Klee - WuotanStudios - 2024
//used in project "RIAD - Reborn in a Dungeon"
//A first person - story driven - action game [WIP]
//
//For more infos follow me on:
//Twitter: https://x.com/WuotanStudios
//Bluesky: https://bsky.app/profile/wuotanstudios.bsky.social
//Striked: https://striked.gg/app/space/29-riad/news-about-riad
//www.wuotanstudios.com
//////////////////////////////////////////////////////////////////


shader_type canvas_item;

render_mode blend_add;

uniform lowp sampler2D Screen_Sample : hint_screen_texture, filter_linear_mipmap_anisotropic;
uniform lowp sampler2D FlareMult;
uniform lowp sampler2D FlareMult2;

uniform float Blur = 2.5;
uniform float FlareThreshold;
uniform float Thresholdsmoothness = 0.2;
uniform int Flares;
uniform float FlareSpacing;
uniform float FlareDistance = 0.5;
uniform float LensThickness = 1.0;

uniform float Intensity;
uniform float Saturation_;
uniform float visibility = 0.95;

uniform float MinFlareIntensity = 0.0;
uniform float MaxFlareIntensity = 0.22;

uniform float AberrationStrength = 0.012;
uniform float EmissionThreshold = 0.8;  // Emission Schwellenwert

// Funktion zur Anwendung des Thresholds
vec3 ApplyThreshold(vec3 color, float threshold){
	return color * smoothstep(threshold - Thresholdsmoothness, threshold + Thresholdsmoothness, length(color));
}

// Funktion zur Anpassung der Sättigung
vec3 AdjustSaturation(vec3 color, float saturation) {
	float gray = dot(color, vec3(0.299, 0.587, 0.114));
	return mix(vec3(gray), color, saturation);
}

// Funktion zur Berechnung der chromatischen Aberration
vec3 ChromaticAberration(vec2 uv, float strength) {
	vec2 offset = uv - vec2(0.5);
	float dist = length(offset);

	vec2 redUV = uv + offset * strength * dist;
	vec2 blueUV = uv - offset * strength * dist;

	vec3 red = texture(Screen_Sample, redUV).rgb;
	vec3 green = texture(Screen_Sample, uv).rgb;
	vec3 blue = texture(Screen_Sample, blueUV).rgb;

	return vec3(red.r, green.g, blue.b);
}

void fragment(){
	vec2 FlippedUV = vec2(LensThickness) - SCREEN_UV;
	vec2 FlareVector = (vec2(FlareDistance) - SCREEN_UV) * FlareSpacing;
	vec3 FinalFlare = vec3(0.0);

	for (int i = 0; i < Flares; ++i){
		vec2 SUV = fract(SCREEN_UV + FlareVector * vec2(float(i)));
		float Dist = distance(SUV, vec2(0.5));
		float Weight = 1.0 - smoothstep(0.0, 0.75, Dist);

		// Hole den Emission-Wert von der Textur (z.B. könnte das Screen_Sample den Emission-Wert enthalten)
		vec3 BlurredScreen = texture(Screen_Sample, SUV, Blur).rgb;

		// Überprüfen, ob der Emission-Wert den EmissionThreshold überschreitet
		float emission_value = length(BlurredScreen);  // Gesamthelligkeit
		if (emission_value > EmissionThreshold) {
			BlurredScreen = ApplyThreshold(BlurredScreen, FlareThreshold);
			FinalFlare += BlurredScreen * Weight;
		}
	}

	FinalFlare *= texture(FlareMult, SCREEN_UV).rgb;
	FinalFlare *= texture(FlareMult2, SCREEN_UV).rgb;
	FinalFlare *= Intensity;
	FinalFlare = clamp(FinalFlare, vec3(MinFlareIntensity), vec3(MaxFlareIntensity));

	// Sättigung anwenden
	FinalFlare = AdjustSaturation(FinalFlare, Saturation_);

	// Chromatische Aberration (Regenbogeneffekt)
	vec3 rainbowEffect = ChromaticAberration(SCREEN_UV, AberrationStrength);

	// Kombiniere den FinalFlare mit dem Regenbogeneffekt
	FinalFlare = mix(FinalFlare, rainbowEffect, 0.5);

	COLOR.rgb = FinalFlare;
	COLOR.a = visibility;
}
Tags
4, camera, flare, godot 4, godot4, lens, lens-flare, lensflare, shader
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.

More from WuotanStudios

Screen Space Lens Flare with rainbow colored effect

Related shaders

Screen Space Lens Flare with rainbow colored effect

Lens Flare Shader

Pencil screen space shader

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments