Browse Source

Add options to reduce lightmaps disk usage.

Added BakedLightmap.use_hdr and BakedLightmap.use_color properties
that can reduce the flie size of lightmap texture at the expense of quality.

Changed the denoiser to work in a single buffer, reducing RAM
usage. Also added the `-mstackrealign` flag in the denoiser compilation
for MinGW builds. This flag helped fix a bug in Embree, so I want to see
if it will help fix GH #45296.
JFonS 4 years ago
parent
commit
56bf256d76

+ 6 - 0
doc/classes/BakedLightmap.xml

@@ -78,9 +78,15 @@
 		<member name="quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="BakedLightmap.BakeQuality" default="1">
 		<member name="quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="BakedLightmap.BakeQuality" default="1">
 			Determines the amount of samples per texel used in indrect light baking. The amount of samples for each quality level can be configured in the project settings.
 			Determines the amount of samples per texel used in indrect light baking. The amount of samples for each quality level can be configured in the project settings.
 		</member>
 		</member>
+		<member name="use_color" type="bool" setter="set_use_color" getter="is_using_color" default="true">
+			Store full color values in the lightmap textures. When disabled, lightmap textures will store a single brightness channel. Can be disabled to reduce disk usage if the scene contains only white lights or you don't mind losing color information in indirect lighting.
+		</member>
 		<member name="use_denoiser" type="bool" setter="set_use_denoiser" getter="is_using_denoiser" default="true">
 		<member name="use_denoiser" type="bool" setter="set_use_denoiser" getter="is_using_denoiser" default="true">
 			When enabled, a lightmap denoiser will be used to reduce the noise inherent to Monte Carlo based global illumination.
 			When enabled, a lightmap denoiser will be used to reduce the noise inherent to Monte Carlo based global illumination.
 		</member>
 		</member>
+		<member name="use_hdr" type="bool" setter="set_use_hdr" getter="is_using_hdr" default="true">
+			Store the lightmap textures in a Hight Dynamic Range format (EXR). Can be disabled to reduce disk usage, but light values over 1.0 will be clamped and you may see banding caused by the reduced precision.
+		</member>
 	</members>
 	</members>
 	<constants>
 	<constants>
 		<constant name="BAKE_QUALITY_LOW" value="0" enum="BakeQuality">
 		<constant name="BAKE_QUALITY_LOW" value="0" enum="BakeQuality">

+ 6 - 0
doc/classes/BakedLightmapData.xml

@@ -23,6 +23,12 @@
 			<description>
 			<description>
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="clear_data">
+			<return type="void">
+			</return>
+			<description>
+			</description>
+		</method>
 		<method name="clear_users">
 		<method name="clear_users">
 			<return type="void">
 			<return type="void">
 			</return>
 			</return>

+ 3 - 0
modules/denoise/SCsub

@@ -108,6 +108,9 @@ env_thirdparty = env_oidn.Clone()
 env_thirdparty.disable_warnings()
 env_thirdparty.disable_warnings()
 env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
 env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
 
 
+if env["platform"] == "windows" and not env.msvc:
+    env_thirdparty.Append(CPPFLAGS=["-mstackrealign"])
+
 weights_in_path = thirdparty_dir + "weights/rtlightmap_hdr.tza"
 weights_in_path = thirdparty_dir + "weights/rtlightmap_hdr.tza"
 weights_out_path = thirdparty_dir + "weights/rtlightmap_hdr.gen.cpp"
 weights_out_path = thirdparty_dir + "weights/rtlightmap_hdr.gen.cpp"
 
 

+ 1 - 3
modules/denoise/denoise_wrapper.cpp

