1/**************************************************************************/
2/* lightmap_gi.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "lightmap_gi.h"
32
33#include "core/config/project_settings.h"
34#include "core/io/config_file.h"
35#include "core/math/delaunay_3d.h"
36#include "lightmap_probe.h"
37#include "scene/3d/mesh_instance_3d.h"
38#include "scene/resources/camera_attributes.h"
39#include "scene/resources/environment.h"
40#include "scene/resources/image_texture.h"
41#include "scene/resources/sky.h"
42
43void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) {
44 User user;
45 user.path = p_path;
46 user.uv_scale = p_uv_scale;
47 user.slice_index = p_slice_index;
48 user.sub_instance = p_sub_instance;
49 users.push_back(user);
50}
51
52int LightmapGIData::get_user_count() const {
53 return users.size();
54}
55
56NodePath LightmapGIData::get_user_path(int p_user) const {
57 ERR_FAIL_INDEX_V(p_user, users.size(), NodePath());
58 return users[p_user].path;
59}
60
61int32_t LightmapGIData::get_user_sub_instance(int p_user) const {
62 ERR_FAIL_INDEX_V(p_user, users.size(), -1);
63 return users[p_user].sub_instance;
64}
65
66Rect2 LightmapGIData::get_user_lightmap_uv_scale(int p_user) const {
67 ERR_FAIL_INDEX_V(p_user, users.size(), Rect2());
68 return users[p_user].uv_scale;
69}
70
71int LightmapGIData::get_user_lightmap_slice_index(int p_user) const {
72 ERR_FAIL_INDEX_V(p_user, users.size(), -1);
73 return users[p_user].slice_index;
74}
75
76void LightmapGIData::clear_users() {
77 users.clear();
78}
79
80void LightmapGIData::_set_user_data(const Array &p_data) {
81 ERR_FAIL_COND(p_data.is_empty());
82 ERR_FAIL_COND((p_data.size() % 4) != 0);
83
84 for (int i = 0; i < p_data.size(); i += 4) {
85 add_user(p_data[i + 0], p_data[i + 1], p_data[i + 2], p_data[i + 3]);
86 }
87}
88
89Array LightmapGIData::_get_user_data() const {
90 Array ret;
91 for (int i = 0; i < users.size(); i++) {
92 ret.push_back(users[i].path);
93 ret.push_back(users[i].uv_scale);
94 ret.push_back(users[i].slice_index);
95 ret.push_back(users[i].sub_instance);
96 }
97 return ret;
98}
99
100void LightmapGIData::_set_light_textures_data(const Array &p_data) {
101 ERR_FAIL_COND(p_data.is_empty());
102
103 if (p_data.size() == 1) {
104 set_light_texture(p_data[0]);
105 } else {
106 Vector<Ref<Image>> images;
107 for (int i = 0; i < p_data.size(); i++) {
108 Ref<TextureLayered> texture = p_data[i];
109 ERR_FAIL_COND_MSG(texture.is_null(), vformat("Invalid TextureLayered at index %d.", i));
110 for (int j = 0; j < texture->get_layers(); j++) {
111 images.push_back(texture->get_layer_data(j));
112 }
113 }
114
115 Ref<Texture2DArray> combined_texture;
116 combined_texture.instantiate();
117
118 combined_texture->create_from_images(images);
119 set_light_texture(combined_texture);
120 }
121}
122
123Array LightmapGIData::_get_light_textures_data() const {
124 Array ret;
125 if (light_texture.is_null() || light_texture->get_layers() == 0) {
126 return ret;
127 }
128
129 Vector<Ref<Image>> images;
130 for (int i = 0; i < light_texture->get_layers(); i++) {
131 images.push_back(light_texture->get_layer_data(i));
132 }
133
134 int slice_count = images.size();
135 int slice_width = images[0]->get_width();
136 int slice_height = images[0]->get_height();
137
138 int slices_per_texture = Image::MAX_HEIGHT / slice_height;
139 int texture_count = Math::ceil(slice_count / (float)slices_per_texture);
140
141 ret.resize(texture_count);
142
143 String base_name = get_path().get_basename();
144
145 int last_count = slice_count % slices_per_texture;
146 for (int i = 0; i < texture_count; i++) {
147 int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture;
148
149 Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
150
151 for (int j = 0; j < texture_slice_count; j++) {
152 texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j));
153 }
154
155 String texture_path = texture_count > 1 ? base_name + "_" + itos(i) + ".exr" : base_name + ".exr";
156
157 Ref<ConfigFile> config;
158 config.instantiate();
159
160 if (FileAccess::exists(texture_path + ".import")) {
161 config->load(texture_path + ".import");
162 }
163
164 config->set_value("remap", "importer", "2d_array_texture");
165 config->set_value("remap", "type", "CompressedTexture2DArray");
166 if (!config->has_section_key("params", "compress/mode")) {
167 // User may want another compression, so leave it be, but default to VRAM uncompressed.
168 config->set_value("params", "compress/mode", 3);
169 }
170 config->set_value("params", "compress/channel_pack", 1);
171 config->set_value("params", "mipmaps/generate", false);
172 config->set_value("params", "slices/horizontal", 1);
173 config->set_value("params", "slices/vertical", texture_slice_count);
174
175 config->save(texture_path + ".import");
176
177 Error err = texture_image->save_exr(texture_path, false);
178 ERR_FAIL_COND_V(err, ret);
179 ResourceLoader::import(texture_path);
180 Ref<TextureLayered> t = ResourceLoader::load(texture_path); //if already loaded, it will be updated on refocus?
181 ERR_FAIL_COND_V(t.is_null(), ret);
182 ret[i] = t;
183 }
184
185 return ret;
186}
187
188RID LightmapGIData::get_rid() const {
189 return lightmap;
190}
191
192void LightmapGIData::clear() {
193 users.clear();
194}
195
196void LightmapGIData::set_light_texture(const Ref<TextureLayered> &p_light_texture) {
197 light_texture = p_light_texture;
198 RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics);
199}
200
201Ref<TextureLayered> LightmapGIData::get_light_texture() const {
202 return light_texture;
203}
204
205void LightmapGIData::set_uses_spherical_harmonics(bool p_enable) {
206 uses_spherical_harmonics = p_enable;
207 RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics);
208}
209
210bool LightmapGIData::is_using_spherical_harmonics() const {
211 return uses_spherical_harmonics;
212}
213
214void 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) {
215 if (p_points.size()) {
216 int pc = p_points.size();
217 ERR_FAIL_COND(pc * 9 != p_point_sh.size());
218 ERR_FAIL_COND((p_tetrahedra.size() % 4) != 0);
219 ERR_FAIL_COND((p_bsp_tree.size() % 6) != 0);
220 RS::get_singleton()->lightmap_set_probe_capture_data(lightmap, p_points, p_point_sh, p_tetrahedra, p_bsp_tree);
221 RS::get_singleton()->lightmap_set_probe_bounds(lightmap, p_bounds);
222 RS::get_singleton()->lightmap_set_probe_interior(lightmap, p_interior);
223 } else {
224 RS::get_singleton()->lightmap_set_probe_capture_data(lightmap, PackedVector3Array(), PackedColorArray(), PackedInt32Array(), PackedInt32Array());
225 RS::get_singleton()->lightmap_set_probe_bounds(lightmap, AABB());
226 RS::get_singleton()->lightmap_set_probe_interior(lightmap, false);
227 }
228 RS::get_singleton()->lightmap_set_baked_exposure_normalization(lightmap, p_baked_exposure);
229 baked_exposure = p_baked_exposure;
230 interior = p_interior;
231 bounds = p_bounds;
232}
233
234PackedVector3Array LightmapGIData::get_capture_points() const {
235 return RS::get_singleton()->lightmap_get_probe_capture_points(lightmap);
236}
237
238PackedColorArray LightmapGIData::get_capture_sh() const {
239 return RS::get_singleton()->lightmap_get_probe_capture_sh(lightmap);
240}
241
242PackedInt32Array LightmapGIData::get_capture_tetrahedra() const {
243 return RS::get_singleton()->lightmap_get_probe_capture_tetrahedra(lightmap);
244}
245
246PackedInt32Array LightmapGIData::get_capture_bsp_tree() const {
247 return RS::get_singleton()->lightmap_get_probe_capture_bsp_tree(lightmap);
248}
249
250AABB LightmapGIData::get_capture_bounds() const {
251 return bounds;
252}
253
254bool LightmapGIData::is_interior() const {
255 return interior;
256}
257
258float LightmapGIData::get_baked_exposure() const {
259 return baked_exposure;
260}
261
262void LightmapGIData::_set_probe_data(const Dictionary &p_data) {
263 ERR_FAIL_COND(!p_data.has("bounds"));
264 ERR_FAIL_COND(!p_data.has("points"));
265 ERR_FAIL_COND(!p_data.has("tetrahedra"));
266 ERR_FAIL_COND(!p_data.has("bsp"));
267 ERR_FAIL_COND(!p_data.has("sh"));
268 ERR_FAIL_COND(!p_data.has("interior"));
269 ERR_FAIL_COND(!p_data.has("baked_exposure"));
270 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"]);
271}
272
273Dictionary LightmapGIData::_get_probe_data() const {
274 Dictionary d;
275 d["bounds"] = get_capture_bounds();
276 d["points"] = get_capture_points();
277 d["tetrahedra"] = get_capture_tetrahedra();
278 d["bsp"] = get_capture_bsp_tree();
279 d["sh"] = get_capture_sh();
280 d["interior"] = is_interior();
281 d["baked_exposure"] = get_baked_exposure();
282 return d;
283}
284
285void LightmapGIData::_bind_methods() {
286 ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &LightmapGIData::_set_user_data);
287 ClassDB::bind_method(D_METHOD("_get_user_data"), &LightmapGIData::_get_user_data);
288
289 ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture);
290 ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture);
291
292 ClassDB::bind_method(D_METHOD("_set_light_textures_data", "data"), &LightmapGIData::_set_light_textures_data);
293 ClassDB::bind_method(D_METHOD("_get_light_textures_data"), &LightmapGIData::_get_light_textures_data);
294
295 ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics);
296 ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics);
297
298 ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &LightmapGIData::add_user);
299 ClassDB::bind_method(D_METHOD("get_user_count"), &LightmapGIData::get_user_count);
300 ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &LightmapGIData::get_user_path);
301 ClassDB::bind_method(D_METHOD("clear_users"), &LightmapGIData::clear_users);
302
303 ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &LightmapGIData::_set_probe_data);
304 ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data);
305
306 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
307 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");
308 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");
309 ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data");
310 ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data");
311}
312
313LightmapGIData::LightmapGIData() {
314 lightmap = RS::get_singleton()->lightmap_create();
315}
316
317LightmapGIData::~LightmapGIData() {
318 ERR_FAIL_NULL(RenderingServer::get_singleton());
319 RS::get_singleton()->free(lightmap);
320}
321
322///////////////////////////
323
324void LightmapGI::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &meshes, Vector<LightsFound> &lights, Vector<Vector3> &probes) {
325 MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
326 if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_STATIC && mi->is_visible_in_tree()) {
327 Ref<Mesh> mesh = mi->get_mesh();
328 if (mesh.is_valid()) {
329 bool all_have_uv2_and_normal = true;
330 bool surfaces_found = false;
331 for (int i = 0; i < mesh->get_surface_count(); i++) {
332 if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
333 continue;
334 }
335 if (!(mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_TEX_UV2)) {
336 all_have_uv2_and_normal = false;
337 break;
338 }
339 if (!(mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_NORMAL)) {
340 all_have_uv2_and_normal = false;
341 break;
342 }
343 surfaces_found = true;
344 }
345
346 if (surfaces_found && all_have_uv2_and_normal) {
347 //READY TO BAKE! size hint could be computed if not found, actually..
348
349 MeshesFound mf;
350 mf.xform = get_global_transform().affine_inverse() * mi->get_global_transform();
351 mf.node_path = get_path_to(mi);
352 mf.subindex = -1;
353 mf.mesh = mesh;
354
355 static const int lightmap_scale[GeometryInstance3D::LIGHTMAP_SCALE_MAX] = { 1, 2, 4, 8 };
356 mf.lightmap_scale = lightmap_scale[mi->get_lightmap_scale()];
357
358 Ref<Material> all_override = mi->get_material_override();
359 for (int i = 0; i < mesh->get_surface_count(); i++) {
360 if (all_override.is_valid()) {
361 mf.overrides.push_back(all_override);
362 } else {
363 mf.overrides.push_back(mi->get_surface_override_material(i));
364 }
365 }
366
367 meshes.push_back(mf);
368 }
369 }
370 }
371
372 Node3D *s = Object::cast_to<Node3D>(p_at_node);
373
374 if (!mi && s) {
375 Array bmeshes = p_at_node->call("get_bake_bmeshes");
376 if (bmeshes.size() && (bmeshes.size() & 1) == 0) {
377 Transform3D xf = get_global_transform().affine_inverse() * s->get_global_transform();
378 for (int i = 0; i < bmeshes.size(); i += 2) {
379 Ref<Mesh> mesh = bmeshes[i];
380 if (!mesh.is_valid()) {
381 continue;
382 }
383
384 MeshesFound mf;
385
386 Transform3D mesh_xf = bmeshes[i + 1];
387 mf.xform = xf * mesh_xf;
388 mf.node_path = get_path_to(s);
389 mf.subindex = i / 2;
390 mf.lightmap_scale = 1;
391 mf.mesh = mesh;
392
393 meshes.push_back(mf);
394 }
395 }
396 }
397
398 Light3D *light = Object::cast_to<Light3D>(p_at_node);
399
400 if (light && light->get_bake_mode() != Light3D::BAKE_DISABLED) {
401 LightsFound lf;
402 lf.xform = get_global_transform().affine_inverse() * light->get_global_transform();
403 lf.light = light;
404 lights.push_back(lf);
405 }
406
407 LightmapProbe *probe = Object::cast_to<LightmapProbe>(p_at_node);
408
409 if (probe) {
410 Transform3D xf = get_global_transform().affine_inverse() * probe->get_global_transform();
411 probes.push_back(xf.origin);
412 }
413
414 for (int i = 0; i < p_at_node->get_child_count(); i++) {
415 Node *child = p_at_node->get_child(i);
416 if (!child->get_owner()) {
417 continue; //maybe a helper
418 }
419
420 _find_meshes_and_lights(child, meshes, lights, probes);
421 }
422}
423
424int LightmapGI::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const LocalVector<BSPSimplex> &p_simplices, const Plane &p_plane, uint32_t p_simplex) const {
425 int over = 0;
426 int under = 0;
427 const BSPSimplex &s = p_simplices[p_simplex];
428 for (int i = 0; i < 4; i++) {
429 const Vector3 v = p_points[s.vertices[i]];
430 if (p_plane.has_point(v)) {
431 // Coplanar.
432 } else if (p_plane.is_point_over(v)) {
433 over++;
434 } else {
435 under++;
436 }
437 }
438
439 ERR_FAIL_COND_V(under == 0 && over == 0, -2); //should never happen, we discarded flat simplices before, but in any case drop it from the bsp tree and throw an error
440 if (under == 0) {
441 return 1; // all over
442 } else if (over == 0) {
443 return -1; // all under
444 } else {
445 return 0; // crossing
446 }
447}
448
449//#define DEBUG_BSP
450
451int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const LocalVector<Plane> &p_planes, LocalVector<int32_t> &planes_tested, const LocalVector<BSPSimplex> &p_simplices, const LocalVector<int32_t> &p_simplex_indices, LocalVector<BSPNode> &bsp_nodes) {
452 //if we reach here, it means there is more than one simplex
453 int32_t node_index = (int32_t)bsp_nodes.size();
454 bsp_nodes.push_back(BSPNode());
455
456 //test with all the simplex planes
457 Plane best_plane;
458 float best_plane_score = -1.0;
459
460 for (const int idx : p_simplex_indices) {
461 const BSPSimplex &s = p_simplices[idx];
462 for (int j = 0; j < 4; j++) {
463 uint32_t plane_index = s.planes[j];
464 if (planes_tested[plane_index] == node_index) {
465 continue; //tested this plane already
466 }
467
468 planes_tested[plane_index] = node_index;
469
470 static const int face_order[4][3] = {
471 { 0, 1, 2 },
472 { 0, 2, 3 },
473 { 0, 1, 3 },
474 { 1, 2, 3 }
475 };
476
477 // despite getting rid of plane duplicates, we should still use here the actual plane to avoid numerical error
478 // from thinking this same simplex is intersecting rather than on a side
479 Vector3 v0 = p_points[s.vertices[face_order[j][0]]];
480 Vector3 v1 = p_points[s.vertices[face_order[j][1]]];
481 Vector3 v2 = p_points[s.vertices[face_order[j][2]]];
482
483 Plane plane(v0, v1, v2);
484
485 //test with all the simplices
486 int over_count = 0;
487 int under_count = 0;
488
489 for (const int &index : p_simplex_indices) {
490 int side = _bsp_get_simplex_side(p_points, p_simplices, plane, index);
491 if (side == -2) {
492 continue; //this simplex is invalid, skip for now
493 } else if (side < 0) {
494 under_count++;
495 } else if (side > 0) {
496 over_count++;
497 }
498 }
499
500 if (under_count == 0 && over_count == 0) {
501 continue; //most likely precision issue with a flat simplex, do not try this plane
502 }
503
504 if (under_count > over_count) { //make sure under is always less than over, so we can compute the same ratio
505 SWAP(under_count, over_count);
506 }
507
508 float score = 0; //by default, score is 0 (worst)
509 if (over_count > 0) {
510 //give score mainly based on ratio (under / over), this means that this plane is splitting simplices a lot, but its balanced
511 score = float(under_count) / over_count;
512 }
513
514 //adjusting priority over least splits, probably not a great idea
515 //score *= Math::sqrt(float(over_count + under_count) / p_simplex_indices.size()); //also multiply score
516
517 if (score > best_plane_score) {
518 best_plane = plane;
519 best_plane_score = score;
520 }
521 }
522 }
523
524 LocalVector<int32_t> indices_over;
525 LocalVector<int32_t> indices_under;
526
527 //split again, but add to list
528 for (const uint32_t index : p_simplex_indices) {
529 int side = _bsp_get_simplex_side(p_points, p_simplices, best_plane, index);
530
531 if (side == -2) {
532 continue; //simplex sits on the plane, does not make sense to use it
533 }
534 if (side <= 0) {
535 indices_under.push_back(index);
536 }
537
538 if (side >= 0) {
539 indices_over.push_back(index);
540 }
541 }
542
543#ifdef DEBUG_BSP
544 print_line("node " + itos(node_index) + " found plane: " + best_plane + " score:" + rtos(best_plane_score) + " - over " + itos(indices_over.size()) + " under " + itos(indices_under.size()) + " intersecting " + itos(intersecting));
545#endif
546
547 if (best_plane_score < 0.0 || indices_over.size() == p_simplex_indices.size() || indices_under.size() == p_simplex_indices.size()) {
548 ERR_FAIL_COND_V(p_simplex_indices.size() <= 1, 0); //should not happen, this is a bug
549
550 // Failed to separate the tetrahedrons using planes
551 // this means Delaunay broke at some point.
552 // Luckily, because we are using tetrahedrons, we can resort to
553 // less precise but still working ways to generate the separating plane
554 // this will most likely look bad when interpolating, but at least it will not crash.
555 // and the artifact will most likely also be very small, so too difficult to notice.
556
557 //find the longest axis
558
559 WARN_PRINT("Inconsistency found in triangulation while building BSP, probe interpolation quality may degrade a bit.");
560
561 LocalVector<Vector3> centers;
562 AABB bounds_all;
563 for (uint32_t i = 0; i < p_simplex_indices.size(); i++) {
564 AABB bounds;
565 for (uint32_t j = 0; j < 4; j++) {
566 Vector3 p = p_points[p_simplices[p_simplex_indices[i]].vertices[j]];
567 if (j == 0) {
568 bounds.position = p;
569 } else {
570 bounds.expand_to(p);
571 }
572 }
573 if (i == 0) {
574 centers.push_back(bounds.get_center());
575 } else {
576 bounds_all.merge_with(bounds);
577 }
578 }
579 Vector3::Axis longest_axis = Vector3::Axis(bounds_all.get_longest_axis_index());
580
581 //find the simplex that will go under
582 uint32_t min_d_idx = 0xFFFFFFFF;
583 float min_d_dist = 1e20;
584
585 for (uint32_t i = 0; i < centers.size(); i++) {
586 if (centers[i][longest_axis] < min_d_dist) {
587 min_d_idx = i;
588 min_d_dist = centers[i][longest_axis];
589 }
590 }
591 //rebuild best_plane and over/under arrays
592 best_plane = Plane();
593 best_plane.normal[longest_axis] = 1.0;
594 best_plane.d = min_d_dist;
595
596 indices_under.clear();
597 indices_under.push_back(min_d_idx);
598
599 indices_over.clear();
600
601 for (uint32_t i = 0; i < p_simplex_indices.size(); i++) {
602 if (i == min_d_idx) {
603 continue;
604 }
605 indices_over.push_back(p_simplex_indices[i]);
606 }
607 }
608
609 BSPNode node;
610 node.plane = best_plane;
611
612 if (indices_under.size() == 0) {
613 //nothing to do here
614 node.under = BSPNode::EMPTY_LEAF;
615 } else if (indices_under.size() == 1) {
616 node.under = -(indices_under[0] + 1);
617 } else {
618 node.under = _compute_bsp_tree(p_points, p_planes, planes_tested, p_simplices, indices_under, bsp_nodes);
619 }
620
621 if (indices_over.size() == 0) {
622 //nothing to do here
623 node.over = BSPNode::EMPTY_LEAF;
624 } else if (indices_over.size() == 1) {
625 node.over = -(indices_over[0] + 1);
626 } else {
627 node.over = _compute_bsp_tree(p_points, p_planes, planes_tested, p_simplices, indices_over, bsp_nodes);
628 }
629
630 bsp_nodes[node_index] = node;
631
632 return node_index;
633}
634
635bool LightmapGI::_lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh) {
636 BakeStepUD *bsud = (BakeStepUD *)ud;
637 bool ret = false;
638 if (bsud->func) {
639 ret = bsud->func(bsud->from_percent + p_completion * (bsud->to_percent - bsud->from_percent), p_text, bsud->ud, p_refresh);
640 }
641 return ret;
642}
643
644void LightmapGI::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle) {
645 for (int i = 0; i < 8; i++) {
646 Vector3i pos = p_cell->offset;
647 uint32_t half_size = p_cell->size / 2;
648 if (i & 1) {
649 pos.x += half_size;
650 }
651 if (i & 2) {
652 pos.y += half_size;
653 }
654 if (i & 4) {
655 pos.z += half_size;
656 }
657
658 AABB subcell;
659 subcell.position = Vector3(pos) * p_cell_size;
660 subcell.size = Vector3(half_size, half_size, half_size) * p_cell_size;
661
662 if (!Geometry3D::triangle_box_overlap(subcell.get_center(), subcell.size * 0.5, p_triangle)) {
663 continue;
664 }
665
666 if (p_cell->children[i] == nullptr) {
667 GenProbesOctree *child = memnew(GenProbesOctree);
668 child->offset = pos;
669 child->size = half_size;
670 p_cell->children[i] = child;
671 }
672
673 if (half_size > 1) {
674 //still levels missing
675 _plot_triangle_into_octree(p_cell->children[i], p_cell_size, p_triangle);
676 }
677 }
678}
679
680void 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) {
681 for (int i = 0; i < 8; i++) {
682 Vector3i pos = p_cell->offset;
683 if (i & 1) {
684 pos.x += p_cell->size;
685 }
686 if (i & 2) {
687 pos.y += p_cell->size;
688 }
689 if (i & 4) {
690 pos.z += p_cell->size;
691 }
692
693 if (p_cell->size == 1 && !positions_used.has(pos)) {
694 //new position to insert!
695 Vector3 real_pos = p_bounds.position + Vector3(pos) * p_cell_size;
696 //see if a user submitted probe is too close
697 int ppcount = probe_positions.size();
698 const Vector3 *pp = probe_positions.ptr();
699 bool exists = false;
700 for (int j = 0; j < ppcount; j++) {
701 if (pp[j].is_equal_approx(real_pos)) {
702 exists = true;
703 break;
704 }
705 }
706
707 if (!exists) {
708 new_probe_positions.push_back(real_pos);
709 }
710
711 positions_used[pos] = true;
712 }
713
714 if (p_cell->children[i] != nullptr) {
715 _gen_new_positions_from_octree(p_cell->children[i], p_cell_size, probe_positions, new_probe_positions, positions_used, p_bounds);
716 }
717 }
718}
719
720LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_path, Lightmapper::BakeStepFunc p_bake_step, void *p_bake_userdata) {
721 if (p_image_data_path.is_empty()) {
722 if (get_light_data().is_null()) {
723 return BAKE_ERROR_NO_SAVE_PATH;
724 }
725
726 p_image_data_path = get_light_data()->get_path();
727 if (!p_image_data_path.is_resource_file()) {
728 return BAKE_ERROR_NO_SAVE_PATH;
729 }
730 }
731
732 Ref<Lightmapper> lightmapper = Lightmapper::create();
733 ERR_FAIL_COND_V(lightmapper.is_null(), BAKE_ERROR_NO_LIGHTMAPPER);
734
735 BakeStepUD bsud;
736 bsud.func = p_bake_step;
737 bsud.ud = p_bake_userdata;
738 bsud.from_percent = 0.2;
739 bsud.to_percent = 0.8;
740
741 if (p_bake_step) {
742 p_bake_step(0.0, RTR("Finding meshes, lights and probes"), p_bake_userdata, true);
743 }
744 /* STEP 1, FIND MESHES, LIGHTS AND PROBES */
745 Vector<Lightmapper::MeshData> mesh_data;
746 Vector<LightsFound> lights_found;
747 Vector<Vector3> probes_found;
748 AABB bounds;
749 {
750 Vector<MeshesFound> meshes_found;
751 _find_meshes_and_lights(p_from_node ? p_from_node : get_parent(), meshes_found, lights_found, probes_found);
752
753 if (meshes_found.size() == 0) {
754 return BAKE_ERROR_NO_MESHES;
755 }
756 // create mesh data for insert
757
758 //get the base material textures, help compute atlas size and bounds
759 for (int m_i = 0; m_i < meshes_found.size(); m_i++) {
760 if (p_bake_step) {
761 float p = (float)(m_i) / meshes_found.size();
762 p_bake_step(p * 0.1, vformat(RTR("Preparing geometry %d/%d"), m_i, meshes_found.size()), p_bake_userdata, false);
763 }
764
765 MeshesFound &mf = meshes_found.write[m_i];
766
767 Size2i lightmap_size = mf.mesh->get_lightmap_size_hint();
768
769 if (lightmap_size == Size2i(0, 0)) {
770 // TODO we should compute a size if no lightmap hint is set, as we did in 3.x.
771 // For now set to basic size to avoid crash.
772 lightmap_size = Size2i(64, 64);
773 }
774
775 lightmap_size *= mf.lightmap_scale;
776 TypedArray<RID> overrides;
777 overrides.resize(mf.overrides.size());
778 for (int i = 0; i < mf.overrides.size(); i++) {
779 if (mf.overrides[i].is_valid()) {
780 overrides[i] = mf.overrides[i]->get_rid();
781 }
782 }
783 TypedArray<Image> images = RS::get_singleton()->bake_render_uv2(mf.mesh->get_rid(), overrides, lightmap_size);
784
785 ERR_FAIL_COND_V(images.is_empty(), BAKE_ERROR_CANT_CREATE_IMAGE);
786
787 Ref<Image> albedo = images[RS::BAKE_CHANNEL_ALBEDO_ALPHA];
788 Ref<Image> orm = images[RS::BAKE_CHANNEL_ORM];
789
790 //multiply albedo by metal
791
792 Lightmapper::MeshData md;
793
794 {
795 Dictionary d;
796 d["path"] = mf.node_path;
797 if (mf.subindex >= 0) {
798 d["subindex"] = mf.subindex;
799 }
800 md.userdata = d;
801 }
802
803 {
804 if (albedo->get_format() != Image::FORMAT_RGBA8) {
805 albedo->convert(Image::FORMAT_RGBA8);
806 }
807 if (orm->get_format() != Image::FORMAT_RGBA8) {
808 orm->convert(Image::FORMAT_RGBA8);
809 }
810 Vector<uint8_t> albedo_alpha = albedo->get_data();
811 Vector<uint8_t> orm_data = orm->get_data();
812
813 Vector<uint8_t> albedom;
814 uint32_t len = albedo_alpha.size();
815 albedom.resize(len);
816 const uint8_t *r_aa = albedo_alpha.ptr();
817 const uint8_t *r_orm = orm_data.ptr();
818 uint8_t *w_albedo = albedom.ptrw();
819
820 for (uint32_t i = 0; i < len; i += 4) {
821 w_albedo[i + 0] = uint8_t(CLAMP(float(r_aa[i + 0]) * (1.0 - float(r_orm[i + 2] / 255.0)), 0, 255));
822 w_albedo[i + 1] = uint8_t(CLAMP(float(r_aa[i + 1]) * (1.0 - float(r_orm[i + 2] / 255.0)), 0, 255));
823 w_albedo[i + 2] = uint8_t(CLAMP(float(r_aa[i + 2]) * (1.0 - float(r_orm[i + 2] / 255.0)), 0, 255));
824 w_albedo[i + 3] = 255;
825 }
826
827 md.albedo_on_uv2.instantiate();
828 md.albedo_on_uv2->set_data(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom);
829 }
830
831 md.emission_on_uv2 = images[RS::BAKE_CHANNEL_EMISSION];
832 if (md.emission_on_uv2->get_format() != Image::FORMAT_RGBAH) {
833 md.emission_on_uv2->convert(Image::FORMAT_RGBAH);
834 }
835
836 //get geometry
837
838 Basis normal_xform = mf.xform.basis.inverse().transposed();
839
840 for (int i = 0; i < mf.mesh->get_surface_count(); i++) {
841 if (mf.mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
842 continue;
843 }
844 Array a = mf.mesh->surface_get_arrays(i);
845
846 Vector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
847 const Vector3 *vr = vertices.ptr();
848 Vector<Vector2> uv = a[Mesh::ARRAY_TEX_UV2];
849 const Vector2 *uvr = nullptr;
850 Vector<Vector3> normals = a[Mesh::ARRAY_NORMAL];
851 const Vector3 *nr = nullptr;
852 Vector<int> index = a[Mesh::ARRAY_INDEX];
853
854 ERR_CONTINUE(uv.size() == 0);
855 ERR_CONTINUE(normals.size() == 0);
856
857 uvr = uv.ptr();
858 nr = normals.ptr();
859
860 int facecount;
861 const int *ir = nullptr;
862
863 if (index.size()) {
864 facecount = index.size() / 3;
865 ir = index.ptr();
866 } else {
867 facecount = vertices.size() / 3;
868 }
869
870 for (int j = 0; j < facecount; j++) {
871 uint32_t vidx[3];
872
873 if (ir) {
874 for (int k = 0; k < 3; k++) {
875 vidx[k] = ir[j * 3 + k];
876 }
877 } else {
878 for (int k = 0; k < 3; k++) {
879 vidx[k] = j * 3 + k;
880 }
881 }
882
883 for (int k = 0; k < 3; k++) {
884 Vector3 v = mf.xform.xform(vr[vidx[k]]);
885 if (bounds == AABB()) {
886 bounds.position = v;
887 } else {
888 bounds.expand_to(v);
889 }
890 md.points.push_back(v);
891
892 md.uv2.push_back(uvr[vidx[k]]);
893 md.normal.push_back(normal_xform.xform(nr[vidx[k]]).normalized());
894 }
895 }
896 }
897
898 mesh_data.push_back(md);
899 }
900 }
901
902 /* STEP 2, CREATE PROBES */
903
904 if (p_bake_step) {
905 p_bake_step(0.3, RTR("Creating probes"), p_bake_userdata, true);
906 }
907
908 //bounds need to include the user probes
909 for (int i = 0; i < probes_found.size(); i++) {
910 bounds.expand_to(probes_found[i]);
911 }
912
913 bounds.grow_by(bounds.size.length() * 0.001);
914
915 if (gen_probes == GENERATE_PROBES_DISABLED) {
916 // generate 8 probes on bound endpoints
917 for (int i = 0; i < 8; i++) {
918 probes_found.push_back(bounds.get_endpoint(i));
919 }
920 } else {
921 // detect probes from geometry
922 static const int subdiv_values[6] = { 0, 4, 8, 16, 32 };
923 int subdiv = subdiv_values[gen_probes];
924
925 float subdiv_cell_size;
926 Vector3i bound_limit;
927 {
928 int longest_axis = bounds.get_longest_axis_index();
929 subdiv_cell_size = bounds.size[longest_axis] / subdiv;
930 int axis_n1 = (longest_axis + 1) % 3;
931 int axis_n2 = (longest_axis + 2) % 3;
932
933 bound_limit[longest_axis] = subdiv;
934 bound_limit[axis_n1] = int(Math::ceil(bounds.size[axis_n1] / subdiv_cell_size));
935 bound_limit[axis_n2] = int(Math::ceil(bounds.size[axis_n2] / subdiv_cell_size));
936 //compensate bounds
937 bounds.size[axis_n1] = bound_limit[axis_n1] * subdiv_cell_size;
938 bounds.size[axis_n2] = bound_limit[axis_n2] * subdiv_cell_size;
939 }
940
941 GenProbesOctree octree;
942 octree.size = subdiv;
943
944 for (int i = 0; i < mesh_data.size(); i++) {
945 if (p_bake_step) {
946 float p = (float)(i) / mesh_data.size();
947 p_bake_step(0.3 + p * 0.1, vformat(RTR("Creating probes from mesh %d/%d"), i, mesh_data.size()), p_bake_userdata, false);
948 }
949
950 for (int j = 0; j < mesh_data[i].points.size(); j += 3) {
951 Vector3 points[3] = { mesh_data[i].points[j + 0] - bounds.position, mesh_data[i].points[j + 1] - bounds.position, mesh_data[i].points[j + 2] - bounds.position };
952 _plot_triangle_into_octree(&octree, subdiv_cell_size, points);
953 }
954 }
955
956 LocalVector<Vector3> new_probe_positions;
957 HashMap<Vector3i, bool> positions_used;
958 for (uint32_t i = 0; i < 8; i++) { //insert bounding endpoints
959 Vector3i pos;
960 if (i & 1) {
961 pos.x += bound_limit.x;
962 }
963 if (i & 2) {
964 pos.y += bound_limit.y;
965 }
966 if (i & 4) {
967 pos.z += bound_limit.z;
968 }
969
970 positions_used[pos] = true;
971 Vector3 real_pos = bounds.position + Vector3(pos) * subdiv_cell_size; //use same formula for numerical stability
972 new_probe_positions.push_back(real_pos);
973 }
974 //skip first level, since probes are always added at bounds endpoints anyway (code above this)
975 for (int i = 0; i < 8; i++) {
976 if (octree.children[i]) {
977 _gen_new_positions_from_octree(octree.children[i], subdiv_cell_size, probes_found, new_probe_positions, positions_used, bounds);
978 }
979 }
980
981 for (const Vector3 &position : new_probe_positions) {
982 probes_found.push_back(position);
983 }
984 }
985
986 // Add everything to lightmapper
987 if (p_bake_step) {
988 p_bake_step(0.4, RTR("Preparing Lightmapper"), p_bake_userdata, true);
989 }
990
991 {
992 for (int i = 0; i < mesh_data.size(); i++) {
993 lightmapper->add_mesh(mesh_data[i]);
994 }
995 for (int i = 0; i < lights_found.size(); i++) {
996 Light3D *light = lights_found[i].light;
997 Transform3D xf = lights_found[i].xform;
998
999 Color linear_color = light->get_color().srgb_to_linear();
1000 float energy = light->get_param(Light3D::PARAM_ENERGY);
1001 if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
1002 energy *= light->get_param(Light3D::PARAM_INTENSITY);
1003 linear_color *= light->get_correlated_color().srgb_to_linear();
1004 }
1005
1006 if (Object::cast_to<DirectionalLight3D>(light)) {
1007 DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light);
1008 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));
1009 } else if (Object::cast_to<OmniLight3D>(light)) {
1010 OmniLight3D *l = Object::cast_to<OmniLight3D>(light);
1011 if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
1012 energy *= (1.0 / (Math_PI * 4.0));
1013 }
1014 lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, energy, 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));
1015 } else if (Object::cast_to<SpotLight3D>(light)) {
1016 SpotLight3D *l = Object::cast_to<SpotLight3D>(light);
1017 if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
1018 energy *= (1.0 / Math_PI);
1019 }
1020 lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, 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), l->get_param(Light3D::PARAM_SHADOW_BLUR));
1021 }
1022 }
1023 for (int i = 0; i < probes_found.size(); i++) {
1024 lightmapper->add_probe(probes_found[i]);
1025 }
1026 }
1027
1028 Ref<Image> environment_image;
1029 Basis environment_transform;
1030
1031 // Add everything to lightmapper
1032 if (environment_mode != ENVIRONMENT_MODE_DISABLED) {
1033 if (p_bake_step) {
1034 p_bake_step(4.1, RTR("Preparing Environment"), p_bake_userdata, true);
1035 }
1036
1037 environment_transform = get_global_transform().basis;
1038
1039 switch (environment_mode) {
1040 case ENVIRONMENT_MODE_DISABLED: {
1041 //nothing
1042 } break;
1043 case ENVIRONMENT_MODE_SCENE: {
1044 Ref<World3D> world = get_world_3d();
1045 if (world.is_valid()) {
1046 Ref<Environment> env = world->get_environment();
1047 if (env.is_null()) {
1048 env = world->get_fallback_environment();
1049 }
1050
1051 if (env.is_valid()) {
1052 environment_image = RS::get_singleton()->environment_bake_panorama(env->get_rid(), true, Size2i(128, 64));
1053 }
1054 }
1055 } break;
1056 case ENVIRONMENT_MODE_CUSTOM_SKY: {
1057 if (environment_custom_sky.is_valid()) {
1058 environment_image = RS::get_singleton()->sky_bake_panorama(environment_custom_sky->get_rid(), environment_custom_energy, true, Size2i(128, 64));
1059 }
1060
1061 } break;
1062 case ENVIRONMENT_MODE_CUSTOM_COLOR: {
1063 environment_image.instantiate();
1064 environment_image->initialize_data(128, 64, false, Image::FORMAT_RGBAF);
1065 Color c = environment_custom_color;
1066 c.r *= environment_custom_energy;
1067 c.g *= environment_custom_energy;
1068 c.b *= environment_custom_energy;
1069 environment_image->fill(c);
1070
1071 } break;
1072 }
1073 }
1074
1075 float exposure_normalization = 1.0;
1076 if (camera_attributes.is_valid()) {
1077 exposure_normalization = camera_attributes->get_exposure_multiplier();
1078 if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
1079 exposure_normalization = camera_attributes->calculate_exposure_normalization();
1080 }
1081 }
1082
1083 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);
1084
1085 if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_TOO_SMALL) {
1086 return BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL;
1087 } else if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES) {
1088 return BAKE_ERROR_MESHES_INVALID;
1089 }
1090
1091 /* POSTBAKE: Save Light Data */
1092
1093 Ref<LightmapGIData> gi_data;
1094 if (get_light_data().is_valid()) {
1095 gi_data = get_light_data();
1096 set_light_data(Ref<LightmapGIData>()); //clear
1097 gi_data->clear();
1098 } else {
1099 gi_data.instantiate();
1100 }
1101
1102 Ref<Texture2DArray> texture;
1103 {
1104 Vector<Ref<Image>> images;
1105 for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) {
1106 images.push_back(lightmapper->get_bake_texture(i));
1107 }
1108
1109 texture.instantiate();
1110 texture->create_from_images(images);
1111 }
1112
1113 gi_data->set_light_texture(texture);
1114 gi_data->set_uses_spherical_harmonics(directional);
1115
1116 for (int i = 0; i < lightmapper->get_bake_mesh_count(); i++) {
1117 Dictionary d = lightmapper->get_bake_mesh_userdata(i);
1118 NodePath np = d["path"];
1119 int32_t subindex = -1;
1120 if (d.has("subindex")) {
1121 subindex = d["subindex"];
1122 }
1123
1124 Rect2 uv_scale = lightmapper->get_bake_mesh_uv_scale(i);
1125 int slice_index = lightmapper->get_bake_mesh_texture_slice(i);
1126 gi_data->add_user(np, uv_scale, slice_index, subindex);
1127 }
1128
1129 {
1130 // create tetrahedrons
1131 Vector<Vector3> points;
1132 Vector<Color> sh;
1133 points.resize(lightmapper->get_bake_probe_count());
1134 sh.resize(lightmapper->get_bake_probe_count() * 9);
1135 for (int i = 0; i < lightmapper->get_bake_probe_count(); i++) {
1136 points.write[i] = lightmapper->get_bake_probe_point(i);
1137 Vector<Color> colors = lightmapper->get_bake_probe_sh(i);
1138 ERR_CONTINUE(colors.size() != 9);
1139 for (int j = 0; j < 9; j++) {
1140 sh.write[i * 9 + j] = colors[j];
1141 }
1142 }
1143
1144 //Obtain solved simplices
1145
1146 if (p_bake_step) {
1147 p_bake_step(0.8, RTR("Generating Probe Volumes"), p_bake_userdata, true);
1148 }
1149 Vector<Delaunay3D::OutputSimplex> solved_simplices = Delaunay3D::tetrahedralize(points);
1150
1151 LocalVector<BSPSimplex> bsp_simplices;
1152 LocalVector<Plane> bsp_planes;
1153 LocalVector<int32_t> bsp_simplex_indices;
1154 PackedInt32Array tetrahedrons;
1155
1156 for (int i = 0; i < solved_simplices.size(); i++) {
1157 //Prepare a special representation of the simplex, which uses a BSP Tree
1158 BSPSimplex bsp_simplex;
1159 for (int j = 0; j < 4; j++) {
1160 bsp_simplex.vertices[j] = solved_simplices[i].points[j];
1161 }
1162 for (int j = 0; j < 4; j++) {
1163 static const int face_order[4][3] = {
1164 { 0, 1, 2 },
1165 { 0, 2, 3 },
1166 { 0, 1, 3 },
1167 { 1, 2, 3 }
1168 };
1169 Vector3 a = points[solved_simplices[i].points[face_order[j][0]]];
1170 Vector3 b = points[solved_simplices[i].points[face_order[j][1]]];
1171 Vector3 c = points[solved_simplices[i].points[face_order[j][2]]];
1172
1173 //store planes in an array, but ensure they are reused, to speed up processing
1174
1175 Plane p(a, b, c);
1176 int plane_index = -1;
1177 for (uint32_t k = 0; k < bsp_planes.size(); k++) {
1178 if (bsp_planes[k].is_equal_approx_any_side(p)) {
1179 plane_index = k;
1180 break;
1181 }
1182 }
1183
1184 if (plane_index == -1) {
1185 plane_index = bsp_planes.size();
1186 bsp_planes.push_back(p);
1187 }
1188
1189 bsp_simplex.planes[j] = plane_index;
1190
1191 //also fill simplex array
1192 tetrahedrons.push_back(solved_simplices[i].points[j]);
1193 }
1194
1195 bsp_simplex_indices.push_back(bsp_simplices.size());
1196 bsp_simplices.push_back(bsp_simplex);
1197 }
1198
1199//#define DEBUG_SIMPLICES_AS_OBJ_FILE
1200#ifdef DEBUG_SIMPLICES_AS_OBJ_FILE
1201 {
1202 Ref<FileAccess> f = FileAccess::open("res://bsp.obj", FileAccess::WRITE);
1203 for (uint32_t i = 0; i < bsp_simplices.size(); i++) {
1204 f->store_line("o Simplex" + itos(i));
1205 for (int j = 0; j < 4; j++) {
1206 f->store_line(vformat("v %f %f %f", points[bsp_simplices[i].vertices[j]].x, points[bsp_simplices[i].vertices[j]].y, points[bsp_simplices[i].vertices[j]].z));
1207 }
1208 static const int face_order[4][3] = {
1209 { 1, 2, 3 },
1210 { 1, 3, 4 },
1211 { 1, 2, 4 },
1212 { 2, 3, 4 }
1213 };
1214
1215 for (int j = 0; j < 4; j++) {
1216 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]));
1217 }
1218 }
1219 }
1220#endif
1221
1222 LocalVector<BSPNode> bsp_nodes;
1223 LocalVector<int32_t> planes_tested;
1224 planes_tested.resize(bsp_planes.size());
1225 for (int &index : planes_tested) {
1226 index = 0x7FFFFFFF;
1227 }
1228
1229 if (p_bake_step) {
1230 p_bake_step(0.9, RTR("Generating Probe Acceleration Structures"), p_bake_userdata, true);
1231 }
1232
1233 _compute_bsp_tree(points, bsp_planes, planes_tested, bsp_simplices, bsp_simplex_indices, bsp_nodes);
1234
1235 PackedInt32Array bsp_array;
1236 bsp_array.resize(bsp_nodes.size() * 6); // six 32 bits values used for each BSP node
1237 {
1238 float *fptr = (float *)bsp_array.ptrw();
1239 int32_t *iptr = (int32_t *)bsp_array.ptrw();
1240 for (uint32_t i = 0; i < bsp_nodes.size(); i++) {
1241 fptr[i * 6 + 0] = bsp_nodes[i].plane.normal.x;
1242 fptr[i * 6 + 1] = bsp_nodes[i].plane.normal.y;
1243 fptr[i * 6 + 2] = bsp_nodes[i].plane.normal.z;
1244 fptr[i * 6 + 3] = bsp_nodes[i].plane.d;
1245 iptr[i * 6 + 4] = bsp_nodes[i].over;
1246 iptr[i * 6 + 5] = bsp_nodes[i].under;
1247 }
1248//#define DEBUG_BSP_TREE
1249#ifdef DEBUG_BSP_TREE
1250 Ref<FileAccess> f = FileAccess::open("res://bsp.txt", FileAccess::WRITE);
1251 for (uint32_t i = 0; i < bsp_nodes.size(); i++) {
1252 f->store_line(itos(i) + " - plane: " + bsp_nodes[i].plane + " over: " + itos(bsp_nodes[i].over) + " under: " + itos(bsp_nodes[i].under));
1253 }
1254#endif
1255 }
1256
1257 /* Obtain the colors from the images, they will be re-created as cubemaps on the server, depending on the driver */
1258
1259 gi_data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array, exposure_normalization);
1260 /* Compute a BSP tree of the simplices, so it's easy to find the exact one */
1261 }
1262
1263 gi_data->set_path(p_image_data_path);
1264 Error err = ResourceSaver::save(gi_data);
1265
1266 if (err != OK) {
1267 return BAKE_ERROR_CANT_CREATE_IMAGE;
1268 }
1269
1270 set_light_data(gi_data);
1271
1272 return BAKE_ERROR_OK;
1273}
1274
1275void LightmapGI::_notification(int p_what) {
1276 switch (p_what) {
1277 case NOTIFICATION_POST_ENTER_TREE: {
1278 if (light_data.is_valid()) {
1279 _assign_lightmaps();
1280 }
1281 } break;
1282
1283 case NOTIFICATION_EXIT_TREE: {
1284 if (light_data.is_valid()) {
1285 _clear_lightmaps();
1286 }
1287 } break;
1288 }
1289}
1290
1291void LightmapGI::_assign_lightmaps() {
1292 ERR_FAIL_COND(!light_data.is_valid());
1293
1294 for (int i = 0; i < light_data->get_user_count(); i++) {
1295 Node *node = get_node(light_data->get_user_path(i));
1296 int instance_idx = light_data->get_user_sub_instance(i);
1297 if (instance_idx >= 0) {
1298 RID instance_id = node->call("get_bake_mesh_instance", instance_idx);
1299 if (instance_id.is_valid()) {
1300 RS::get_singleton()->instance_geometry_set_lightmap(instance_id, get_instance(), light_data->get_user_lightmap_uv_scale(i), light_data->get_user_lightmap_slice_index(i));
1301 }
1302 } else {
1303 VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(node);
1304 ERR_CONTINUE(!vi);
1305 RS::get_singleton()->instance_geometry_set_lightmap(vi->get_instance(), get_instance(), light_data->get_user_lightmap_uv_scale(i), light_data->get_user_lightmap_slice_index(i));
1306 }
1307 }
1308}
1309
1310void LightmapGI::_clear_lightmaps() {
1311 ERR_FAIL_COND(!light_data.is_valid());
1312 for (int i = 0; i < light_data->get_user_count(); i++) {
1313 Node *node = get_node(light_data->get_user_path(i));
1314 int instance_idx = light_data->get_user_sub_instance(i);
1315 if (instance_idx >= 0) {
1316 RID instance_id = node->call("get_bake_mesh_instance", instance_idx);
1317 if (instance_id.is_valid()) {
1318 RS::get_singleton()->instance_geometry_set_lightmap(instance_id, RID(), Rect2(), 0);
1319 }
1320 } else {
1321 VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(node);
1322 ERR_CONTINUE(!vi);
1323 RS::get_singleton()->instance_geometry_set_lightmap(vi->get_instance(), RID(), Rect2(), 0);
1324 }
1325 }
1326}
1327
1328void LightmapGI::set_light_data(const Ref<LightmapGIData> &p_data) {
1329 if (light_data.is_valid()) {
1330 if (is_inside_tree()) {
1331 _clear_lightmaps();
1332 }
1333 set_base(RID());
1334 }
1335 light_data = p_data;
1336
1337 if (light_data.is_valid()) {
1338 set_base(light_data->get_rid());
1339 if (is_inside_tree()) {
1340 _assign_lightmaps();
1341 }
1342 }
1343
1344 update_gizmos();
1345}
1346
1347Ref<LightmapGIData> LightmapGI::get_light_data() const {
1348 return light_data;
1349}
1350
1351void LightmapGI::set_bake_quality(BakeQuality p_quality) {
1352 bake_quality = p_quality;
1353}
1354
1355LightmapGI::BakeQuality LightmapGI::get_bake_quality() const {
1356 return bake_quality;
1357}
1358
1359AABB LightmapGI::get_aabb() const {
1360 return AABB();
1361}
1362
1363void LightmapGI::set_use_denoiser(bool p_enable) {
1364 use_denoiser = p_enable;
1365}
1366
1367bool LightmapGI::is_using_denoiser() const {
1368 return use_denoiser;
1369}
1370
1371void LightmapGI::set_directional(bool p_enable) {
1372 directional = p_enable;
1373}
1374
1375bool LightmapGI::is_directional() const {
1376 return directional;
1377}
1378
1379void LightmapGI::set_interior(bool p_enable) {
1380 interior = p_enable;
1381}
1382
1383bool LightmapGI::is_interior() const {
1384 return interior;
1385}
1386
1387void LightmapGI::set_environment_mode(EnvironmentMode p_mode) {
1388 environment_mode = p_mode;
1389 notify_property_list_changed();
1390}
1391
1392LightmapGI::EnvironmentMode LightmapGI::get_environment_mode() const {
1393 return environment_mode;
1394}
1395
1396void LightmapGI::set_environment_custom_sky(const Ref<Sky> &p_sky) {
1397 environment_custom_sky = p_sky;
1398}
1399
1400Ref<Sky> LightmapGI::get_environment_custom_sky() const {
1401 return environment_custom_sky;
1402}
1403
1404void LightmapGI::set_environment_custom_color(const Color &p_color) {
1405 environment_custom_color = p_color;
1406}
1407
1408Color LightmapGI::get_environment_custom_color() const {
1409 return environment_custom_color;
1410}
1411
1412void LightmapGI::set_environment_custom_energy(float p_energy) {
1413 environment_custom_energy = p_energy;
1414}
1415
1416float LightmapGI::get_environment_custom_energy() const {
1417 return environment_custom_energy;
1418}
1419
1420void LightmapGI::set_bounces(int p_bounces) {
1421 ERR_FAIL_COND(p_bounces < 0 || p_bounces > 16);
1422 bounces = p_bounces;
1423}
1424
1425int LightmapGI::get_bounces() const {
1426 return bounces;
1427}
1428
1429void LightmapGI::set_bias(float p_bias) {
1430 ERR_FAIL_COND(p_bias < 0.00001);
1431 bias = p_bias;
1432}
1433
1434float LightmapGI::get_bias() const {
1435 return bias;
1436}
1437
1438void LightmapGI::set_max_texture_size(int p_size) {
1439 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));
1440 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));
1441 max_texture_size = p_size;
1442}
1443
1444int LightmapGI::get_max_texture_size() const {
1445 return max_texture_size;
1446}
1447
1448void LightmapGI::set_generate_probes(GenerateProbes p_generate_probes) {
1449 gen_probes = p_generate_probes;
1450}
1451
1452LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const {
1453 return gen_probes;
1454}
1455
1456void LightmapGI::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) {
1457 camera_attributes = p_camera_attributes;
1458}
1459
1460Ref<CameraAttributes> LightmapGI::get_camera_attributes() const {
1461 return camera_attributes;
1462}
1463
1464PackedStringArray LightmapGI::get_configuration_warnings() const {
1465 PackedStringArray warnings = Node::get_configuration_warnings();
1466
1467 if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
1468 warnings.push_back(RTR("LightmapGI nodes are not supported when using the GL Compatibility backend yet. Support will be added in a future release."));
1469 return warnings;
1470 }
1471
1472 return warnings;
1473}
1474
1475void LightmapGI::_validate_property(PropertyInfo &p_property) const {
1476 if (p_property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
1477 p_property.usage = PROPERTY_USAGE_NONE;
1478 }
1479 if (p_property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) {
1480 p_property.usage = PROPERTY_USAGE_NONE;
1481 }
1482 if (p_property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
1483 p_property.usage = PROPERTY_USAGE_NONE;
1484 }
1485}
1486
1487void LightmapGI::_bind_methods() {
1488 ClassDB::bind_method(D_METHOD("set_light_data", "data"), &LightmapGI::set_light_data);
1489 ClassDB::bind_method(D_METHOD("get_light_data"), &LightmapGI::get_light_data);
1490
1491 ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &LightmapGI::set_bake_quality);
1492 ClassDB::bind_method(D_METHOD("get_bake_quality"), &LightmapGI::get_bake_quality);
1493
1494 ClassDB::bind_method(D_METHOD("set_bounces", "bounces"), &LightmapGI::set_bounces);
1495 ClassDB::bind_method(D_METHOD("get_bounces"), &LightmapGI::get_bounces);
1496
1497 ClassDB::bind_method(D_METHOD("set_generate_probes", "subdivision"), &LightmapGI::set_generate_probes);
1498 ClassDB::bind_method(D_METHOD("get_generate_probes"), &LightmapGI::get_generate_probes);
1499
1500 ClassDB::bind_method(D_METHOD("set_bias", "bias"), &LightmapGI::set_bias);
1501 ClassDB::bind_method(D_METHOD("get_bias"), &LightmapGI::get_bias);
1502
1503 ClassDB::bind_method(D_METHOD("set_environment_mode", "mode"), &LightmapGI::set_environment_mode);
1504 ClassDB::bind_method(D_METHOD("get_environment_mode"), &LightmapGI::get_environment_mode);
1505
1506 ClassDB::bind_method(D_METHOD("set_environment_custom_sky", "sky"), &LightmapGI::set_environment_custom_sky);
1507 ClassDB::bind_method(D_METHOD("get_environment_custom_sky"), &LightmapGI::get_environment_custom_sky);
1508
1509 ClassDB::bind_method(D_METHOD("set_environment_custom_color", "color"), &LightmapGI::set_environment_custom_color);
1510 ClassDB::bind_method(D_METHOD("get_environment_custom_color"), &LightmapGI::get_environment_custom_color);
1511
1512 ClassDB::bind_method(D_METHOD("set_environment_custom_energy", "energy"), &LightmapGI::set_environment_custom_energy);
1513 ClassDB::bind_method(D_METHOD("get_environment_custom_energy"), &LightmapGI::get_environment_custom_energy);
1514
1515 ClassDB::bind_method(D_METHOD("set_max_texture_size", "max_texture_size"), &LightmapGI::set_max_texture_size);
1516 ClassDB::bind_method(D_METHOD("get_max_texture_size"), &LightmapGI::get_max_texture_size);
1517
1518 ClassDB::bind_method(D_METHOD("set_use_denoiser", "use_denoiser"), &LightmapGI::set_use_denoiser);
1519 ClassDB::bind_method(D_METHOD("is_using_denoiser"), &LightmapGI::is_using_denoiser);
1520
1521 ClassDB::bind_method(D_METHOD("set_interior", "enable"), &LightmapGI::set_interior);
1522 ClassDB::bind_method(D_METHOD("is_interior"), &LightmapGI::is_interior);
1523
1524 ClassDB::bind_method(D_METHOD("set_directional", "directional"), &LightmapGI::set_directional);
1525 ClassDB::bind_method(D_METHOD("is_directional"), &LightmapGI::is_directional);
1526
1527 ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &LightmapGI::set_camera_attributes);
1528 ClassDB::bind_method(D_METHOD("get_camera_attributes"), &LightmapGI::get_camera_attributes);
1529
1530 // ClassDB::bind_method(D_METHOD("bake", "from_node"), &LightmapGI::bake, DEFVAL(Variant()));
1531
1532 ADD_GROUP("Tweaks", "");
1533 ADD_PROPERTY(PropertyInfo(Variant::INT, "quality", PROPERTY_HINT_ENUM, "Low,Medium,High,Ultra"), "set_bake_quality", "get_bake_quality");
1534 ADD_PROPERTY(PropertyInfo(Variant::INT, "bounces", PROPERTY_HINT_RANGE, "0,16,1"), "set_bounces", "get_bounces");
1535 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional"), "set_directional", "is_directional");
1536 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
1537 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_denoiser"), "set_use_denoiser", "is_using_denoiser");
1538 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.00001,0.1,0.00001,or_greater"), "set_bias", "get_bias");
1539 ADD_PROPERTY(PropertyInfo(Variant::INT, "max_texture_size", PROPERTY_HINT_RANGE, "2048,16384,1"), "set_max_texture_size", "get_max_texture_size");
1540 ADD_GROUP("Environment", "environment_");
1541 ADD_PROPERTY(PropertyInfo(Variant::INT, "environment_mode", PROPERTY_HINT_ENUM, "Disabled,Scene,Custom Sky,Custom Color"), "set_environment_mode", "get_environment_mode");
1542 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment_custom_sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_environment_custom_sky", "get_environment_custom_sky");
1543 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "environment_custom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_environment_custom_color", "get_environment_custom_color");
1544 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "environment_custom_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_environment_custom_energy", "get_environment_custom_energy");
1545 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes");
1546 ADD_GROUP("Gen Probes", "generate_probes_");
1547 ADD_PROPERTY(PropertyInfo(Variant::INT, "generate_probes_subdiv", PROPERTY_HINT_ENUM, "Disabled,4,8,16,32"), "set_generate_probes", "get_generate_probes");
1548 ADD_GROUP("Data", "");
1549 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "LightmapGIData"), "set_light_data", "get_light_data");
1550
1551 BIND_ENUM_CONSTANT(BAKE_QUALITY_LOW);
1552 BIND_ENUM_CONSTANT(BAKE_QUALITY_MEDIUM);
1553 BIND_ENUM_CONSTANT(BAKE_QUALITY_HIGH);
1554 BIND_ENUM_CONSTANT(BAKE_QUALITY_ULTRA);
1555
1556 BIND_ENUM_CONSTANT(GENERATE_PROBES_DISABLED);
1557 BIND_ENUM_CONSTANT(GENERATE_PROBES_SUBDIV_4);
1558 BIND_ENUM_CONSTANT(GENERATE_PROBES_SUBDIV_8);
1559 BIND_ENUM_CONSTANT(GENERATE_PROBES_SUBDIV_16);
1560 BIND_ENUM_CONSTANT(GENERATE_PROBES_SUBDIV_32);
1561
1562 BIND_ENUM_CONSTANT(BAKE_ERROR_OK);
1563 BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SCENE_ROOT);
1564 BIND_ENUM_CONSTANT(BAKE_ERROR_FOREIGN_DATA);
1565 BIND_ENUM_CONSTANT(BAKE_ERROR_NO_LIGHTMAPPER);
1566 BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SAVE_PATH);
1567 BIND_ENUM_CONSTANT(BAKE_ERROR_NO_MESHES);
1568 BIND_ENUM_CONSTANT(BAKE_ERROR_MESHES_INVALID);
1569 BIND_ENUM_CONSTANT(BAKE_ERROR_CANT_CREATE_IMAGE);
1570 BIND_ENUM_CONSTANT(BAKE_ERROR_USER_ABORTED);
1571 BIND_ENUM_CONSTANT(BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL);
1572
1573 BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_DISABLED);
1574 BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_SCENE);
1575 BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_CUSTOM_SKY);
1576 BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_CUSTOM_COLOR);
1577}
1578
1579LightmapGI::LightmapGI() {
1580}
1581