From e0d4a9d5756e66102cfc05dc9a187c5ada8cf0be Mon Sep 17 00:00:00 2001 From: Lars Date: Mon, 23 Oct 2023 17:05:31 -0700 Subject: [PATCH] Make volumetric light effect strength server controllable - Make volumetric light effect strength server controllable - Separate volumetric and bloom shader pipeline - Require bloom to be enable, scale godrays with bloom --- builtin/settingtypes.txt | 4 + .../extract_bloom/opengl_fragment.glsl | 93 -------------- .../shaders/second_stage/opengl_fragment.glsl | 1 - .../volumetric_light/opengl_fragment.glsl | 115 ++++++++++++++++++ .../volumetric_light/opengl_vertex.glsl | 12 ++ doc/lua_api.md | 3 + src/client/game.cpp | 80 ++++++------ src/client/render/secondstage.cpp | 36 ++++-- src/client/shader.cpp | 4 + src/client/sky.h | 3 + src/defaultsettings.cpp | 1 + src/lighting.h | 1 + src/network/clientpackethandler.cpp | 2 + src/script/lua_api/l_object.cpp | 13 +- src/server.cpp | 2 + src/skyparams.h | 1 + 16 files changed, 227 insertions(+), 144 deletions(-) create mode 100644 client/shaders/volumetric_light/opengl_fragment.glsl create mode 100644 client/shaders/volumetric_light/opengl_vertex.glsl diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 205d427fb..0af96cc33 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -627,6 +627,10 @@ bloom_strength_factor (Bloom Strength Factor) float 1.0 0.1 10.0 # Requires: shaders, enable_bloom bloom_radius (Bloom Radius) float 1 0.1 8 +# Set to true to enable volumetric lighting effect (a.k.a. "Godrays"). +# +# Requires: shaders, enable_bloom +enable_volumetric_lighting (Volumetric lighting) bool false [*Audio] diff --git a/client/shaders/extract_bloom/opengl_fragment.glsl b/client/shaders/extract_bloom/opengl_fragment.glsl index b79911b9a..36671b06c 100644 --- a/client/shaders/extract_bloom/opengl_fragment.glsl +++ b/client/shaders/extract_bloom/opengl_fragment.glsl @@ -1,28 +1,13 @@ #define rendered texture0 -#define depthmap texture2 struct ExposureParams { float compensationFactor; }; uniform sampler2D rendered; -uniform sampler2D depthmap; - uniform mediump float bloomStrength; uniform ExposureParams exposureParams; -uniform vec3 sunPositionScreen; -uniform float sunBrightness; -uniform vec3 moonPositionScreen; -uniform float moonBrightness; - -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 @@ -33,80 +18,6 @@ centroid varying vec2 varTexCoord; varying float exposure; // linear exposure factor, see vertex shader #endif -const float far = 1000.; -const float near = 1.; -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)); - vec3 lightSourceTint = vec3(1.0, 0.98, 0.4); - - 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.) { - lightSourceTint = vec3(0.4, 0.9, 1.); - 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); - - // 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; @@ -120,9 +31,5 @@ void main(void) color *= exposure; #endif - 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. } diff --git a/client/shaders/second_stage/opengl_fragment.glsl b/client/shaders/second_stage/opengl_fragment.glsl index 973cfc424..45e99928e 100644 --- a/client/shaders/second_stage/opengl_fragment.glsl +++ b/client/shaders/second_stage/opengl_fragment.glsl @@ -126,7 +126,6 @@ void main(void) #endif } - #ifdef ENABLE_BLOOM color = applyBloom(color, uv); #endif diff --git a/client/shaders/volumetric_light/opengl_fragment.glsl b/client/shaders/volumetric_light/opengl_fragment.glsl new file mode 100644 index 000000000..9ed5fa9ba --- /dev/null +++ b/client/shaders/volumetric_light/opengl_fragment.glsl @@ -0,0 +1,115 @@ +#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. +} diff --git a/client/shaders/volumetric_light/opengl_vertex.glsl b/client/shaders/volumetric_light/opengl_vertex.glsl new file mode 100644 index 000000000..d264ae071 --- /dev/null +++ b/client/shaders/volumetric_light/opengl_vertex.glsl @@ -0,0 +1,12 @@ +#ifdef GL_ES +varying mediump vec2 varTexCoord; +#else +centroid varying vec2 varTexCoord; +#endif + + +void main(void) +{ + varTexCoord.st = inTexCoord0.st; + gl_Position = inVertexPosition; +} diff --git a/doc/lua_api.md b/doc/lua_api.md index 67d9cf604..ab4ff52cc 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8036,6 +8036,9 @@ child will follow movement and rotation of that bone. * `speed_dark_bright` set the speed of adapting to bright light (default: `1000.0`) * `speed_bright_dark` set the speed of adapting to dark scene (default: `1000.0`) * `center_weight_power` set the power factor for center-weighted luminance measurement (default: `1.0`) + * `volumetric_light`: is a table that controls volumetric light (a.k.a. "godrays") + * `strength`: sets the strength of the volumetric light effect from 0 (off, default) to 1 (strongest) + * This value has no effect on clients who have the "Volumetric Lighting" or "Bloom" shaders disabled. * `get_lighting()`: returns the current state of lighting for the player. * Result is a table with the same fields as `light_definition` in `set_lighting`. diff --git a/src/client/game.cpp b/src/client/game.cpp index ab1927eab..af225924a 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -404,10 +404,12 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter CachedPixelShaderSetting m_bloom_radius_pixel; float m_bloom_radius; CachedPixelShaderSetting m_saturation_pixel; + bool m_volumetric_light_enabled; CachedPixelShaderSetting m_sun_position_pixel; CachedPixelShaderSetting m_sun_brightness_pixel; CachedPixelShaderSetting m_moon_position_pixel; CachedPixelShaderSetting m_moon_brightness_pixel; + CachedPixelShaderSetting m_volumetric_light_strength_pixel; public: void onSettingsChange(const std::string &name) @@ -469,7 +471,8 @@ public: m_sun_position_pixel("sunPositionScreen"), m_sun_brightness_pixel("sunBrightness"), m_moon_position_pixel("moonPositionScreen"), - m_moon_brightness_pixel("moonBrightness") + m_moon_brightness_pixel("moonBrightness"), + m_volumetric_light_strength_pixel("volumetricLightStrength") { g_settings->registerChangedCallback("enable_fog", settingsCallback, this); g_settings->registerChangedCallback("exposure_compensation", settingsCallback, this); @@ -483,6 +486,7 @@ public: m_bloom_intensity = g_settings->getFloat("bloom_intensity", 0.01f, 1.0f); m_bloom_strength = RenderingEngine::BASE_BLOOM_STRENGTH * g_settings->getFloat("bloom_strength_factor", 0.1f, 10.0f); m_bloom_radius = g_settings->getFloat("bloom_radius", 0.1f, 8.0f); + m_volumetric_light_enabled = g_settings->getBool("enable_volumetric_lighting") && m_bloom_enabled; } ~GameGlobalShaderConstantSetter() @@ -588,49 +592,52 @@ public: float saturation = m_client->getEnv().getLocalPlayer()->getLighting().saturation; m_saturation_pixel.set(&saturation, services); - // Map directional light to screen space - auto camera_node = m_client->getCamera()->getCameraNode(); - core::matrix4 transform = camera_node->getProjectionMatrix(); - transform *= camera_node->getViewMatrix(); + if (m_volumetric_light_enabled) { + // Map directional light to screen space + auto camera_node = m_client->getCamera()->getCameraNode(); + core::matrix4 transform = camera_node->getProjectionMatrix(); + transform *= camera_node->getViewMatrix(); - if (m_sky->getSunVisible()) { - v3f sun_position = camera_node->getAbsolutePosition() + - 10000. * m_sky->getSunDirection(); - transform.transformVect(sun_position); - sun_position.normalize(); + if (m_sky->getSunVisible()) { + v3f sun_position = camera_node->getAbsolutePosition() + + 10000. * m_sky->getSunDirection(); + transform.transformVect(sun_position); + sun_position.normalize(); - float sun_position_array[3] = { sun_position.X, sun_position.Y, sun_position.Z}; - m_sun_position_pixel.set(sun_position_array, services); + float sun_position_array[3] = { sun_position.X, sun_position.Y, sun_position.Z}; + m_sun_position_pixel.set(sun_position_array, services); - float sun_brightness = rangelim(107.143f * m_sky->getSunDirection().dotProduct(v3f(0.f, 1.f, 0.f)), 0.f, 1.f); - m_sun_brightness_pixel.set(&sun_brightness, services); - } - else { - float sun_position_array[3] = { 0.f, 0.f, -1.f }; - m_sun_position_pixel.set(sun_position_array, services); + float sun_brightness = rangelim(107.143f * m_sky->getSunDirection().dotProduct(v3f(0.f, 1.f, 0.f)), 0.f, 1.f); + m_sun_brightness_pixel.set(&sun_brightness, services); + } else { + float sun_position_array[3] = { 0.f, 0.f, -1.f }; + m_sun_position_pixel.set(sun_position_array, services); - float sun_brightness = 0.f; - m_sun_brightness_pixel.set(&sun_brightness, services); - } + float sun_brightness = 0.f; + m_sun_brightness_pixel.set(&sun_brightness, services); + } - if (m_sky->getMoonVisible()) { - v3f moon_position = camera_node->getAbsolutePosition() + - 10000. * m_sky->getMoonDirection(); - transform.transformVect(moon_position); - moon_position.normalize(); + if (m_sky->getMoonVisible()) { + v3f moon_position = camera_node->getAbsolutePosition() + + 10000. * m_sky->getMoonDirection(); + transform.transformVect(moon_position); + moon_position.normalize(); - float moon_position_array[3] = { moon_position.X, moon_position.Y, moon_position.Z}; - m_moon_position_pixel.set(moon_position_array, services); + float moon_position_array[3] = { moon_position.X, moon_position.Y, moon_position.Z}; + m_moon_position_pixel.set(moon_position_array, services); - float moon_brightness = rangelim(107.143f * m_sky->getMoonDirection().dotProduct(v3f(0.f, 1.f, 0.f)), 0.f, 1.f); - m_moon_brightness_pixel.set(&moon_brightness, services); - } - else { - float moon_position_array[3] = { 0.f, 0.f, -1.f }; - m_moon_position_pixel.set(moon_position_array, services); + float moon_brightness = rangelim(107.143f * m_sky->getMoonDirection().dotProduct(v3f(0.f, 1.f, 0.f)), 0.f, 1.f); + m_moon_brightness_pixel.set(&moon_brightness, services); + } + else { + float moon_position_array[3] = { 0.f, 0.f, -1.f }; + m_moon_position_pixel.set(moon_position_array, services); - float moon_brightness = 0.f; - m_moon_brightness_pixel.set(&moon_brightness, services); + float moon_brightness = 0.f; + m_moon_brightness_pixel.set(&moon_brightness, services); + } + float volumetric_light_strength = m_client->getEnv().getLocalPlayer()->getLighting().volumetric_light_strength; + m_volumetric_light_strength_pixel.set(&volumetric_light_strength, services); } } @@ -3089,7 +3096,6 @@ void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam) else sky->setFogStart(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f)); - delete event->set_sky; } diff --git a/src/client/render/secondstage.cpp b/src/client/render/secondstage.cpp index 6a71f395e..da6536b97 100644 --- a/src/client/render/secondstage.cpp +++ b/src/client/render/secondstage.cpp @@ -120,8 +120,9 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep static const u8 TEXTURE_EXPOSURE_1 = 3; static const u8 TEXTURE_EXPOSURE_2 = 4; static const u8 TEXTURE_FXAA = 5; - static const u8 TEXTURE_BLOOM_DOWN = 10; - static const u8 TEXTURE_BLOOM_UP = 20; + static const u8 TEXTURE_VOLUME = 6; + static const u8 TEXTURE_SCALE_DOWN = 10; + static const u8 TEXTURE_SCALE_UP = 20; // Super-sampling is simply rendering into a larger texture. // Downscaling is done by the final step when rendering to the screen. @@ -130,6 +131,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep const bool enable_auto_exposure = g_settings->getBool("enable_auto_exposure"); const bool enable_ssaa = antialiasing == "ssaa"; const bool enable_fxaa = antialiasing == "fxaa"; + const bool enable_volumetric_light = g_settings->getBool("enable_volumetric_lighting") && enable_bloom; if (enable_ssaa) { u16 ssaa_scale = MYMAX(2, g_settings->getU16("fsaa")); @@ -160,9 +162,9 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep v2f downscale = scale * 0.5; for (u8 i = 0; i < MIPMAP_LEVELS; i++) { - buffer->setTexture(TEXTURE_BLOOM_DOWN + i, downscale, std::string("downsample") + std::to_string(i), color_format); + buffer->setTexture(TEXTURE_SCALE_DOWN + i, downscale, std::string("downsample") + std::to_string(i), color_format); if (enable_bloom) - buffer->setTexture(TEXTURE_BLOOM_UP + i, downscale, std::string("upsample") + std::to_string(i), color_format); + buffer->setTexture(TEXTURE_SCALE_UP + i, downscale, std::string("upsample") + std::to_string(i), color_format); downscale *= 0.5; } @@ -171,20 +173,30 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep // get bright spots u32 shader_id = client->getShaderSource()->getShader("extract_bloom", TILE_MATERIAL_PLAIN, NDT_MESH); - RenderStep *extract_bloom = pipeline->addStep(shader_id, std::vector { TEXTURE_COLOR, TEXTURE_EXPOSURE_1, TEXTURE_DEPTH }); + RenderStep *extract_bloom = pipeline->addStep(shader_id, std::vector { source, TEXTURE_EXPOSURE_1 }); extract_bloom->setRenderSource(buffer); extract_bloom->setRenderTarget(pipeline->createOwned(buffer, TEXTURE_BLOOM)); source = TEXTURE_BLOOM; } + if (enable_volumetric_light) { + buffer->setTexture(TEXTURE_VOLUME, scale, "volume", color_format); + + shader_id = client->getShaderSource()->getShader("volumetric_light", TILE_MATERIAL_PLAIN, NDT_MESH); + auto volume = pipeline->addStep(shader_id, std::vector { source, TEXTURE_DEPTH }); + volume->setRenderSource(buffer); + volume->setRenderTarget(pipeline->createOwned(buffer, TEXTURE_VOLUME)); + source = TEXTURE_VOLUME; + } + // downsample shader_id = client->getShaderSource()->getShader("bloom_downsample", TILE_MATERIAL_PLAIN, NDT_MESH); for (u8 i = 0; i < MIPMAP_LEVELS; i++) { auto step = pipeline->addStep(shader_id, std::vector { source }); step->setRenderSource(buffer); step->setBilinearFilter(0, true); - step->setRenderTarget(pipeline->createOwned(buffer, TEXTURE_BLOOM_DOWN + i)); - source = TEXTURE_BLOOM_DOWN + i; + step->setRenderTarget(pipeline->createOwned(buffer, TEXTURE_SCALE_DOWN + i)); + source = TEXTURE_SCALE_DOWN + i; } } @@ -193,19 +205,19 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep // upsample shader_id = client->getShaderSource()->getShader("bloom_upsample", TILE_MATERIAL_PLAIN, NDT_MESH); for (u8 i = MIPMAP_LEVELS - 1; i > 0; i--) { - auto step = pipeline->addStep(shader_id, std::vector { u8(TEXTURE_BLOOM_DOWN + i - 1), source }); + auto step = pipeline->addStep(shader_id, std::vector { u8(TEXTURE_SCALE_DOWN + i - 1), source }); step->setRenderSource(buffer); step->setBilinearFilter(0, true); step->setBilinearFilter(1, true); - step->setRenderTarget(pipeline->createOwned(buffer, u8(TEXTURE_BLOOM_UP + i - 1))); - source = TEXTURE_BLOOM_UP + i - 1; + step->setRenderTarget(pipeline->createOwned(buffer, u8(TEXTURE_SCALE_UP + i - 1))); + source = TEXTURE_SCALE_UP + i - 1; } } // Dynamic Exposure pt2 if (enable_auto_exposure) { shader_id = client->getShaderSource()->getShader("update_exposure", TILE_MATERIAL_PLAIN, NDT_MESH); - auto update_exposure = pipeline->addStep(shader_id, std::vector { TEXTURE_EXPOSURE_1, u8(TEXTURE_BLOOM_DOWN + MIPMAP_LEVELS - 1) }); + auto update_exposure = pipeline->addStep(shader_id, std::vector { TEXTURE_EXPOSURE_1, u8(TEXTURE_SCALE_DOWN + MIPMAP_LEVELS - 1) }); update_exposure->setBilinearFilter(1, true); update_exposure->setRenderSource(buffer); update_exposure->setRenderTarget(pipeline->createOwned(buffer, TEXTURE_EXPOSURE_2)); @@ -228,7 +240,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep // final merge shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH); - PostProcessingStep *effect = pipeline->createOwned(shader_id, std::vector { final_stage_source, TEXTURE_BLOOM_UP, TEXTURE_EXPOSURE_2 }); + PostProcessingStep *effect = pipeline->createOwned(shader_id, std::vector { final_stage_source, TEXTURE_SCALE_UP, TEXTURE_EXPOSURE_2 }); pipeline->addStep(effect); if (enable_ssaa) effect->setBilinearFilter(0, true); diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 3e6e67e45..9d074e886 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -770,6 +770,10 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, if (g_settings->getBool("debanding")) shaders_header << "#define ENABLE_DITHERING 1\n"; + if (g_settings->getBool("enable_volumetric_lighting")) { + shaders_header << "#define VOLUMETRIC_LIGHT 1\n"; + } + shaders_header << "#line 0\n"; // reset the line counter for meaningful diagnostics std::string common_header = shaders_header.str(); diff --git a/src/client/sky.h b/src/client/sky.h index a5b92ace2..b76a5311b 100644 --- a/src/client/sky.h +++ b/src/client/sky.h @@ -120,6 +120,9 @@ public: void setFogStart(float fog_start) { m_sky_params.fog_start = fog_start; } float getFogStart() const { return m_sky_params.fog_start; } + void setVolumetricLightStrength(float volumetric_light_strength) { m_sky_params.volumetric_light_strength = volumetric_light_strength; } + float getVolumetricLightStrength() const { return m_sky_params.volumetric_light_strength; } + private: aabb3f m_box; video::SMaterial m_materials[SKY_MATERIAL_COUNT]; diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 90d7df05f..4505bdc2c 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -271,6 +271,7 @@ void set_default_settings() settings->setDefault("bloom_strength_factor", "1.0"); settings->setDefault("bloom_intensity", "0.05"); settings->setDefault("bloom_radius", "1"); + settings->setDefault("enable_volumetric_lighting", "false"); // Effects Shadows settings->setDefault("enable_dynamic_shadows", "false"); diff --git a/src/lighting.h b/src/lighting.h index 0535383a6..262a48b5d 100644 --- a/src/lighting.h +++ b/src/lighting.h @@ -53,4 +53,5 @@ struct Lighting AutoExposure exposure; float shadow_intensity {0.0f}; float saturation {1.0f}; + float volumetric_light_strength {0.0f}; }; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 2cb3b20ed..3c6da09a7 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1804,4 +1804,6 @@ void Client::handleCommand_SetLighting(NetworkPacket *pkt) >> lighting.exposure.speed_bright_dark >> lighting.exposure.center_weight_power; } + if (pkt->getRemainingBytes() >= 4) + *pkt >> lighting.volumetric_light_strength; } diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 0221b2576..c9dae1885 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2495,7 +2495,14 @@ int ObjectRef::l_set_lighting(lua_State *L) lighting.exposure.center_weight_power = getfloatfield_default(L, -1, "center_weight_power", lighting.exposure.center_weight_power); } lua_pop(L, 1); // exposure - } + + lua_getfield(L, 2, "volumetric_light"); + if (lua_istable(L, -1)) { + getfloatfield(L, -1, "strength", lighting.volumetric_light_strength); + lighting.volumetric_light_strength = rangelim(lighting.volumetric_light_strength, 0.0f, 1.0f); + } + lua_pop(L, 1); // volumetric_light +} getServer(L)->setLighting(player, lighting); return 0; @@ -2533,6 +2540,10 @@ int ObjectRef::l_get_lighting(lua_State *L) lua_pushnumber(L, lighting.exposure.center_weight_power); lua_setfield(L, -2, "center_weight_power"); lua_setfield(L, -2, "exposure"); + lua_newtable(L); // "volumetric_light" + lua_pushnumber(L, lighting.volumetric_light_strength); + lua_setfield(L, -2, "strength"); + lua_setfield(L, -2, "volumetric_light"); return 1; } diff --git a/src/server.cpp b/src/server.cpp index 19b506ddd..af79632e5 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1919,6 +1919,8 @@ void Server::SendSetLighting(session_t peer_id, const Lighting &lighting) << lighting.exposure.speed_bright_dark << lighting.exposure.center_weight_power; + pkt << lighting.volumetric_light_strength; + Send(&pkt); } diff --git a/src/skyparams.h b/src/skyparams.h index 554904bc0..ff9a921ae 100644 --- a/src/skyparams.h +++ b/src/skyparams.h @@ -46,6 +46,7 @@ struct SkyboxParams float body_orbit_tilt { INVALID_SKYBOX_TILT }; s16 fog_distance { -1 }; float fog_start { -1.0f }; + float volumetric_light_strength { 0.0f }; }; struct SunParams