@@ -43,9 +43,7 @@ void *oidn_denoiser_init() {
 bool oidn_denoise(void *deviceptr, float *p_floats, int p_width, int p_height) {
 bool oidn_denoise(void *deviceptr, float *p_floats, int p_width, int p_height) {
 	OIDNDeviceImpl *device = (OIDNDeviceImpl *)deviceptr;
 	OIDNDeviceImpl *device = (OIDNDeviceImpl *)deviceptr;
 	OIDNFilter filter = oidnNewFilter(device, "RTLightmap");
 	OIDNFilter filter = oidnNewFilter(device, "RTLightmap");
-	void *input_buffer = memalloc(p_width * p_height * 3 * sizeof(float));
-	copymem(input_buffer, p_floats, p_width * p_height * 3 * sizeof(float));
-	oidnSetSharedFilterImage(filter, "color", input_buffer, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
+	oidnSetSharedFilterImage(filter, "color", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
 	oidnSetSharedFilterImage(filter, "output", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
 	oidnSetSharedFilterImage(filter, "output", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
 	oidnSetFilter1b(filter, "hdr", true);
 	oidnSetFilter1b(filter, "hdr", true);
 	oidnCommitFilter(filter);
 	oidnCommitFilter(filter);

+ 2 - 0
modules/lightmapper_cpu/lightmapper_cpu.cpp

@@ -1369,6 +1369,7 @@ LightmapperCPU::BakeError LightmapperCPU::bake(BakeQuality p_quality, bool p_use
 	if (parameters.environment_panorama.is_valid()) {
 	if (parameters.environment_panorama.is_valid()) {
 		parameters.environment_panorama->lock();
 		parameters.environment_panorama->lock();
 	}
 	}
+
 	for (unsigned int i = 0; i < mesh_instances.size(); i++) {
 	for (unsigned int i = 0; i < mesh_instances.size(); i++) {
 
 
 		if (!mesh_instances[i].generate_lightmap) {
 		if (!mesh_instances[i].generate_lightmap) {
@@ -1389,6 +1390,7 @@ LightmapperCPU::BakeError LightmapperCPU::bake(BakeQuality p_quality, bool p_use
 			}
 			}
 		}
 		}
 	}
 	}
+
 	if (parameters.environment_panorama.is_valid()) {
 	if (parameters.environment_panorama.is_valid()) {
 		parameters.environment_panorama->unlock();
 		parameters.environment_panorama->unlock();
 	}
 	}

+ 85 - 15
scene/3d/baked_lightmap.cpp

@@ -516,6 +516,55 @@ void BakedLightmap::_get_material_images(const MeshesFound &p_found_mesh, Lightm
 	}
 	}
 }
 }
 
 
+void BakedLightmap::_save_image(String &r_base_path, Ref<Image> r_img, bool p_use_srgb) {
+	if (use_hdr) {
+		r_base_path += ".exr";
+	} else {
+		r_base_path += ".png";
+	}
+
+	String relative_path = r_base_path;
+	if (relative_path.begins_with("res://")) {
+		relative_path = relative_path.substr(6, relative_path.length());
+	}
+
+	bool hdr_grayscale = use_hdr && !use_color;
+
+	if (p_use_srgb || hdr_grayscale) {
+		r_img->lock();
+		for (int i = 0; i < r_img->get_height(); i++) {
+			for (int j = 0; j < r_img->get_width(); j++) {
+				Color c = r_img->get_pixel(j, i);
+
+				if (hdr_grayscale) {
+					c = Color(c.get_v(), 0.0f, 0.0f);
+				}
+
+				if (p_use_srgb) {
+					c = c.to_srgb();
+				}
+
+				r_img->set_pixel(j, i, c);
+			}
+		}
+		r_img->unlock();
+	}
+
+	if (!use_color) {
+		if (use_hdr) {
+			r_img->convert(Image::FORMAT_RH);
+		} else {
+			r_img->convert(Image::FORMAT_L8);
+		}
+	}
+
+	if (use_hdr) {
+		r_img->save_exr(relative_path, !use_color);
+	} else {
+		r_img->save_png(relative_path);
+	}
+}
+
 bool BakedLightmap::_lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh) {
 bool BakedLightmap::_lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh) {
 	BakeStepUD *bsud = (BakeStepUD *)ud;
 	BakeStepUD *bsud = (BakeStepUD *)ud;
 	bool ret = false;
 	bool ret = false;
@@ -893,6 +942,8 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa
 		images.push_back(lightmapper->get_bake_texture(i));
 		images.push_back(lightmapper->get_bake_texture(i));
 	}
 	}
 
 
+	bool use_srgb = use_color && !use_hdr;
+
 	if (gen_atlas) {
 	if (gen_atlas) {
 
 
 		Ref<Image> large_image;
 		Ref<Image> large_image;
@@ -906,13 +957,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa
 		String base_path = p_data_save_path.get_basename();
 		String base_path = p_data_save_path.get_basename();
 
 
 		if (ResourceLoader::import) {
 		if (ResourceLoader::import) {
-
-			base_path += ".exr";
-			String relative_path = base_path;
-			if (relative_path.begins_with("res://")) {
-				relative_path = relative_path.substr(6, relative_path.length());
-			}
-			large_image->save_exr(relative_path, false);
+			_save_image(base_path, large_image, use_srgb);
 
 
 			Ref<ConfigFile> config;
 			Ref<ConfigFile> config;
 			config.instance();
 			config.instance();
@@ -928,7 +973,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa
 			config->set_value("params", "flags/repeat", false);
 			config->set_value("params", "flags/repeat", false);
 			config->set_value("params", "flags/filter", true);
 			config->set_value("params", "flags/filter", true);
 			config->set_value("params", "flags/mipmaps", false);
 			config->set_value("params", "flags/mipmaps", false);
-			config->set_value("params", "flags/srgb", false);
+			config->set_value("params", "flags/srgb", use_srgb);
 			config->set_value("params", "slices/horizontal", 1);
 			config->set_value("params", "slices/horizontal", 1);
 			config->set_value("params", "slices/vertical", images.size());
 			config->set_value("params", "slices/vertical", images.size());
 			config->save(base_path + ".import");
 			config->save(base_path + ".import");
@@ -987,12 +1032,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa
 
 
 			if (ResourceLoader::import) {
 			if (ResourceLoader::import) {
 
 
-				base_path += ".exr";
-				String relative_path = base_path;
-				if (relative_path.begins_with("res://")) {
-					relative_path = relative_path.substr(6, relative_path.length());
-				}
-				images[i]->save_exr(relative_path, false);
+				_save_image(base_path, images[i], use_srgb);
 
 
 				Ref<ConfigFile> config;
 				Ref<ConfigFile> config;
 				config.instance();
 				config.instance();
@@ -1008,7 +1048,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa
 				config->set_value("params", "flags/repeat", false);
 				config->set_value("params", "flags/repeat", false);
 				config->set_value("params", "flags/filter", true);
 				config->set_value("params", "flags/filter", true);
 				config->set_value("params", "flags/mipmaps", false);
 				config->set_value("params", "flags/mipmaps", false);
-				config->set_value("params", "flags/srgb", false);
+				config->set_value("params", "flags/srgb", use_srgb);
 
 
 				config->save(base_path + ".import");
 				config->save(base_path + ".import");
 
 
@@ -1309,6 +1349,26 @@ bool BakedLightmap::is_using_denoiser() const {
 	return use_denoiser;
 	return use_denoiser;
 }
 }
 
 
+void BakedLightmap::set_use_hdr(bool p_enable) {
+
+	use_hdr = p_enable;
+}
+
+bool BakedLightmap::is_using_hdr() const {
+
+	return use_hdr;
+}
+
+void BakedLightmap::set_use_color(bool p_enable) {
+
+	use_color = p_enable;
+}
+
+bool BakedLightmap::is_using_color() const {
+
+	return use_color;
+}
+
 void BakedLightmap::set_environment_mode(EnvironmentMode p_mode) {
 void BakedLightmap::set_environment_mode(EnvironmentMode p_mode) {
 	environment_mode = p_mode;
 	environment_mode = p_mode;
 	_change_notify();
 	_change_notify();
@@ -1428,6 +1488,12 @@ void BakedLightmap::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_use_denoiser", "use_denoiser"), &BakedLightmap::set_use_denoiser);
 	ClassDB::bind_method(D_METHOD("set_use_denoiser", "use_denoiser"), &BakedLightmap::set_use_denoiser);
 	ClassDB::bind_method(D_METHOD("is_using_denoiser"), &BakedLightmap::is_using_denoiser);
 	ClassDB::bind_method(D_METHOD("is_using_denoiser"), &BakedLightmap::is_using_denoiser);
 
 
+	ClassDB::bind_method(D_METHOD("set_use_hdr", "use_denoiser"), &BakedLightmap::set_use_hdr);
+	ClassDB::bind_method(D_METHOD("is_using_hdr"), &BakedLightmap::is_using_hdr);
+
+	ClassDB::bind_method(D_METHOD("set_use_color", "use_denoiser"), &BakedLightmap::set_use_color);
+	ClassDB::bind_method(D_METHOD("is_using_color"), &BakedLightmap::is_using_color);
+
 	ClassDB::bind_method(D_METHOD("set_generate_atlas", "enabled"), &BakedLightmap::set_generate_atlas);
 	ClassDB::bind_method(D_METHOD("set_generate_atlas", "enabled"), &BakedLightmap::set_generate_atlas);
 	ClassDB::bind_method(D_METHOD("is_generate_atlas_enabled"), &BakedLightmap::is_generate_atlas_enabled);
 	ClassDB::bind_method(D_METHOD("is_generate_atlas_enabled"), &BakedLightmap::is_generate_atlas_enabled);
 
 
@@ -1463,6 +1529,8 @@ void BakedLightmap::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "quality", PROPERTY_HINT_ENUM, "Low,Medium,High,Ultra"), "set_bake_quality", "get_bake_quality");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "quality", PROPERTY_HINT_ENUM, "Low,Medium,High,Ultra"), "set_bake_quality", "get_bake_quality");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "bounces", PROPERTY_HINT_RANGE, "0,16,1"), "set_bounces", "get_bounces");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "bounces", PROPERTY_HINT_RANGE, "0,16,1"), "set_bounces", "get_bounces");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_denoiser"), "set_use_denoiser", "is_using_denoiser");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_denoiser"), "set_use_denoiser", "is_using_denoiser");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_color"), "set_use_color", "is_using_color");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_RANGE, "0.00001,0.1,0.00001,or_greater"), "set_bias", "get_bias");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_RANGE, "0.00001,0.1,0.00001,or_greater"), "set_bias", "get_bias");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "default_texels_per_unit", PROPERTY_HINT_RANGE, "0.0,64.0,0.01,or_greater"), "set_default_texels_per_unit", "get_default_texels_per_unit");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "default_texels_per_unit", PROPERTY_HINT_RANGE, "0.0,64.0,0.01,or_greater"), "set_default_texels_per_unit", "get_default_texels_per_unit");
 
 
@@ -1528,6 +1596,8 @@ BakedLightmap::BakedLightmap() {
 	environment_custom_energy = 1.0;
 	environment_custom_energy = 1.0;
 
 
 	use_denoiser = true;
 	use_denoiser = true;
+	use_hdr = true;
+	use_color = true;
 	bias = 0.005;
 	bias = 0.005;
 
 
 	generate_atlas = true;
 	generate_atlas = true;

+ 9 - 0
scene/3d/baked_lightmap.h

@@ -161,6 +161,8 @@ private:
 	bool capture_enabled;
 	bool capture_enabled;
 	int bounces;
 	int bounces;
 	bool use_denoiser;
 	bool use_denoiser;
+	bool use_hdr;
+	bool use_color;
 
 
 	EnvironmentMode environment_mode;
 	EnvironmentMode environment_mode;
 	Ref<Sky> environment_custom_sky;
 	Ref<Sky> environment_custom_sky;
@@ -186,6 +188,7 @@ private:
 	Vector2i _compute_lightmap_size(const MeshesFound &p_mesh);
 	Vector2i _compute_lightmap_size(const MeshesFound &p_mesh);
 
 
 	static bool _lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh);
 	static bool _lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh);
+	void _save_image(String &r_base_path, Ref<Image> p_img, bool p_use_srgb);
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
@@ -247,6 +250,12 @@ public:
 	void set_use_denoiser(bool p_enable);
 	void set_use_denoiser(bool p_enable);
 	bool is_using_denoiser() const;
 	bool is_using_denoiser() const;
 
 
+	void set_use_hdr(bool p_enable);
+	bool is_using_hdr() const;
+
+	void set_use_color(bool p_enable);
+	bool is_using_color() const;
+
 	void set_bounces(int p_bounces);
 	void set_bounces(int p_bounces);
 	int get_bounces() const;
 	int get_bounces() const;