diff options
Diffstat (limited to 'scene/3d/lightmap_gi.cpp')
-rw-r--r-- | scene/3d/lightmap_gi.cpp | 267 |
1 files changed, 177 insertions, 90 deletions
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 68d2b91fad..555884f445 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -30,10 +30,14 @@ #include "lightmap_gi.h" +#include "core/config/project_settings.h" #include "core/io/config_file.h" #include "core/math/delaunay_3d.h" #include "lightmap_probe.h" #include "scene/3d/mesh_instance_3d.h" +#include "scene/resources/camera_attributes.h" +#include "scene/resources/environment.h" +#include "scene/resources/sky.h" void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) { User user; @@ -73,7 +77,7 @@ void LightmapGIData::clear_users() { } void LightmapGIData::_set_user_data(const Array &p_data) { - ERR_FAIL_COND(p_data.size() <= 0); + ERR_FAIL_COND(p_data.is_empty()); ERR_FAIL_COND((p_data.size() % 4) != 0); for (int i = 0; i < p_data.size(); i += 4) { @@ -92,6 +96,96 @@ 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()); + + if (p_data.size() == 1) { + set_light_texture(p_data[0]); + } else { + Vector<Ref<Image>> images; + for (int i = 0; i < p_data.size(); i++) { + Ref<TextureLayered> texture = p_data[i]; + ERR_FAIL_COND_MSG(texture.is_null(), vformat("Invalid TextureLayered at index %d.", i)); + for (int j = 0; j < texture->get_layers(); j++) { + images.push_back(texture->get_layer_data(j)); + } + } + + Ref<Texture2DArray> combined_texture; + combined_texture.instantiate(); + + combined_texture->create_from_images(images); + set_light_texture(combined_texture); + } +} + +Array LightmapGIData::_get_light_textures_data() const { + Array ret; + if (light_texture.is_null() || light_texture->get_layers() == 0) { + return ret; + } + + Vector<Ref<Image>> 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<Image> texture_image; + texture_image.instantiate(); + + texture_image->create(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<ConfigFile> 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")) { + config->set_value("params", "compress/mode", 2); //user may want another compression, so leave it be + } + 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<TextureLayered> 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; +} + RID LightmapGIData::get_rid() const { return lightmap; } @@ -118,7 +212,7 @@ bool LightmapGIData::is_using_spherical_harmonics() const { return uses_spherical_harmonics; } -void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { +void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree, float p_baked_exposure) { if (p_points.size()) { int pc = p_points.size(); ERR_FAIL_COND(pc * 9 != p_point_sh.size()); @@ -132,6 +226,8 @@ void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, con RS::get_singleton()->lightmap_set_probe_bounds(lightmap, AABB()); RS::get_singleton()->lightmap_set_probe_interior(lightmap, false); } + RS::get_singleton()->lightmap_set_baked_exposure_normalization(lightmap, p_baked_exposure); + baked_exposure = p_baked_exposure; interior = p_interior; bounds = p_bounds; } @@ -160,6 +256,10 @@ bool LightmapGIData::is_interior() const { return interior; } +float LightmapGIData::get_baked_exposure() const { + return baked_exposure; +} + void LightmapGIData::_set_probe_data(const Dictionary &p_data) { ERR_FAIL_COND(!p_data.has("bounds")); ERR_FAIL_COND(!p_data.has("points")); @@ -167,7 +267,8 @@ void LightmapGIData::_set_probe_data(const Dictionary &p_data) { ERR_FAIL_COND(!p_data.has("bsp")); ERR_FAIL_COND(!p_data.has("sh")); ERR_FAIL_COND(!p_data.has("interior")); - set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"]); + ERR_FAIL_COND(!p_data.has("baked_exposure")); + set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"], p_data["baked_exposure"]); } Dictionary LightmapGIData::_get_probe_data() const { @@ -178,6 +279,7 @@ Dictionary LightmapGIData::_get_probe_data() const { d["bsp"] = get_capture_bsp_tree(); d["sh"] = get_capture_sh(); d["interior"] = is_interior(); + d["baked_exposure"] = get_baked_exposure(); return d; } @@ -188,6 +290,9 @@ void LightmapGIData::_bind_methods() { 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_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); @@ -199,7 +304,8 @@ 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"), "set_light_texture", "get_light_texture"); + 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::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"); @@ -318,12 +424,11 @@ void LightmapGI::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &m int LightmapGI::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const LocalVector<BSPSimplex> &p_simplices, const Plane &p_plane, uint32_t p_simplex) const { int over = 0; int under = 0; - int coplanar = 0; const BSPSimplex &s = p_simplices[p_simplex]; for (int i = 0; i < 4; i++) { const Vector3 v = p_points[s.vertices[i]]; - if (p_plane.has_point(v)) { //coplanar - coplanar++; + if (p_plane.has_point(v)) { + // Coplanar. } else if (p_plane.is_point_over(v)) { over++; } else { @@ -573,7 +678,7 @@ void LightmapGI::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cel } } -void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool, Vector3iHash> &positions_used, const AABB &p_bounds) { +void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds) { for (int i = 0; i < 8; i++) { Vector3i pos = p_cell->offset; if (i & 1) { @@ -635,7 +740,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa bsud.to_percent = 0.8; if (p_bake_step) { - p_bake_step(0.0, TTR("Finding meshes, lights and probes"), p_bake_userdata, true); + p_bake_step(0.0, RTR("Finding meshes, lights and probes"), p_bake_userdata, true); } /* STEP 1, FIND MESHES, LIGHTS AND PROBES */ Vector<Lightmapper::MeshData> mesh_data; @@ -655,17 +760,17 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa for (int m_i = 0; m_i < meshes_found.size(); m_i++) { if (p_bake_step) { float p = (float)(m_i) / meshes_found.size(); - p_bake_step(p * 0.1, vformat(TTR("Preparing geometry %d/%d"), m_i, meshes_found.size()), p_bake_userdata, false); + p_bake_step(p * 0.1, vformat(RTR("Preparing geometry %d/%d"), m_i, meshes_found.size()), p_bake_userdata, false); } MeshesFound &mf = meshes_found.write[m_i]; Size2i lightmap_size = mf.mesh->get_lightmap_size_hint() * mf.lightmap_scale; - Vector<RID> overrides; + TypedArray<RID> overrides; overrides.resize(mf.overrides.size()); for (int i = 0; i < mf.overrides.size(); i++) { if (mf.overrides[i].is_valid()) { - overrides.write[i] = mf.overrides[i]->get_rid(); + overrides[i] = mf.overrides[i]->get_rid(); } } TypedArray<Image> images = RS::get_singleton()->bake_render_uv2(mf.mesh->get_rid(), overrides, lightmap_size); @@ -790,7 +895,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa /* STEP 2, CREATE PROBES */ if (p_bake_step) { - p_bake_step(0.3, TTR("Creating probes"), p_bake_userdata, true); + p_bake_step(0.3, RTR("Creating probes"), p_bake_userdata, true); } //bounds need to include the user probes @@ -832,7 +937,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa for (int i = 0; i < mesh_data.size(); i++) { if (p_bake_step) { float p = (float)(i) / mesh_data.size(); - p_bake_step(0.3 + p * 0.1, vformat(TTR("Creating probes from mesh %d/%d"), i, mesh_data.size()), p_bake_userdata, false); + p_bake_step(0.3 + p * 0.1, vformat(RTR("Creating probes from mesh %d/%d"), i, mesh_data.size()), p_bake_userdata, false); } for (int j = 0; j < mesh_data[i].points.size(); j += 3) { @@ -842,7 +947,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } LocalVector<Vector3> new_probe_positions; - HashMap<Vector3i, bool, Vector3iHash> positions_used; + HashMap<Vector3i, bool> positions_used; for (uint32_t i = 0; i < 8; i++) { //insert bounding endpoints Vector3i pos; if (i & 1) { @@ -873,7 +978,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa // Add everything to lightmapper if (p_bake_step) { - p_bake_step(0.4, TTR("Preparing Lightmapper"), p_bake_userdata, true); + p_bake_step(0.4, RTR("Preparing Lightmapper"), p_bake_userdata, true); } { @@ -884,16 +989,22 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa Light3D *light = lights_found[i].light; Transform3D xf = lights_found[i].xform; - Color linear_color = light->get_color().to_linear(); + Color linear_color = light->get_color().srgb_to_linear(); + float energy = light->get_param(Light3D::PARAM_ENERGY); + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + energy *= light->get_param(Light3D::PARAM_INTENSITY); + linear_color *= light->get_correlated_color().srgb_to_linear(); + } + if (Object::cast_to<DirectionalLight3D>(light)) { DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light); - lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_axis(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE)); + lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy, l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } else if (Object::cast_to<OmniLight3D>(light)) { OmniLight3D *l = Object::cast_to<OmniLight3D>(light); - lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE)); + lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, energy * (1.0 / (Math_PI * 4.0)), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } else if (Object::cast_to<SpotLight3D>(light)) { SpotLight3D *l = Object::cast_to<SpotLight3D>(light); - lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_axis(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE)); + lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy * (1.0 / Math_PI), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } } for (int i = 0; i < probes_found.size(); i++) { @@ -907,7 +1018,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa // Add everything to lightmapper if (environment_mode != ENVIRONMENT_MODE_DISABLED) { if (p_bake_step) { - p_bake_step(4.1, TTR("Preparing Environment"), p_bake_userdata, true); + p_bake_step(4.1, RTR("Preparing Environment"), p_bake_userdata, true); } environment_transform = get_global_transform().basis; @@ -948,57 +1059,15 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } } - Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, max_texture_size, directional, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud); - - if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES) { - return BAKE_ERROR_MESHES_INVALID; + float exposure_normalization = 1.0; + if (camera_attributes.is_valid()) { + exposure_normalization = camera_attributes->calculate_exposure_normalization() * camera_attributes->get_exposure_multiplier(); } - /* POSTBAKE: Save Textures */ - - Ref<TextureLayered> texture; - { - Vector<Ref<Image>> images; - for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) { - images.push_back(lightmapper->get_bake_texture(i)); - } - //we assume they are all the same, so let's create a large one for saving - Ref<Image> large_image; - large_image.instantiate(); - - large_image->create(images[0]->get_width(), images[0]->get_height() * images.size(), false, images[0]->get_format()); + Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, max_texture_size, directional, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud, exposure_normalization); - for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) { - large_image->blit_rect(images[i], Rect2(0, 0, images[i]->get_width(), images[i]->get_height()), Point2(0, images[i]->get_height() * i)); - } - - String base_path = p_image_data_path.get_basename() + ".exr"; - - Ref<ConfigFile> config; - - config.instantiate(); - if (FileAccess::exists(base_path + ".import")) { - config->load(base_path + ".import"); - } - - config->set_value("remap", "importer", "2d_array_texture"); - config->set_value("remap", "type", "StreamTexture2DArray"); - if (!config->has_section_key("params", "compress/mode")) { - config->set_value("params", "compress/mode", 2); //user may want another compression, so leave it be - } - 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", images.size()); - - config->save(base_path + ".import"); - - Error err = large_image->save_exr(base_path, false); - ERR_FAIL_COND_V(err, BAKE_ERROR_CANT_CREATE_IMAGE); - ResourceLoader::import(base_path); - Ref<Texture> t = ResourceLoader::load(base_path); //if already loaded, it will be updated on refocus? - ERR_FAIL_COND_V(t.is_null(), BAKE_ERROR_CANT_CREATE_IMAGE); - texture = t; + if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES) { + return BAKE_ERROR_MESHES_INVALID; } /* POSTBAKE: Save Light Data */ @@ -1012,6 +1081,17 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa data.instantiate(); } + Ref<Texture2DArray> texture; + { + Vector<Ref<Image>> 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); + } + data->set_light_texture(texture); data->set_uses_spherical_harmonics(directional); @@ -1046,7 +1126,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa //Obtain solved simplices if (p_bake_step) { - p_bake_step(0.8, TTR("Generating Probe Volumes"), p_bake_userdata, true); + p_bake_step(0.8, RTR("Generating Probe Volumes"), p_bake_userdata, true); } Vector<Delaunay3D::OutputSimplex> solved_simplices = Delaunay3D::tetrahedralize(points); @@ -1101,7 +1181,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa //#define DEBUG_SIMPLICES_AS_OBJ_FILE #ifdef DEBUG_SIMPLICES_AS_OBJ_FILE { - FileAccessRef f = FileAccess::open("res://bsp.obj", FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open("res://bsp.obj", FileAccess::WRITE); for (uint32_t i = 0; i < bsp_simplices.size(); i++) { f->store_line("o Simplex" + itos(i)); for (int j = 0; j < 4; j++) { @@ -1118,7 +1198,6 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa f->store_line(vformat("f %d %d %d", 4 * i + face_order[j][0], 4 * i + face_order[j][1], 4 * i + face_order[j][2])); } } - f->close(); } #endif @@ -1130,7 +1209,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } if (p_bake_step) { - p_bake_step(0.9, TTR("Generating Probe Acceleration Structures"), p_bake_userdata, true); + p_bake_step(0.9, RTR("Generating Probe Acceleration Structures"), p_bake_userdata, true); } _compute_bsp_tree(points, bsp_planes, planes_tested, bsp_simplices, bsp_simplex_indices, bsp_nodes); @@ -1150,7 +1229,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } //#define DEBUG_BSP_TREE #ifdef DEBUG_BSP_TREE - FileAccessRef f = FileAccess::open("res://bsp.txt", FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open("res://bsp.txt", FileAccess::WRITE); for (uint32_t i = 0; i < bsp_nodes.size(); i++) { f->store_line(itos(i) + " - plane: " + bsp_nodes[i].plane + " over: " + itos(bsp_nodes[i].over) + " under: " + itos(bsp_nodes[i].under)); } @@ -1159,12 +1238,12 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa /* Obtain the colors from the images, they will be re-created as cubemaps on the server, depending on the driver */ - data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array); + data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array, exposure_normalization); /* Compute a BSP tree of the simplices, so it's easy to find the exact one */ } - Error err = ResourceSaver::save(p_image_data_path, data); data->set_path(p_image_data_path); + Error err = ResourceSaver::save(data); if (err != OK) { return BAKE_ERROR_CANT_CREATE_IMAGE; @@ -1263,10 +1342,6 @@ AABB LightmapGI::get_aabb() const { return AABB(); } -Vector<Face3> LightmapGI::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - void LightmapGI::set_use_denoiser(bool p_enable) { use_denoiser = p_enable; } @@ -1343,7 +1418,8 @@ float LightmapGI::get_bias() const { } void LightmapGI::set_max_texture_size(int p_size) { - ERR_FAIL_COND(p_size < 2048); + ERR_FAIL_COND_MSG(p_size < 2048, vformat("The LightmapGI maximum texture size supplied (%d) is too small. The minimum allowed value is 2048.", p_size)); + ERR_FAIL_COND_MSG(p_size > 16384, vformat("The LightmapGI maximum texture size supplied (%d) is too large. The maximum allowed value is 16384.", p_size)); max_texture_size = p_size; } @@ -1359,17 +1435,24 @@ LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const { return gen_probes; } -void LightmapGI::_validate_property(PropertyInfo &property) const { - if (property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { - property.usage = PROPERTY_USAGE_NONE; +void LightmapGI::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) { + camera_attributes = p_camera_attributes; +} + +Ref<CameraAttributes> LightmapGI::get_camera_attributes() const { + return camera_attributes; +} + +void LightmapGI::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { + p_property.usage = PROPERTY_USAGE_NONE; } - VisualInstance3D::_validate_property(property); } void LightmapGI::_bind_methods() { @@ -1412,6 +1495,9 @@ void LightmapGI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_directional", "directional"), &LightmapGI::set_directional); ClassDB::bind_method(D_METHOD("is_directional"), &LightmapGI::is_directional); + ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &LightmapGI::set_camera_attributes); + ClassDB::bind_method(D_METHOD("get_camera_attributes"), &LightmapGI::get_camera_attributes); + // ClassDB::bind_method(D_METHOD("bake", "from_node"), &LightmapGI::bake, DEFVAL(Variant())); ADD_GROUP("Tweaks", ""); @@ -1421,12 +1507,13 @@ void LightmapGI::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_denoiser"), "set_use_denoiser", "is_using_denoiser"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.00001,0.1,0.00001,or_greater"), "set_bias", "get_bias"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "max_texture_size"), "set_max_texture_size", "get_max_texture_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_texture_size", PROPERTY_HINT_RANGE, "2048,16384,1"), "set_max_texture_size", "get_max_texture_size"); ADD_GROUP("Environment", "environment_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "environment_mode", PROPERTY_HINT_ENUM, "Disabled,Scene,Custom Sky,Custom Color"), "set_environment_mode", "get_environment_mode"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment_custom_sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_environment_custom_sky", "get_environment_custom_sky"); 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::FLOAT, "environment_custom_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_environment_custom_energy", "get_environment_custom_energy"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes"); ADD_GROUP("Gen Probes", "generate_probes_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "generate_probes_subdiv", PROPERTY_HINT_ENUM, "Disabled,4,8,16,32"), "set_generate_probes", "get_generate_probes"); ADD_GROUP("Data", ""); |