From e2c28675efe439a83f650795aba3d2dda6d7c9d6 Mon Sep 17 00:00:00 2001 From: JFonS Date: Thu, 11 Mar 2021 13:34:57 +0100 Subject: [PATCH] Batch of lightmapper fixes and minor improvements - Fix objects with no material being considered as fully transparent by the lightmapper. - Added "environment_min_light" property: gives artistic control over the shadow color. - Fixed "Custom Color" environment mode, it was ignored before. - Added "interior" property to BakedLightmapData: controls whether dynamic capture objects receive environment light or not. - Automatically update dynamic capture objects when the capture data changes (also works for "energy" which used to require object movement to trigger the update). - Added "use_in_baked_light" property to GridMap: controls whether the GridMap will be included in BakedLightmap bakes. - Set "flush zero" and "denormal zero" mode for SSE2 instructions in the Embree raycaster. According to Embree docs it should give a performance improvement. --- doc/classes/BakedLightmap.xml | 4 +- doc/classes/BakedLightmapData.xml | 4 ++ doc/classes/VisualServer.xml | 20 +++++++ drivers/dummy/rasterizer_dummy.h | 2 + drivers/gles2/rasterizer_scene_gles2.cpp | 1 - drivers/gles2/rasterizer_storage_gles2.cpp | 29 ++++++++++ drivers/gles2/rasterizer_storage_gles2.h | 15 ++++- drivers/gles2/shaders/scene.glsl | 7 +-- drivers/gles3/rasterizer_scene_gles3.cpp | 1 - drivers/gles3/rasterizer_storage_gles3.cpp | 28 +++++++++ drivers/gles3/rasterizer_storage_gles3.h | 14 ++++- drivers/gles3/shaders/scene.glsl | 7 +-- modules/gridmap/doc_classes/GridMap.xml | 3 + modules/gridmap/grid_map.cpp | 18 ++++++ modules/gridmap/grid_map.h | 4 ++ modules/raycast/lightmap_raycaster.cpp | 7 +++ scene/3d/baked_lightmap.cpp | 66 ++++++++++++++++------ scene/3d/baked_lightmap.h | 8 +++ servers/visual/rasterizer.h | 2 + servers/visual/visual_server_raster.h | 3 + servers/visual/visual_server_scene.cpp | 10 ++++ servers/visual/visual_server_wrap_mt.h | 2 + servers/visual_server.cpp | 2 + servers/visual_server.h | 2 + 24 files changed, 229 insertions(+), 30 deletions(-) diff --git a/doc/classes/BakedLightmap.xml b/doc/classes/BakedLightmap.xml index e73ad41b262..ba5b99687ca 100644 --- a/doc/classes/BakedLightmap.xml +++ b/doc/classes/BakedLightmap.xml @@ -5,7 +5,6 @@ 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] This node has many known bugs and will be [url=https://godotengine.org/article/godot-40-will-get-new-modernized-lightmapper]rewritten for Godot 4.0[/url]. See [url=https://github.com/godotengine/godot/issues/30929]GitHub issue #30929[/url]. https://docs.godotengine.org/en/3.2/tutorials/3d/baked_lightmaps.html @@ -63,6 +62,9 @@ The rotation of the baked custom sky. + + Minimum ambient light for all the lightmap texels. This doesn't take into account any occlusion from the scene's geometry, it simply ensures a minimum amount of light on all the lightmap texels. Can be used for artistic control on shadow color. + Decides which environment to use during baking. diff --git a/doc/classes/BakedLightmapData.xml b/doc/classes/BakedLightmapData.xml index f602b3f0bc0..6799054e191 100644 --- a/doc/classes/BakedLightmapData.xml +++ b/doc/classes/BakedLightmapData.xml @@ -66,6 +66,10 @@ + Global energy multiplier for baked and dynamic capture objects. + + + Controls whether dynamic capture objects receive environment lighting or not. diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml index 8aae7d98a4b..2f29aebda89 100644 --- a/doc/classes/VisualServer.xml +++ b/doc/classes/VisualServer.xml @@ -2323,6 +2323,15 @@ Returns the cell transform for this lightmap capture's octree. + + + + + + + Returns [code]true[/code] if capture is in "interior" mode. + + @@ -2345,6 +2354,17 @@ Sets the energy multiplier for this lightmap capture. Equivalent to [member BakedLightmapData.energy]. + + + + + + + + + Sets the "interior" mode for this lightmap capture. Equivalent to [member BakedLightmapData.interior]. + + diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index c56354a3c05..04eb47971e7 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -655,6 +655,8 @@ public: int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { return 0; } void lightmap_capture_set_energy(RID p_capture, float p_energy) {} float lightmap_capture_get_energy(RID p_capture) const { return 0.0; } + void lightmap_capture_set_interior(RID p_capture, bool p_interior) {} + bool lightmap_capture_is_interior(RID p_capture) const { return false; } const PoolVector *lightmap_capture_get_octree_ptr(RID p_capture) const { const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); ERR_FAIL_COND_V(!capture, NULL); diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 6e856b9e30e..eba43e1c0ba 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -2598,7 +2598,6 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, if (use_lightmap_capture) { //this is per instance, must be set always if present glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES2::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr()); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_CAPTURE_SKY, false); } _render_geometry(e); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index d296826601f..1cf3a571cc7 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -4521,6 +4521,10 @@ void RasterizerStorageGLES2::lightmap_capture_set_energy(RID p_capture, float p_ LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); ERR_FAIL_COND(!capture); capture->energy = p_energy; + + if (!capture->update_list.in_list()) { + capture_update_list.add(&capture->update_list); + } } float RasterizerStorageGLES2::lightmap_capture_get_energy(RID p_capture) const { @@ -4530,6 +4534,30 @@ float RasterizerStorageGLES2::lightmap_capture_get_energy(RID p_capture) const { return capture->energy; } +void RasterizerStorageGLES2::lightmap_capture_set_interior(RID p_capture, bool p_interior) { + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->interior = p_interior; + + if (!capture->update_list.in_list()) { + capture_update_list.add(&capture->update_list); + } +} + +bool RasterizerStorageGLES2::lightmap_capture_is_interior(RID p_capture) const { + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, false); + return capture->interior; +} + +void RasterizerStorageGLES2::update_dirty_captures() { + while (capture_update_list.first()) { + LightmapCapture *capture = capture_update_list.first()->self(); + capture->instance_change_notify(false, true); + capture_update_list.remove(capture_update_list.first()); + } +} + const PoolVector *RasterizerStorageGLES2::lightmap_capture_get_octree_ptr(RID p_capture) const { const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); ERR_FAIL_COND_V(!capture, NULL); @@ -6361,6 +6389,7 @@ void RasterizerStorageGLES2::update_dirty_resources() { update_dirty_materials(); update_dirty_skeletons(); update_dirty_multimeshes(); + update_dirty_captures(); } RasterizerStorageGLES2::RasterizerStorageGLES2() { diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 3c18715885c..f9d2c503afa 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -1096,12 +1096,22 @@ public: Transform cell_xform; int cell_subdiv; float energy; - LightmapCapture() { + bool interior; + + SelfList update_list; + + LightmapCapture() : + update_list(this) { energy = 1.0; cell_subdiv = 1; + interior = false; } }; + SelfList::List capture_update_list; + + void update_dirty_captures(); + mutable RID_Owner lightmap_capture_data_owner; virtual RID lightmap_capture_create(); @@ -1115,6 +1125,9 @@ public: virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const; virtual void lightmap_capture_set_energy(RID p_capture, float p_energy); virtual float lightmap_capture_get_energy(RID p_capture) const; + virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior); + virtual bool lightmap_capture_is_interior(RID p_capture) const; + virtual const PoolVector *lightmap_capture_get_octree_ptr(RID p_capture) const; /* PARTICLES */ diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index 521d420b168..e4d0620cbab 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -956,8 +956,6 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv) { #ifdef USE_LIGHTMAP_CAPTURE uniform mediump vec4 lightmap_captures[12]; -uniform bool lightmap_capture_sky; - #endif #ifdef USE_RADIANCE_MAP @@ -1781,8 +1779,9 @@ FRAGMENT_SHADER_CODE captured /= sum; - if (lightmap_capture_sky) { - ambient_light = mix(ambient_light, captured.rgb, captured.a); + // Alpha channel is used to indicate if dynamic objects keep the environment lighting + if (lightmap_captures[0].a > 0.5) { + ambient_light += captured.rgb; } else { ambient_light = captured.rgb; } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 01e6631f6e5..dac4c47f805 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1941,7 +1941,6 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform } else if (!e->instance->lightmap_capture_data.empty()) { glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES3::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr()); - state.scene_shader.set_uniform(SceneShaderGLES3::LIGHTMAP_CAPTURE_SKY, false); } else if (e->instance->lightmap.is_valid()) { RasterizerStorageGLES3::Texture *lightmap = storage->texture_owner.getornull(e->instance->lightmap); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 9d852a072e3..fc05532ae2a 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -6385,6 +6385,10 @@ void RasterizerStorageGLES3::lightmap_capture_set_energy(RID p_capture, float p_ LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); ERR_FAIL_COND(!capture); capture->energy = p_energy; + + if (!capture->update_list.in_list()) { + capture_update_list.add(&capture->update_list); + } } float RasterizerStorageGLES3::lightmap_capture_get_energy(RID p_capture) const { @@ -6394,12 +6398,35 @@ float RasterizerStorageGLES3::lightmap_capture_get_energy(RID p_capture) const { return capture->energy; } +void RasterizerStorageGLES3::lightmap_capture_set_interior(RID p_capture, bool p_interior) { + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->interior = p_interior; + if (!capture->update_list.in_list()) { + capture_update_list.add(&capture->update_list); + } +} + +bool RasterizerStorageGLES3::lightmap_capture_is_interior(RID p_capture) const { + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, false); + return capture->interior; +} + const PoolVector *RasterizerStorageGLES3::lightmap_capture_get_octree_ptr(RID p_capture) const { const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); ERR_FAIL_COND_V(!capture, NULL); return &capture->octree; } +void RasterizerStorageGLES3::update_dirty_captures() { + while (capture_update_list.first()) { + LightmapCapture *capture = capture_update_list.first()->self(); + capture->instance_change_notify(false, true); + capture_update_list.remove(capture_update_list.first()); + } +} + /////// RID RasterizerStorageGLES3::particles_create() { @@ -8591,6 +8618,7 @@ void RasterizerStorageGLES3::update_dirty_resources() { update_dirty_shaders(); update_dirty_materials(); update_particles(); + update_dirty_captures(); } RasterizerStorageGLES3::RasterizerStorageGLES3() { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 1101d25ee0c..3e05b028bd1 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -1152,6 +1152,8 @@ public: virtual void lightmap_capture_set_energy(RID p_capture, float p_energy); virtual float lightmap_capture_get_energy(RID p_capture) const; + virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior); + virtual bool lightmap_capture_is_interior(RID p_capture) const; virtual const PoolVector *lightmap_capture_get_octree_ptr(RID p_capture) const; @@ -1162,12 +1164,22 @@ public: Transform cell_xform; int cell_subdiv; float energy; - LightmapCapture() { + bool interior; + + SelfList update_list; + + LightmapCapture() : + update_list(this) { energy = 1.0; cell_subdiv = 1; + interior = false; } }; + SelfList::List capture_update_list; + + void update_dirty_captures(); + mutable RID_Owner lightmap_capture_data_owner; /* PARTICLES */ diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 021cf703152..a1d3b3beeca 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1548,8 +1548,6 @@ vec4 textureArray_bicubic(sampler2DArray tex, vec3 uv) { #ifdef USE_LIGHTMAP_CAPTURE uniform mediump vec4[12] lightmap_captures; -uniform bool lightmap_capture_sky; - #endif #ifdef USE_GI_PROBES @@ -1964,8 +1962,9 @@ FRAGMENT_SHADER_CODE captured /= sum; - if (lightmap_capture_sky) { - ambient_light = mix(ambient_light, captured.rgb, captured.a); + // Alpha channel is used to indicate if dynamic objects keep the environment lighting + if (lightmap_captures[0].a > 0.5) { + ambient_light += captured.rgb; } else { ambient_light = captured.rgb; } diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 8395667d315..3d31406e086 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -230,6 +230,9 @@ The assigned [MeshLibrary]. + + Controls whether this GridMap will be baked in a [BakedLightmap] or not. + diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 5be5671b90f..fa79cfc4a06 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -210,6 +210,14 @@ Ref GridMap::get_mesh_library() const { return mesh_library; } +void GridMap::set_use_in_baked_light(bool p_use_baked_light) { + use_in_baked_light = p_use_baked_light; +} + +bool GridMap::get_use_in_baked_light() const { + return use_in_baked_light; +} + void GridMap::set_cell_size(const Vector3 &p_size) { ERR_FAIL_COND(p_size.x < 0.001 || p_size.y < 0.001 || p_size.z < 0.001); cell_size = p_size; @@ -864,7 +872,11 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_baked_meshes"), &GridMap::clear_baked_meshes); ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1)); + ClassDB::bind_method(D_METHOD("set_use_in_baked_light", "use_in_baked_light"), &GridMap::set_use_in_baked_light); + ClassDB::bind_method(D_METHOD("get_use_in_baked_light"), &GridMap::get_use_in_baked_light); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_use_in_baked_light", "get_use_in_baked_light"); ADD_GROUP("Cell", "cell_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cell_size"), "set_cell_size", "get_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_octant_size", PROPERTY_HINT_RANGE, "1,1024,1"), "set_octant_size", "get_octant_size"); @@ -1066,6 +1078,10 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe Array GridMap::get_bake_meshes() { + if (!use_in_baked_light) { + return Array(); + } + if (!baked_meshes.size()) { make_baked_meshes(true); } @@ -1107,6 +1123,8 @@ GridMap::GridMap() { navigation = NULL; set_notify_transform(true); recreating_octants = false; + + use_in_baked_light = false; } GridMap::~GridMap() { diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index a8acb07b28c..cc2c583c7f0 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -158,6 +158,7 @@ class GridMap : public Spatial { Vector3::Axis clip_axis; Ref mesh_library; + bool use_in_baked_light; Map octant_map; Map cell_map; @@ -230,6 +231,9 @@ public: void set_mesh_library(const Ref &p_mesh_library); Ref get_mesh_library() const; + void set_use_in_baked_light(bool p_use_baked_light); + bool get_use_in_baked_light() const; + void set_cell_size(const Vector3 &p_size); Vector3 get_cell_size() const; diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster.cpp index a8d7ce01869..29334b7cb02 100644 --- a/modules/raycast/lightmap_raycaster.cpp +++ b/modules/raycast/lightmap_raycaster.cpp @@ -33,6 +33,7 @@ // From Embree. #include #include +#include using namespace embree; @@ -185,12 +186,18 @@ void embree_error_handler(void *p_user_data, RTCError p_code, const char *p_str) } LightmapRaycasterEmbree::LightmapRaycasterEmbree() { + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); + embree_device = rtcNewDevice(nullptr); rtcSetDeviceErrorFunction(embree_device, &embree_error_handler, nullptr); embree_scene = rtcNewScene(embree_device); } LightmapRaycasterEmbree::~LightmapRaycasterEmbree() { + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF); + if (embree_scene != nullptr) rtcReleaseScene(embree_scene); if (embree_device != nullptr) diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index b7b7fde2e0a..67c201c3e5d 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -87,6 +87,17 @@ float BakedLightmapData::get_energy() const { return energy; } +void BakedLightmapData::set_interior(bool p_interior) { + + interior = p_interior; + VS::get_singleton()->lightmap_capture_set_interior(baked_light, interior); +} + +bool BakedLightmapData::is_interior() const { + + return interior; +} + void BakedLightmapData::add_user(const NodePath &p_path, const Ref &p_lightmap, int p_lightmap_slice, const Rect2 &p_lightmap_uv_rect, int p_instance) { ERR_FAIL_COND_MSG(p_lightmap.is_null(), "It's not a reference to a valid Texture object."); @@ -230,6 +241,9 @@ void BakedLightmapData::_bind_methods() { ClassDB::bind_method(D_METHOD("set_energy", "energy"), &BakedLightmapData::set_energy); ClassDB::bind_method(D_METHOD("get_energy"), &BakedLightmapData::get_energy); + ClassDB::bind_method(D_METHOD("set_interior", "interior"), &BakedLightmapData::set_interior); + ClassDB::bind_method(D_METHOD("is_interior"), &BakedLightmapData::is_interior); + ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap", "lightmap_slice", "lightmap_uv_rect", "instance"), &BakedLightmapData::add_user); ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count); ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path); @@ -241,6 +255,7 @@ void BakedLightmapData::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "cell_space_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_space_transform", "get_cell_space_transform"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_subdiv", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_subdiv", "get_cell_subdiv"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior"); ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "octree", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_octree", "get_octree"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data"); } @@ -250,6 +265,7 @@ BakedLightmapData::BakedLightmapData() { baked_light = VS::get_singleton()->lightmap_capture_create(); energy = 1; cell_subdiv = 1; + interior = false; } BakedLightmapData::~BakedLightmapData() { @@ -464,7 +480,7 @@ void BakedLightmap::_get_material_images(const MeshesFound &p_found_mesh, Lightm } Ref albedo_texture; - Color albedo_add = Color(0, 0, 0, 0); + Color albedo_add = Color(1, 1, 1, 1); Color albedo_mul = Color(1, 1, 1, 1); Ref emission_texture; @@ -477,6 +493,7 @@ void BakedLightmap::_get_material_images(const MeshesFound &p_found_mesh, Lightm if (albedo_texture.is_valid()) { albedo_mul = mat->get_albedo(); + albedo_add = Color(0, 0, 0, 0); } else { albedo_add = mat->get_albedo(); } @@ -531,25 +548,27 @@ void BakedLightmap::_save_image(String &r_base_path, Ref r_img, bool p_us 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); + 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); - } + c.r = MAX(c.r, environment_min_light.r); + c.g = MAX(c.g, environment_min_light.g); + c.b = MAX(c.b, environment_min_light.b); - if (p_use_srgb) { - c = c.to_srgb(); - } - - r_img->set_pixel(j, i, c); + 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(); } + r_img->unlock(); if (!use_color) { if (use_hdr) { @@ -792,7 +811,6 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa case ENVIRONMENT_MODE_CUSTOM_SKY: { if (environment_custom_sky.is_valid()) { environment_image = _get_irradiance_from_sky(environment_custom_sky, Vector2i(128, 64)); - print_line(vformat("env -> %s", environment_custom_sky_rotation_degrees)); environment_xform.set_euler(environment_custom_sky_rotation_degrees * Math_PI / 180.0); } @@ -804,12 +822,13 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa c.r *= environment_custom_energy; c.g *= environment_custom_energy; c.b *= environment_custom_energy; + environment_image->lock(); for (int i = 0; i < 128; i++) { for (int j = 0; j < 64; j++) { environment_image->set_pixel(i, j, c); } } - + environment_image->unlock(); } break; } } @@ -1409,6 +1428,14 @@ float BakedLightmap::get_environment_custom_energy() const { return environment_custom_energy; } +void BakedLightmap::set_environment_min_light(Color p_min_light) { + environment_min_light = p_min_light; +} + +Color BakedLightmap::get_environment_min_light() const { + return environment_min_light; +} + void BakedLightmap::set_bounces(int p_bounces) { ERR_FAIL_COND(p_bounces < 0 || p_bounces > 16); bounces = p_bounces; @@ -1486,6 +1513,9 @@ void BakedLightmap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_environment_custom_energy", "energy"), &BakedLightmap::set_environment_custom_energy); ClassDB::bind_method(D_METHOD("get_environment_custom_energy"), &BakedLightmap::get_environment_custom_energy); + ClassDB::bind_method(D_METHOD("set_environment_min_light", "min_light"), &BakedLightmap::set_environment_min_light); + ClassDB::bind_method(D_METHOD("get_environment_min_light"), &BakedLightmap::get_environment_min_light); + 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); @@ -1545,6 +1575,7 @@ void BakedLightmap::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "environment_custom_sky_rotation_degrees", PROPERTY_HINT_NONE), "set_environment_custom_sky_rotation_degrees", "get_environment_custom_sky_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "environment_custom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_environment_custom_color", "get_environment_custom_color"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "environment_custom_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_environment_custom_energy", "get_environment_custom_energy"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "environment_min_light", PROPERTY_HINT_COLOR_NO_ALPHA), "set_environment_min_light", "get_environment_min_light"); ADD_GROUP("Capture", "capture_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "capture_enabled"), "set_capture_enabled", "get_capture_enabled"); @@ -1595,6 +1626,7 @@ BakedLightmap::BakedLightmap() { environment_mode = ENVIRONMENT_MODE_DISABLED; environment_custom_color = Color(0.2, 0.7, 1.0); environment_custom_energy = 1.0; + environment_min_light = Color(0.0, 0.0, 0.0); use_denoiser = true; use_hdr = true; diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h index ddafbebfcfd..6f8f0b8f980 100644 --- a/scene/3d/baked_lightmap.h +++ b/scene/3d/baked_lightmap.h @@ -44,6 +44,7 @@ class BakedLightmapData : public Resource { RID baked_light; AABB bounds; float energy; + bool interior; int cell_subdiv; Transform cell_space_xform; @@ -83,6 +84,9 @@ public: void set_energy(float p_energy); float get_energy() const; + void set_interior(bool p_interior); + bool is_interior() const; + void add_user(const NodePath &p_path, const Ref &p_lightmap, int p_lightmap_slice, const Rect2 &p_lightmap_uv_rect, int p_instance); int get_user_count() const; NodePath get_user_path(int p_user) const; @@ -169,6 +173,7 @@ private: Vector3 environment_custom_sky_rotation_degrees; Color environment_custom_color; float environment_custom_energy; + Color environment_min_light; BakeQuality capture_quality; float capture_propagation; @@ -247,6 +252,9 @@ public: void set_environment_custom_energy(float p_energy); float get_environment_custom_energy() const; + void set_environment_min_light(Color p_min_light); + Color get_environment_min_light() const; + void set_use_denoiser(bool p_enable); bool is_using_denoiser() const; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 894b782f5b3..dedb34d9c04 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -514,6 +514,8 @@ public: virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const = 0; virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0; virtual float lightmap_capture_get_energy(RID p_capture) const = 0; + virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior) = 0; + virtual bool lightmap_capture_is_interior(RID p_capture) const = 0; virtual const PoolVector *lightmap_capture_get_octree_ptr(RID p_capture) const = 0; /* PARTICLES */ diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index cf6d6f7d729..549cfd062c1 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -396,6 +396,9 @@ public: BIND2(lightmap_capture_set_energy, RID, float) BIND1RC(float, lightmap_capture_get_energy, RID) + BIND2(lightmap_capture_set_interior, RID, bool) + BIND1RC(bool, lightmap_capture_is_interior, RID) + /* PARTICLES */ BIND0R(RID, particles_create) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index f51070dcd6f..920993b7bea 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1085,6 +1085,13 @@ void VisualServerScene::_update_instance(Instance *p_instance) { VSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform); } + if (p_instance->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE) { + InstanceLightmapCaptureData *capture = static_cast(p_instance->base_data); + for (List::Element *E = capture->geometries.front(); E; E = E->next()) { + _instance_queue_update(E->get().geometry, false, true); + } + } + if (p_instance->aabb.has_no_surface()) { return; } @@ -1441,6 +1448,7 @@ void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance) for (int i = 0; i < 12; i++) new (&p_instance->lightmap_capture_data.ptrw()[i]) Color; + bool interior = true; //this could use some sort of blending.. for (List::Element *E = geom->lightmap_captures.front(); E; E = E->next()) { const PoolVector *octree = VSG::storage->lightmap_capture_get_octree_ptr(E->get()->base); @@ -1456,6 +1464,7 @@ void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance) Vector3 pos = to_cell_xform.xform(p_instance->transform.origin); const float capture_energy = VSG::storage->lightmap_capture_get_energy(E->get()->base); + interior = interior && VSG::storage->lightmap_capture_is_interior(E->get()->base); for (int i = 0; i < 12; i++) { @@ -1467,6 +1476,7 @@ void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance) p_instance->lightmap_capture_data.write[i] += capture; } } + p_instance->lightmap_capture_data.write[0].a = interior ? 0.0f : 1.0f; } bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario) { diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index e4e6dd0da15..872fa71c6c3 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -330,6 +330,8 @@ public: FUNC1RC(int, lightmap_capture_get_octree_cell_subdiv, RID) FUNC2(lightmap_capture_set_energy, RID, float) FUNC1RC(float, lightmap_capture_get_energy, RID) + FUNC2(lightmap_capture_set_interior, RID, bool) + FUNC1RC(bool, lightmap_capture_is_interior, RID) /* PARTICLES */ diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index ead05d1e4b3..9f5dbe5b4ce 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1830,6 +1830,8 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree", "capture"), &VisualServer::lightmap_capture_get_octree); ClassDB::bind_method(D_METHOD("lightmap_capture_set_energy", "capture", "energy"), &VisualServer::lightmap_capture_set_energy); ClassDB::bind_method(D_METHOD("lightmap_capture_get_energy", "capture"), &VisualServer::lightmap_capture_get_energy); + ClassDB::bind_method(D_METHOD("lightmap_capture_set_interior", "capture", "interior"), &VisualServer::lightmap_capture_set_interior); + ClassDB::bind_method(D_METHOD("lightmap_capture_is_interior", "capture"), &VisualServer::lightmap_capture_is_interior); #endif ClassDB::bind_method(D_METHOD("particles_create"), &VisualServer::particles_create); ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &VisualServer::particles_set_emitting); diff --git a/servers/visual_server.h b/servers/visual_server.h index 5d177c5e738..74e5cafaf96 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -558,6 +558,8 @@ public: virtual PoolVector lightmap_capture_get_octree(RID p_capture) const = 0; virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0; virtual float lightmap_capture_get_energy(RID p_capture) const = 0; + virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior) = 0; + virtual bool lightmap_capture_is_interior(RID p_capture) const = 0; /* PARTICLES API */