diff --git a/doc/classes/BakedLightmap.xml b/doc/classes/BakedLightmap.xml
index f7d280f36f6..eba1ae6bd4b 100644
--- a/doc/classes/BakedLightmap.xml
+++ b/doc/classes/BakedLightmap.xml
@@ -5,6 +5,7 @@
Baked lightmaps are an alternative workflow for adding indirect (or baked) lighting to a scene. Unlike the [GIProbe] approach, baked lightmaps work fine on low-end PCs and mobile devices as they consume almost no resources in run-time.
+ [b]Note:[/b] Due to how lightmaps work, most properties only have a visible effect once lightmaps are baked again.
https://docs.godotengine.org/en/3.3/tutorials/3d/baked_lightmaps.html
@@ -30,10 +31,14 @@
Maximum size of each lightmap layer, only used when [member atlas_generate] is enabled.
- Raycasting bias used during baking to avoid floating point precission issues.
+ Raycasting bias used during baking to avoid floating point precision issues.
+
+
+ The energy multiplier for each bounce. Higher values will make indirect lighting brighter. A value of [code]1.0[/code] represents physically accurate behavior, but higher values can be used to make indirect lighting propagate more visibly when using a low number of bounces. This can be used to speed up bake times by lowering the number of [member bounces] then increasing [member bounce_indirect_energy]. Unlike [member BakedLightmapData.energy], this property does not affect direct lighting emitted by light nodes, emissive materials and the environment.
+ [b]Note:[/b] [member bounce_indirect_energy] only has an effect if [member bounces] is set to a value greater than or equal to [code]1[/code].
- Number of light bounces that are taken into account during baking.
+ Number of light bounces that are taken into account during baking. See also [member bounce_indirect_energy].
Grid size used for real-time capture information on dynamic objects.
diff --git a/doc/classes/BakedLightmapData.xml b/doc/classes/BakedLightmapData.xml
index ea68fabcfac..3dcbe79be7b 100644
--- a/doc/classes/BakedLightmapData.xml
+++ b/doc/classes/BakedLightmapData.xml
@@ -66,7 +66,8 @@
- Global energy multiplier for baked and dynamic capture objects.
+ Global energy multiplier for baked and dynamic capture objects. This can be changed at run-time without having to bake lightmaps again.
+ To adjust only the energy of indirect lighting (without affecting direct lighting or emissive materials), adjust [member BakedLightmap.bounce_indirect_energy] and bake lightmaps again.
Controls whether dynamic capture objects receive environment lighting or not.
diff --git a/modules/lightmapper_cpu/lightmapper_cpu.cpp b/modules/lightmapper_cpu/lightmapper_cpu.cpp
index 0ff8afdf388..e19c9096ee3 100644
--- a/modules/lightmapper_cpu/lightmapper_cpu.cpp
+++ b/modules/lightmapper_cpu/lightmapper_cpu.cpp
@@ -897,7 +897,7 @@ void LightmapperCPU::_compute_indirect_light(uint32_t p_idx, void *r_lightmap) {
color += throughput * sample.emission;
throughput *= sample.albedo;
- color += throughput * sample.direct_light;
+ color += throughput * sample.direct_light * parameters.bounce_indirect_energy;
// Russian Roulette
// https://computergraphics.stackexchange.com/questions/2316/is-russian-roulette-really-the-answer
@@ -1256,7 +1256,7 @@ void LightmapperCPU::_blit_lightmap(const Vector &p_src, const Vector2i
p_dst->unlock();
}
-LightmapperCPU::BakeError LightmapperCPU::bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, bool p_generate_atlas, int p_max_texture_size, const Ref &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata, BakeStepFunc p_substep_function) {
+LightmapperCPU::BakeError LightmapperCPU::bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bounce_indirect_energy, float p_bias, bool p_generate_atlas, int p_max_texture_size, const Ref &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata, BakeStepFunc p_substep_function) {
if (p_step_function) {
bool cancelled = p_step_function(0.0, TTR("Begin Bake"), p_bake_userdata, true);
if (cancelled) {
@@ -1272,6 +1272,7 @@ LightmapperCPU::BakeError LightmapperCPU::bake(BakeQuality p_quality, bool p_use
parameters.use_denoiser = p_use_denoiser;
parameters.bias = p_bias;
parameters.bounces = p_bounces;
+ parameters.bounce_indirect_energy = p_bounce_indirect_energy;
parameters.environment_transform = p_environment_transform;
parameters.environment_panorama = p_environment_panorama;
diff --git a/modules/lightmapper_cpu/lightmapper_cpu.h b/modules/lightmapper_cpu/lightmapper_cpu.h
index 503a09c1344..7f64b3f8611 100644
--- a/modules/lightmapper_cpu/lightmapper_cpu.h
+++ b/modules/lightmapper_cpu/lightmapper_cpu.h
@@ -82,6 +82,7 @@ class LightmapperCPU : public Lightmapper {
struct BakeParams {
float bias;
int bounces;
+ float bounce_indirect_energy;
int samples;
bool use_denoiser = true;
Ref environment_panorama;
@@ -169,7 +170,7 @@ public:
virtual void add_directional_light(bool p_bake_direct, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_size);
virtual void add_omni_light(bool p_bake_direct, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_size);
virtual void add_spot_light(bool p_bake_direct, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size);
- virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, bool p_generate_atlas, int p_max_texture_size, const Ref &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr, BakeStepFunc p_substep_function = nullptr);
+ virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bounce_energy, float p_bias, bool p_generate_atlas, int p_max_texture_size, const Ref &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr, BakeStepFunc p_substep_function = nullptr);
int get_bake_texture_count() const;
Ref get_bake_texture(int p_index) const;
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 23584ec501a..e1f631c4be6 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -815,7 +815,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa
bool gen_atlas = OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2 ? false : generate_atlas;
- Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, gen_atlas, max_atlas_size, environment_image, environment_xform, _lightmap_bake_step_function, &bsud, bake_substep_function);
+ Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bounce_indirect_energy, bias, gen_atlas, max_atlas_size, environment_image, environment_xform, _lightmap_bake_step_function, &bsud, bake_substep_function);
if (bake_err != Lightmapper::BAKE_OK) {
switch (bake_err) {
@@ -1412,6 +1412,15 @@ int BakedLightmap::get_bounces() const {
return bounces;
}
+void BakedLightmap::set_bounce_indirect_energy(float p_indirect_energy) {
+ ERR_FAIL_COND(p_indirect_energy < 0.0);
+ bounce_indirect_energy = p_indirect_energy;
+}
+
+float BakedLightmap::get_bounce_indirect_energy() const {
+ return bounce_indirect_energy;
+}
+
void BakedLightmap::set_bias(float p_bias) {
ERR_FAIL_COND(p_bias < 0.00001f);
bias = p_bias;
@@ -1460,6 +1469,9 @@ void BakedLightmap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bounces", "bounces"), &BakedLightmap::set_bounces);
ClassDB::bind_method(D_METHOD("get_bounces"), &BakedLightmap::get_bounces);
+ ClassDB::bind_method(D_METHOD("set_bounce_indirect_energy", "bounce_indirect_energy"), &BakedLightmap::set_bounce_indirect_energy);
+ ClassDB::bind_method(D_METHOD("get_bounce_indirect_energy"), &BakedLightmap::get_bounce_indirect_energy);
+
ClassDB::bind_method(D_METHOD("set_bias", "bias"), &BakedLightmap::set_bias);
ClassDB::bind_method(D_METHOD("get_bias"), &BakedLightmap::get_bias);
@@ -1524,6 +1536,7 @@ void BakedLightmap::_bind_methods() {
ADD_GROUP("Tweaks", "");
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::REAL, "bounce_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bounce_indirect_energy", "get_bounce_indirect_energy");
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");
@@ -1583,6 +1596,7 @@ BakedLightmap::BakedLightmap() {
capture_propagation = 1;
capture_enabled = true;
bounces = 3;
+ bounce_indirect_energy = 1.0;
image_path = "";
set_disable_scale(true);
capture_cell_size = 0.5;
diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h
index fa4f5c1b5b3..438c7a89d5c 100644
--- a/scene/3d/baked_lightmap.h
+++ b/scene/3d/baked_lightmap.h
@@ -163,6 +163,7 @@ private:
int max_atlas_size;
bool capture_enabled;
int bounces;
+ float bounce_indirect_energy;
bool use_denoiser;
bool use_hdr;
bool use_color;
@@ -266,6 +267,9 @@ public:
void set_bounces(int p_bounces);
int get_bounces() const;
+ void set_bounce_indirect_energy(float p_indirect_energy);
+ float get_bounce_indirect_energy() const;
+
void set_bias(float p_bias);
float get_bias() const;
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index 1ca81ab9765..80b8d1a411b 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -179,7 +179,7 @@ public:
virtual void add_directional_light(bool p_bake_direct, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_size) = 0;
virtual void add_omni_light(bool p_bake_direct, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_size) = 0;
virtual void add_spot_light(bool p_bake_direct, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) = 0;
- virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, bool p_generate_atlas, int p_max_texture_size, const Ref &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr, BakeStepFunc p_substep_function = nullptr) = 0;
+ virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bounce_indirect_energy, float p_bias, bool p_generate_atlas, int p_max_texture_size, const Ref &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr, BakeStepFunc p_substep_function = nullptr) = 0;
virtual int get_bake_texture_count() const = 0;
virtual Ref get_bake_texture(int p_index) const = 0;