mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-10-31 15:35:21 +01:00 
			
		
		
		
	- Make volumetric light effect strength server controllable - Separate volumetric and bloom shader pipeline - Require bloom to be enable, scale godrays with bloom
		
			
				
	
	
		
			116 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			GLSL
		
	
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			GLSL
		
	
	
	
	
	
| #define rendered texture0
 | |
| #define depthmap texture1
 | |
| 
 | |
| uniform sampler2D rendered;
 | |
| uniform sampler2D depthmap;
 | |
| 
 | |
| uniform vec3 sunPositionScreen;
 | |
| uniform float sunBrightness;
 | |
| uniform vec3 moonPositionScreen;
 | |
| uniform float moonBrightness;
 | |
| 
 | |
| uniform lowp float volumetricLightStrength;
 | |
| 
 | |
| uniform vec3 dayLight;
 | |
| #ifdef ENABLE_DYNAMIC_SHADOWS
 | |
| uniform vec3 v_LightDirection;
 | |
| #else
 | |
| const vec3 v_LightDirection = vec3(0.0, -1.0, 0.0);
 | |
| #endif
 | |
| 
 | |
| #ifdef GL_ES
 | |
| varying mediump vec2 varTexCoord;
 | |
| #else
 | |
| centroid varying vec2 varTexCoord;
 | |
| #endif
 | |
| 
 | |
| const float far = 1000.;
 | |
| float mapDepth(float depth)
 | |
| {
 | |
| 	return min(1., 1. / (1.00001 - depth) / far);
 | |
| }
 | |
| 
 | |
| float noise(vec3 uvd) {
 | |
| 	return fract(dot(sin(uvd * vec3(13041.19699, 27723.29171, 61029.77801)), vec3(73137.11101, 37312.92319, 10108.89991)));
 | |
| }
 | |
| 
 | |
| float sampleVolumetricLight(vec2 uv, vec3 lightVec, float rawDepth)
 | |
| {
 | |
| 	lightVec = 0.5 * lightVec / lightVec.z + 0.5;
 | |
| 	const float samples = 30.;
 | |
| 	float result = texture2D(depthmap, uv).r < 1. ? 0.0 : 1.0;
 | |
| 	float bias = noise(vec3(uv, rawDepth));
 | |
| 	vec2 samplepos;
 | |
| 	for (float i = 1.; i < samples; i++) {
 | |
| 		samplepos = mix(uv, lightVec.xy, (i + bias) / samples);
 | |
| 		if (min(samplepos.x, samplepos.y) > 0. && max(samplepos.x, samplepos.y) < 1.)
 | |
| 			result += texture2D(depthmap, samplepos).r < 1. ? 0.0 : 1.0;
 | |
| 	}
 | |
| 	return result / samples;
 | |
| }
 | |
| 
 | |
| vec3 getDirectLightScatteringAtGround(vec3 v_LightDirection)
 | |
| {
 | |
| 	// Based on talk at 2002 Game Developers Conference by Naty Hoffman and Arcot J. Preetham
 | |
| 	const float beta_r0 = 1e-5; // Rayleigh scattering beta
 | |
| 
 | |
| 	// These factors are calculated based on expected value of scattering factor of 1e-5
 | |
| 	// for Nitrogen at 532nm (green), 2e25 molecules/m3 in atmosphere
 | |
| 	const vec3 beta_r0_l = vec3(3.3362176e-01, 8.75378289198826e-01, 1.95342379700656) * beta_r0; // wavelength-dependent scattering
 | |
| 
 | |
| 	const float atmosphere_height = 15000.; // height of the atmosphere in meters
 | |
| 	// sun/moon light at the ground level, after going through the atmosphere
 | |
| 	return exp(-beta_r0_l * atmosphere_height / (1e-5 - dot(v_LightDirection, vec3(0., 1., 0.))));
 | |
| }
 | |
| 
 | |
| vec3 applyVolumetricLight(vec3 color, vec2 uv, float rawDepth)
 | |
| {
 | |
| 	vec3 lookDirection = normalize(vec3(uv.x * 2. - 1., uv.y * 2. - 1., rawDepth));
 | |
| 
 | |
| 	const float boost = 4.0;
 | |
| 	float brightness = 0.;
 | |
| 	vec3 sourcePosition = vec3(-1., -1., -1);
 | |
| 
 | |
| 	if (sunPositionScreen.z > 0. && sunBrightness > 0.) {
 | |
| 		brightness = sunBrightness;
 | |
| 		sourcePosition = sunPositionScreen;
 | |
| 	}
 | |
| 	else if (moonPositionScreen.z > 0. && moonBrightness > 0.) {
 | |
| 		brightness = moonBrightness * 0.05;
 | |
| 		sourcePosition = moonPositionScreen;
 | |
| 	}
 | |
| 
 | |
| 	float cameraDirectionFactor = pow(clamp(dot(sourcePosition, vec3(0., 0., 1.)), 0.0, 0.7), 2.5);
 | |
| 	float viewAngleFactor = pow(max(0., dot(sourcePosition, lookDirection)), 8.);
 | |
| 
 | |
| 	float lightFactor = brightness * sampleVolumetricLight(uv, sourcePosition, rawDepth) *
 | |
| 			(0.05 * cameraDirectionFactor + 0.95 * viewAngleFactor);
 | |
| 
 | |
| 	color = mix(color, boost * getDirectLightScatteringAtGround(v_LightDirection) * dayLight, lightFactor);
 | |
| 
 | |
| 	// a factor of 5 tested well
 | |
| 	color *= volumetricLightStrength * 5.0;
 | |
| 
 | |
| 	// if (sunPositionScreen.z < 0.)
 | |
| 	// 	color.rg += 1. - clamp(abs((2. * uv.xy - 1.) - sunPositionScreen.xy / sunPositionScreen.z) * 1000., 0., 1.);
 | |
| 	// if (moonPositionScreen.z < 0.)
 | |
| 	// 	color.rg += 1. - clamp(abs((2. * uv.xy - 1.) - moonPositionScreen.xy / moonPositionScreen.z) * 1000., 0., 1.);
 | |
| 	return color;
 | |
| }
 | |
| 
 | |
| void main(void)
 | |
| {
 | |
| 	vec2 uv = varTexCoord.st;
 | |
| 	vec3 color = texture2D(rendered, uv).rgb;
 | |
| 	// translate to linear colorspace (approximate)
 | |
| 	color = pow(color, vec3(2.2));
 | |
| 
 | |
| 	if (volumetricLightStrength > 0.0) {
 | |
| 		float rawDepth = texture2D(depthmap, uv).r;
 | |
| 
 | |
| 		color = applyVolumetricLight(color, uv, rawDepth);
 | |
| 	}
 | |
| 
 | |
| 	gl_FragColor = vec4(color, 1.0); // force full alpha to avoid holes in the image.
 | |
| }
 |