mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-10-30 15:05:32 +01:00 
			
		
		
		
	Improve bloom effect (#12916)
* Remove the built-in exposure factor of 2.5 * Add physics-based bloom (https://learnopengl.com/Guest-Articles/2022/Phys.-Based-Bloom) * Add luminance scaling for bloom layer to simulate HDR * Add setting to control bloom strength
This commit is contained in:
		| @@ -432,6 +432,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter | ||||
| 	bool m_bloom_enabled; | ||||
| 	CachedPixelShaderSetting<float> m_bloom_intensity_pixel; | ||||
| 	float m_bloom_intensity; | ||||
| 	CachedPixelShaderSetting<float> m_bloom_strength_pixel; | ||||
| 	float m_bloom_strength; | ||||
| 	CachedPixelShaderSetting<float> m_bloom_radius_pixel; | ||||
| 	float m_bloom_radius; | ||||
| 
 | ||||
| @@ -444,8 +446,10 @@ public: | ||||
| 			m_user_exposure_factor = g_settings->getFloat("exposure_factor", 0.1f, 10.0f); | ||||
| 		if (name == "bloom_intensity") | ||||
| 			m_bloom_intensity = g_settings->getFloat("bloom_intensity", 0.01f, 1.0f); | ||||
| 		if (name == "bloom_strength_factor") | ||||
| 			m_bloom_strength = RenderingEngine::BASE_BLOOM_STRENGTH * g_settings->getFloat("bloom_strength_factor", 0.1f, 10.0f); | ||||
| 		if (name == "bloom_radius") | ||||
| 			m_bloom_radius = g_settings->getFloat("bloom_radius", 1.0f, 64.0f); | ||||
| 			m_bloom_radius = g_settings->getFloat("bloom_radius", 0.1f, 8.0f); | ||||
| 	} | ||||
| 
 | ||||
| 	static void settingsCallback(const std::string &name, void *userdata) | ||||
| @@ -479,17 +483,20 @@ public: | ||||
| 		m_texel_size0("texelSize0"), | ||||
| 		m_exposure_factor_pixel("exposureFactor"), | ||||
| 		m_bloom_intensity_pixel("bloomIntensity"), | ||||
| 		m_bloom_strength_pixel("bloomStrength"), | ||||
| 		m_bloom_radius_pixel("bloomRadius") | ||||
| 	{ | ||||
| 		g_settings->registerChangedCallback("enable_fog", settingsCallback, this); | ||||
| 		g_settings->registerChangedCallback("exposure_factor", settingsCallback, this); | ||||
| 		g_settings->registerChangedCallback("bloom_intensity", settingsCallback, this); | ||||
| 		g_settings->registerChangedCallback("bloom_strength_factor", settingsCallback, this); | ||||
| 		g_settings->registerChangedCallback("bloom_radius", settingsCallback, this); | ||||
| 		m_fog_enabled = g_settings->getBool("enable_fog"); | ||||
| 		m_user_exposure_factor = g_settings->getFloat("exposure_factor", 0.1f, 10.0f); | ||||
| 		m_bloom_enabled = g_settings->getBool("enable_bloom"); | ||||
| 		m_bloom_intensity = g_settings->getFloat("bloom_intensity", 0.01f, 1.0f); | ||||
| 		m_bloom_radius = g_settings->getFloat("bloom_radius", 1.0f, 64.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); | ||||
| 	} | ||||
| 
 | ||||
| 	~GameGlobalShaderConstantSetter() | ||||
| @@ -567,14 +574,15 @@ public: | ||||
| 
 | ||||
| 		m_texel_size0.set(m_texel_size0_values.data(), services); | ||||
| 
 | ||||
| 		float exposure_factor = RenderingEngine::DEFAULT_EXPOSURE_FACTOR * m_user_exposure_factor; | ||||
| 		float exposure_factor = m_user_exposure_factor; | ||||
| 		if (std::isnan(exposure_factor)) | ||||
| 			exposure_factor = RenderingEngine::DEFAULT_EXPOSURE_FACTOR; | ||||
| 			exposure_factor = 1.0f; | ||||
| 		m_exposure_factor_pixel.set(&exposure_factor, services); | ||||
| 
 | ||||
| 		if (m_bloom_enabled) { | ||||
| 			m_bloom_intensity_pixel.set(&m_bloom_intensity, services); | ||||
| 			m_bloom_radius_pixel.set(&m_bloom_radius, services); | ||||
| 			m_bloom_strength_pixel.set(&m_bloom_strength, services); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|   | ||||
| @@ -390,9 +390,10 @@ public: | ||||
| 	 * @return RenderStep* Pointer to the created step for further configuration. | ||||
| 	 */ | ||||
| 	template<typename T, typename... Args> | ||||
| 	RenderStep *addStep(Args&&... args) { | ||||
| 	T *addStep(Args&&... args) { | ||||
| 		T* result = own(std::make_unique<T>(std::forward<Args>(args)...)); | ||||
| 		return addStep(result); | ||||
| 		addStep(result); | ||||
| 		return result; | ||||
| 	} | ||||
| 
 | ||||
| 	RenderSource *getInput(); | ||||
|   | ||||
| @@ -115,8 +115,8 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep | ||||
| 	static const u8 TEXTURE_COLOR = 0; | ||||
| 	static const u8 TEXTURE_DEPTH = 1; | ||||
| 	static const u8 TEXTURE_BLOOM = 2; | ||||
| 	static const u8 TEXTURE_BLUR = 3; | ||||
| 	static const u8 TEXTURE_BLUR_SECONDARY = 4; | ||||
| 	static const u8 TEXTURE_BLOOM_DOWN = 10; | ||||
| 	static const u8 TEXTURE_BLOOM_UP = 20; | ||||
| 
 | ||||
| 	buffer->setTexture(TEXTURE_COLOR, scale, "3d_render", color_format); | ||||
| 	buffer->setTexture(TEXTURE_DEPTH, scale, "3d_depthmap", depth_format); | ||||
| @@ -124,39 +124,56 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep | ||||
| 	// attach buffer to the previous step
 | ||||
| 	previousStep->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, std::vector<u8> { TEXTURE_COLOR }, TEXTURE_DEPTH)); | ||||
| 
 | ||||
| 	// shared variables
 | ||||
| 	u32 shader_id; | ||||
| 
 | ||||
| 	// post-processing stage
 | ||||
| 	// set up bloom
 | ||||
| 	if (g_settings->getBool("enable_bloom")) { | ||||
| 
 | ||||
| 		buffer->setTexture(TEXTURE_BLUR, scale * 0.5, "blur", color_format); | ||||
| 		buffer->setTexture(TEXTURE_BLOOM, scale * 0.5, "bloom", color_format); | ||||
| 		u8 bloom_input_texture = TEXTURE_BLOOM; | ||||
| 		 | ||||
| 		if (g_settings->getBool("enable_bloom_dedicated_texture")) { | ||||
| 			buffer->setTexture(TEXTURE_BLUR_SECONDARY, scale * 0.5, "blur2", color_format); | ||||
| 			bloom_input_texture = TEXTURE_BLUR_SECONDARY; | ||||
| 
 | ||||
| 		buffer->setTexture(TEXTURE_BLOOM, scale, "bloom", color_format); | ||||
| 
 | ||||
| 		const u8 MIPMAP_LEVELS = 4; | ||||
| 		v2f downscale = scale * 0.5; | ||||
| 		for (u8 i = 0; i < MIPMAP_LEVELS; i++) { | ||||
| 			buffer->setTexture(TEXTURE_BLOOM_DOWN + i, downscale, std::string("bloom_down") + std::to_string(i), color_format); | ||||
| 			buffer->setTexture(TEXTURE_BLOOM_UP + i, downscale, std::string("bloom_up") + std::to_string(i), color_format); | ||||
| 			downscale *= 0.5; | ||||
| 		} | ||||
| 
 | ||||
| 		// get bright spots
 | ||||
| 		u32 shader_id = client->getShaderSource()->getShader("extract_bloom", TILE_MATERIAL_PLAIN, NDT_MESH); | ||||
| 		RenderStep *extract_bloom = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR }); | ||||
| 		extract_bloom->setRenderSource(buffer); | ||||
| 		extract_bloom->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, bloom_input_texture)); | ||||
| 		// horizontal blur
 | ||||
