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;