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.
This commit is contained in:
JFonS 2021-02-15 12:32:31 +01:00
parent 7241139356
commit 56bf256d76
7 changed files with 112 additions and 18 deletions

View File

@ -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">

View File

@ -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>

View File

@ -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"

View File

@ -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)); oidnSetSharedFilterImage(filter, "color", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
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, "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);

View File

@ -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();
} }

View File

@ -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) {
_save_image(base_path, large_image, use_srgb);
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);
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"; _save_image(base_path, images[i], use_srgb);
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);
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;

View File

@ -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;