| 		shader_id = client->getShaderSource()->getShader("blur_h", TILE_MATERIAL_PLAIN, NDT_MESH); | ||||
| 		RenderStep *blur_h = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { bloom_input_texture }); | ||||
| 		blur_h->setRenderSource(buffer); | ||||
| 		blur_h->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLUR)); | ||||
| 		// vertical blur
 | ||||
| 		shader_id = client->getShaderSource()->getShader("blur_v", TILE_MATERIAL_PLAIN, NDT_MESH); | ||||
| 		RenderStep *blur_v = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_BLUR }); | ||||
| 		blur_v->setRenderSource(buffer); | ||||
| 		blur_v->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM)); | ||||
| 		extract_bloom->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM)); | ||||
| 
 | ||||
| 		// downsample
 | ||||
| 		shader_id = client->getShaderSource()->getShader("bloom_downsample", TILE_MATERIAL_PLAIN, NDT_MESH); | ||||
| 		u8 source = TEXTURE_BLOOM; | ||||
| 		for (u8 i = 0; i < MIPMAP_LEVELS; i++) { | ||||
| 			auto step = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source }); | ||||
| 			step->setRenderSource(buffer); | ||||
| 			step->setBilinearFilter(0, true); | ||||
| 			step->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM_DOWN + i)); | ||||
| 			source = TEXTURE_BLOOM_DOWN + i; | ||||
| 		} | ||||
| 
 | ||||
