summaryrefslogtreecommitdiff
path: root/scene/3d/lightmap_gi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d/lightmap_gi.cpp')
-rw-r--r--scene/3d/lightmap_gi.cpp267
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", "");