diff --git a/doc/classes/LightmapGIData.xml b/doc/classes/LightmapGIData.xml index 09c4383829fb..db6c9e70ca43 100644 --- a/doc/classes/LightmapGIData.xml +++ b/doc/classes/LightmapGIData.xml @@ -54,8 +54,12 @@ - + The lightmap atlas texture generated by the lightmapper. + [i]Deprecated.[/i] The lightmap atlas can now have multiple textures. See [member lightmap_textures]. + + + The lightmap atlas textures generated by the lightmapper. diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index fe1b10a31f35..427a9b0a70b9 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -97,11 +97,16 @@ Array LightmapGIData::_get_user_data() const { return ret; } -void LightmapGIData::_set_light_textures_data(const Array &p_data) { - ERR_FAIL_COND(p_data.is_empty()); +void LightmapGIData::set_lightmap_textures(const TypedArray &p_data) { + light_textures = p_data; + if (p_data.is_empty()) { + light_texture = Ref(); + _reset_lightmap_textures(); + return; + } if (p_data.size() == 1) { - set_light_texture(p_data[0]); + light_texture = p_data[0]; } else { Vector> images; for (int i = 0; i < p_data.size(); i++) { @@ -116,73 +121,13 @@ void LightmapGIData::_set_light_textures_data(const Array &p_data) { combined_texture.instantiate(); combined_texture->create_from_images(images); - set_light_texture(combined_texture); + light_texture = combined_texture; } + _reset_lightmap_textures(); } -Array LightmapGIData::_get_light_textures_data() const { - Array ret; - if (light_texture.is_null() || light_texture->get_layers() == 0) { - return ret; - } - - Vector> images; - for (int i = 0; i < light_texture->get_layers(); i++) { - images.push_back(light_texture->get_layer_data(i)); - } - - int slice_count = images.size(); - int slice_width = images[0]->get_width(); - int slice_height = images[0]->get_height(); - - int slices_per_texture = Image::MAX_HEIGHT / slice_height; - int texture_count = Math::ceil(slice_count / (float)slices_per_texture); - - ret.resize(texture_count); - - String base_name = get_path().get_basename(); - - int last_count = slice_count % slices_per_texture; - for (int i = 0; i < texture_count; i++) { - int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture; - - Ref texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format()); - - for (int j = 0; j < texture_slice_count; j++) { - texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j)); - } - - String texture_path = texture_count > 1 ? base_name + "_" + itos(i) + ".exr" : base_name + ".exr"; - - Ref config; - config.instantiate(); - - if (FileAccess::exists(texture_path + ".import")) { - config->load(texture_path + ".import"); - } - - config->set_value("remap", "importer", "2d_array_texture"); - config->set_value("remap", "type", "CompressedTexture2DArray"); - if (!config->has_section_key("params", "compress/mode")) { - // User may want another compression, so leave it be, but default to VRAM uncompressed. - config->set_value("params", "compress/mode", 3); - } - config->set_value("params", "compress/channel_pack", 1); - config->set_value("params", "mipmaps/generate", false); - config->set_value("params", "slices/horizontal", 1); - config->set_value("params", "slices/vertical", texture_slice_count); - - config->save(texture_path + ".import"); - - Error err = texture_image->save_exr(texture_path, false); - ERR_FAIL_COND_V(err, ret); - ResourceLoader::import(texture_path); - Ref t = ResourceLoader::load(texture_path); //if already loaded, it will be updated on refocus? - ERR_FAIL_COND_V(t.is_null(), ret); - ret[i] = t; - } - - return ret; +TypedArray LightmapGIData::get_lightmap_textures() const { + return light_textures; } RID LightmapGIData::get_rid() const { @@ -193,18 +138,13 @@ void LightmapGIData::clear() { users.clear(); } -void LightmapGIData::set_light_texture(const Ref &p_light_texture) { - light_texture = p_light_texture; +void LightmapGIData::_reset_lightmap_textures() { RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics); } -Ref LightmapGIData::get_light_texture() const { - return light_texture; -} - void LightmapGIData::set_uses_spherical_harmonics(bool p_enable) { uses_spherical_harmonics = p_enable; - RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics); + _reset_lightmap_textures(); } bool LightmapGIData::is_using_spherical_harmonics() const { @@ -282,15 +222,35 @@ Dictionary LightmapGIData::_get_probe_data() const { return d; } +#ifndef DISABLE_DEPRECATED +void LightmapGIData::set_light_texture(const Ref &p_light_texture) { + TypedArray arr; + arr.append(p_light_texture); + set_lightmap_textures(arr); +} + +Ref LightmapGIData::get_light_texture() const { + if (light_textures.is_empty()) { + return Ref(); + } + return light_textures.get(0); +} + +void LightmapGIData::_set_light_textures_data(const Array &p_data) { + set_lightmap_textures(p_data); +} + +Array LightmapGIData::_get_light_textures_data() const { + return Array(light_textures); +} +#endif + void LightmapGIData::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &LightmapGIData::_set_user_data); ClassDB::bind_method(D_METHOD("_get_user_data"), &LightmapGIData::_get_user_data); - ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture); - ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture); - - ClassDB::bind_method(D_METHOD("_set_light_textures_data", "data"), &LightmapGIData::_set_light_textures_data); - ClassDB::bind_method(D_METHOD("_get_light_textures_data"), &LightmapGIData::_get_light_textures_data); + ClassDB::bind_method(D_METHOD("set_lightmap_textures", "light_textures"), &LightmapGIData::set_lightmap_textures); + ClassDB::bind_method(D_METHOD("get_lightmap_textures"), &LightmapGIData::get_lightmap_textures); ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics); ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics); @@ -303,11 +263,21 @@ void LightmapGIData::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &LightmapGIData::_set_probe_data); ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_EDITOR), "set_light_texture", "get_light_texture"); // property usage default but no save - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lightmap_textures", PROPERTY_HINT_ARRAY_TYPE, "TextureLayered", PROPERTY_USAGE_NO_EDITOR), "set_lightmap_textures", "get_lightmap_textures"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data"); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data"); + +#ifndef DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture); + ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture); + + ClassDB::bind_method(D_METHOD("_set_light_textures_data", "data"), &LightmapGIData::_set_light_textures_data); + ClassDB::bind_method(D_METHOD("_get_light_textures_data"), &LightmapGIData::_get_light_textures_data); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_EDITOR), "set_light_texture", "get_light_texture"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data"); +#endif } LightmapGIData::LightmapGIData() { @@ -1091,6 +1061,68 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa return BAKE_ERROR_MESHES_INVALID; } + // POSTBAKE: Save Textures. + + TypedArray textures; + { + Vector> images; + images.resize(lightmapper->get_bake_texture_count()); + for (int i = 0; i < images.size(); i++) { + images.set(i, lightmapper->get_bake_texture(i)); + } + + int slice_count = images.size(); + int slice_width = images[0]->get_width(); + int slice_height = images[0]->get_height(); + + int slices_per_texture = Image::MAX_HEIGHT / slice_height; + int texture_count = Math::ceil(slice_count / (float)slices_per_texture); + + textures.resize(texture_count); + + String base_path = p_image_data_path.get_basename(); + + int last_count = slice_count % slices_per_texture; + for (int i = 0; i < texture_count; i++) { + int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture; + + Ref texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format()); + + for (int j = 0; j < texture_slice_count; j++) { + texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j)); + } + + String texture_path = texture_count > 1 ? base_path + "_" + itos(i) + ".exr" : base_path + ".exr"; + + Ref config; + config.instantiate(); + + if (FileAccess::exists(texture_path + ".import")) { + config->load(texture_path + ".import"); + } + + config->set_value("remap", "importer", "2d_array_texture"); + config->set_value("remap", "type", "CompressedTexture2DArray"); + if (!config->has_section_key("params", "compress/mode")) { + // User may want another compression, so leave it be, but default to VRAM uncompressed. + config->set_value("params", "compress/mode", 3); + } + config->set_value("params", "compress/channel_pack", 1); + config->set_value("params", "mipmaps/generate", false); + config->set_value("params", "slices/horizontal", 1); + config->set_value("params", "slices/vertical", texture_slice_count); + + config->save(texture_path + ".import"); + + Error err = texture_image->save_exr(texture_path, false); + ERR_FAIL_COND_V(err, BAKE_ERROR_CANT_CREATE_IMAGE); + ResourceLoader::import(texture_path); + Ref t = ResourceLoader::load(texture_path); // If already loaded, it will be updated on refocus? + ERR_FAIL_COND_V(t.is_null(), BAKE_ERROR_CANT_CREATE_IMAGE); + textures[i] = t; + } + } + /* POSTBAKE: Save Light Data */ Ref gi_data; @@ -1102,18 +1134,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa gi_data.instantiate(); } - Ref texture; - { - Vector> images; - for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) { - images.push_back(lightmapper->get_bake_texture(i)); - } - - texture.instantiate(); - texture->create_from_images(images); - } - - gi_data->set_light_texture(texture); + gi_data->set_lightmap_textures(textures); gi_data->set_uses_spherical_harmonics(directional); for (int i = 0; i < lightmapper->get_bake_mesh_count(); i++) { diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index b65d7f8c7881..fec00756930c 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -44,6 +44,7 @@ class LightmapGIData : public Resource { RES_BASE_EXTENSION("lmbake") Ref light_texture; + TypedArray light_textures; bool uses_spherical_harmonics = false; bool interior = false; @@ -65,8 +66,8 @@ class LightmapGIData : public Resource { Array _get_user_data() const; void _set_probe_data(const Dictionary &p_data); Dictionary _get_probe_data() const; - void _set_light_textures_data(const Array &p_data); - Array _get_light_textures_data() const; + + void _reset_lightmap_textures(); protected: static void _bind_methods(); @@ -80,9 +81,14 @@ class LightmapGIData : public Resource { int get_user_lightmap_slice_index(int p_user) const; void clear_users(); +#ifndef DISABLE_DEPRECATED void set_light_texture(const Ref &p_light_texture); Ref get_light_texture() const; + void _set_light_textures_data(const Array &p_data); + Array _get_light_textures_data() const; +#endif + void set_uses_spherical_harmonics(bool p_enable); bool is_using_spherical_harmonics() const; @@ -98,6 +104,9 @@ class LightmapGIData : public Resource { void clear(); + void set_lightmap_textures(const TypedArray &p_data); + TypedArray get_lightmap_textures() const; + virtual RID get_rid() const override; LightmapGIData(); ~LightmapGIData();