瀏覽代碼

Add an option to clamp HDR exposure to reduce environment fireflies

HDRI panoramas designed for realistic lighting can have extremely
bright suns, causing fireflies to appear in the environment reflection
(in addition to making environment lighting too bright when a
DirectionalLight3D is used).

This uses the Filament tonemapping formula.
Hugo Locurcio 3 年之前
父節點
當前提交
2694138060
共有 1 個文件被更改,包括 30 次插入0 次删除
  1. 30 0
      editor/import/resource_importer_texture.cpp

+ 30 - 0
editor/import/resource_importer_texture.cpp

@@ -217,6 +217,7 @@ void ResourceImporterTexture::get_import_options(const String &p_path, List<Impo
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/normal_map_invert_y"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/normal_map_invert_y"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/hdr_as_srgb"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/hdr_as_srgb"), false));
+	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/hdr_clamp_exposure"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "detect_3d/compress_to", PROPERTY_HINT_ENUM, "Disabled,VRAM Compressed,Basis Universal"), (p_preset == PRESET_DETECT) ? 1 : 0));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "detect_3d/compress_to", PROPERTY_HINT_ENUM, "Disabled,VRAM Compressed,Basis Universal"), (p_preset == PRESET_DETECT) ? 1 : 0));
 
 
@@ -411,6 +412,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
 	const bool stream = p_options["compress/streamed"];
 	const bool stream = p_options["compress/streamed"];
 	const int size_limit = p_options["process/size_limit"];
 	const int size_limit = p_options["process/size_limit"];
 	const bool hdr_as_srgb = p_options["process/hdr_as_srgb"];
 	const bool hdr_as_srgb = p_options["process/hdr_as_srgb"];
+	const bool hdr_clamp_exposure = p_options["process/hdr_clamp_exposure"];
 	const int normal = p_options["compress/normal_map"];
 	const int normal = p_options["compress/normal_map"];
 	const int hdr_compression = p_options["compress/hdr_compression"];
 	const int hdr_compression = p_options["compress/hdr_compression"];
 	const int bptc_ldr = p_options["compress/bptc_ldr"];
 	const int bptc_ldr = p_options["compress/bptc_ldr"];
@@ -482,6 +484,34 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
 		}
 		}
 	}
 	}
 
 
+	if (hdr_clamp_exposure) {
+		// Clamp HDR exposure following Filament's tonemapping formula.
+		// This can be used to reduce fireflies in environment maps or reduce the influence
+		// of the sun from an HDRI panorama on environment lighting (when a DirectionalLight3D is used instead).
+		const int height = image->get_height();
+		const int width = image->get_width();
+
+		// These values are chosen arbitrarily and seem to produce good results with 4,096 samples.
+		const float linear = 4096.0;
+		const float compressed = 16384.0;
+
+		for (int i = 0; i < width; i++) {
+			for (int j = 0; j < height; j++) {
+				const Color color = image->get_pixel(i, j);
+				const float luma = color.get_luminance();
+
+				Color clamped_color;
+				if (luma <= linear) {
+					clamped_color = color;
+				} else {
+					clamped_color = (color / luma) * ((linear * linear - compressed * luma) / (2 * linear - compressed - luma));
+				}
+
+				image->set_pixel(i, j, clamped_color);
+			}
+		}
+	}
+
 	if (compress_mode == COMPRESS_BASIS_UNIVERSAL && image->get_format() >= Image::FORMAT_RF) {
 	if (compress_mode == COMPRESS_BASIS_UNIVERSAL && image->get_format() >= Image::FORMAT_RF) {
 		//basis universal does not support float formats, fall back
 		//basis universal does not support float formats, fall back
 		compress_mode = COMPRESS_VRAM_COMPRESSED;
 		compress_mode = COMPRESS_VRAM_COMPRESSED;