| 		// 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<PostProcessingStep>(shader_id, std::vector<u8> { u8(TEXTURE_BLOOM_DOWN + i - 1), source }); | ||||
| 			step->setRenderSource(buffer); | ||||
| 			step->setBilinearFilter(0, true); | ||||
| 			step->setBilinearFilter(1, true); | ||||
| 			step->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, u8(TEXTURE_BLOOM_UP + i - 1))); | ||||
| 			source = TEXTURE_BLOOM_UP + i - 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// final post-processing
 | ||||
| 	u32 shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH); | ||||
| 	PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR, TEXTURE_BLOOM }); | ||||
| 	shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH); | ||||
| 	PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR, TEXTURE_BLOOM_UP }); | ||||
| 	pipeline->addStep(effect); | ||||
| 	effect->setBilinearFilter(1, true); // apply filter to the bloom
 | ||||
| 	effect->setRenderSource(buffer); | ||||
|   | ||||
| @@ -56,6 +56,7 @@ with this program; if not, write to the Free Software Foundation, Inc., | ||||
| #endif | ||||
| 
 | ||||
| RenderingEngine *RenderingEngine::s_singleton = nullptr; | ||||
| const float RenderingEngine::BASE_BLOOM_STRENGTH = 8.0f; | ||||
| 
 | ||||
| 
 | ||||
| static gui::GUISkin *createSkin(gui::IGUIEnvironment *environment, | ||||
|   | ||||
| @@ -46,9 +46,7 @@ class RenderingCore; | ||||
| class RenderingEngine | ||||
| { | ||||
| public: | ||||
| 	/// Default color factor before applying effects like bloom or tomemapping
 | ||||
| 	/// this is derived from tonemapping code and tuned empirically
 | ||||
| 	static constexpr float DEFAULT_EXPOSURE_FACTOR = 2.5f; | ||||
| 	static const float BASE_BLOOM_STRENGTH; | ||||
| 
 | ||||
| 	RenderingEngine(IEventReceiver *eventReceiver); | ||||
| 	~RenderingEngine(); | ||||
|   | ||||
| @@ -273,9 +273,9 @@ void set_default_settings() | ||||
| 	settings->setDefault("exposure_factor", "1.0"); | ||||
| 	settings->setDefault("enable_bloom", "false"); | ||||
| 	settings->setDefault("enable_bloom_debug", "false"); | ||||
| 	settings->setDefault("enable_bloom_dedicated_texture", "false"); | ||||
| 	settings->setDefault("bloom_strength_factor", "1.0"); | ||||
| 	settings->setDefault("bloom_intensity", "0.05"); | ||||
| 	settings->setDefault("bloom_radius", "16"); | ||||
| 	settings->setDefault("bloom_radius", "1"); | ||||
| 
 | ||||
| 	// Effects Shadows
 | ||||
| 	settings->setDefault("enable_dynamic_shadows", "false"); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user