Assorted fixes to UV unwrapping and GPU lightmapper

Various fixes to UV2 unwrapping and the GPU lightmapper. Listed here for
context in case of git blame/bisect:

* Fix UV2 unwrapping on import, also cleaned up the unwrap cache code.
* Fix saving of RGBA images in EXR format.
* Fixes to the GPU lightmapper:
	- Added padding between atlas elements, avoids bleeding.
	- Remove old SDF generation code.
	- Fix baked attenuation for Omni/Spot lights.
	- Fix baking of material properties onto UV2 (wireframe was
	  wrongly used before).
	- Disable statically baked lights for objects that have a
	  lightmap texture to avoid applying the same light twice.
	- Fix lightmap pairing in RendererSceneCull.
	- Fix UV2 array generated from `RenderingServer::mesh_surface_get_arrays()`.
	- Port autoexposure fix for OIDN from 3.x.
	- Save debug textures as EXR when using floating point format.
This commit is contained in:
jfons 2021-04-25 23:36:39 +02:00
parent eb57dcdb90
commit 6995b0429c
21 changed files with 457 additions and 481 deletions

View File

@ -1136,7 +1136,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
return importer->import_animation(p_path, p_flags, p_bake_fps); return importer->import_animation(p_path, p_flags, p_bake_fps);
} }
void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache) { void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches) {
EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node); EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
if (src_mesh_node) { if (src_mesh_node) {
//is mesh //is mesh
@ -1216,7 +1216,28 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
n = n->get_parent_spatial(); n = n->get_parent_spatial();
} }
//use xf as transform for mesh, and bake it Vector<uint8_t> lightmap_cache;
src_mesh_node->get_mesh()->lightmap_unwrap_cached(xf, p_lightmap_texel_size, p_src_lightmap_cache, lightmap_cache);
if (!lightmap_cache.is_empty()) {
if (r_lightmap_caches.is_empty()) {
r_lightmap_caches.push_back(lightmap_cache);
} else {
String new_md5 = String::md5(lightmap_cache.ptr()); // MD5 is stored at the beginning of the cache data
for (int i = 0; i < r_lightmap_caches.size(); i++) {
String md5 = String::md5(r_lightmap_caches[i].ptr());
if (new_md5 < md5) {
r_lightmap_caches.insert(i, lightmap_cache);
break;
}
if (new_md5 == md5) {
break;
}
}
}
}
} }
if (save_to_file != String()) { if (save_to_file != String()) {
@ -1265,7 +1286,7 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
} }
for (int i = 0; i < p_node->get_child_count(); i++) { for (int i = 0; i < p_node->get_child_count(); i++) {
_generate_meshes(p_node->get_child(i), p_mesh_data, p_generate_lods, p_create_shadow_meshes, p_light_bake_mode, p_lightmap_texel_size, p_src_lightmap_cache, r_dst_lightmap_cache); _generate_meshes(p_node->get_child(i), p_mesh_data, p_generate_lods, p_create_shadow_meshes, p_light_bake_mode, p_lightmap_texel_size, p_src_lightmap_cache, r_lightmap_caches);
} }
} }
@ -1433,7 +1454,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
float lightmap_texel_size = MAX(0.001, texel_size); float lightmap_texel_size = MAX(0.001, texel_size);
Vector<uint8_t> src_lightmap_cache; Vector<uint8_t> src_lightmap_cache;
Vector<uint8_t> dst_lightmap_cache; Vector<Vector<uint8_t>> mesh_lightmap_caches;
{ {
src_lightmap_cache = FileAccess::get_file_as_array(p_source_file + ".unwrap_cache", &err); src_lightmap_cache = FileAccess::get_file_as_array(p_source_file + ".unwrap_cache", &err);
@ -1446,125 +1467,21 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
if (subresources.has("meshes")) { if (subresources.has("meshes")) {
mesh_data = subresources["meshes"]; mesh_data = subresources["meshes"];
} }
_generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, dst_lightmap_cache); _generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, mesh_lightmap_caches);
if (dst_lightmap_cache.size()) { if (mesh_lightmap_caches.size()) {
FileAccessRef f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE); FileAccessRef f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE);
if (f) { if (f) {
f->store_buffer(dst_lightmap_cache.ptr(), dst_lightmap_cache.size()); f->store_32(mesh_lightmap_caches.size());
for (int i = 0; i < mesh_lightmap_caches.size(); i++) {
String md5 = String::md5(mesh_lightmap_caches[i].ptr());
f->store_buffer(mesh_lightmap_caches[i].ptr(), mesh_lightmap_caches[i].size());
}
f->close();
} }
} }
err = OK; err = OK;
#if 0
if (light_bake_mode == 2 /* || generate LOD */) {
Map<Ref<ArrayMesh>, Transform> meshes;
_find_meshes(scene, meshes);
String file_id = src_path.get_file();
String cache_file_path = base_path.plus_file(file_id + ".unwrap_cache");
Vector<unsigned char> cache_data;
if (FileAccess::exists(cache_file_path)) {
Error err2;
FileAccess *file = FileAccess::open(cache_file_path, FileAccess::READ, &err2);
if (err2) {
if (file) {
memdelete(file);
}
} else {
int cache_size = file->get_len();
cache_data.resize(cache_size);
file->get_buffer(cache_data.ptrw(), cache_size);
}
}
Map<String, unsigned int> used_unwraps;
EditorProgress progress2("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size());
int step = 0;
for (Map<Ref<ArrayMesh>, Transform>::Element *E = meshes.front(); E; E = E->next()) {
Ref<ArrayMesh> mesh = E->key();
String name = mesh->get_name();
if (name == "") { //should not happen but..
name = "Mesh " + itos(step);
}
progress2.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step);
int *ret_cache_data = (int *)cache_data.ptrw();
unsigned int ret_cache_size = cache_data.size();
bool ret_used_cache = true; // Tell the unwrapper to use the cache
Error err2 = mesh->lightmap_unwrap_cached(ret_cache_data, ret_cache_size, ret_used_cache, E->get(), texel_size);
if (err2 != OK) {
EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry.");
} else {
` String hash = String::md5((unsigned char *)ret_cache_data);
used_unwraps.insert(hash, ret_cache_size);
if (!ret_used_cache) {
// Cache was not used, add the generated entry to the current cache
if (cache_data.is_empty()) {
cache_data.resize(4 + ret_cache_size);
int *data = (int *)cache_data.ptrw();
data[0] = 1;
memcpy(&data[1], ret_cache_data, ret_cache_size);
} else {
int current_size = cache_data.size();
cache_data.resize(cache_data.size() + ret_cache_size);
unsigned char *ptrw = cache_data.ptrw();
memcpy(&ptrw[current_size], ret_cache_data, ret_cache_size);
int *data = (int *)ptrw;
data[0] += 1;
}
}
}
step++;
}
Error err2;
FileAccess *file = FileAccess::open(cache_file_path, FileAccess::WRITE, &err2);
if (err2) {
if (file) {
memdelete(file);
}
} else {
// Store number of entries
file->store_32(used_unwraps.size());
// Store cache entries
const int *cache = (int *)cache_data.ptr();
unsigned int r_idx = 1;
for (int i = 0; i < cache[0]; ++i) {
unsigned char *entry_start = (unsigned char *)&cache[r_idx];
String entry_hash = String::md5(entry_start);
if (used_unwraps.has(entry_hash)) {
unsigned int entry_size = used_unwraps[entry_hash];
file->store_buffer(entry_start, entry_size);
}
r_idx += 4; // hash
r_idx += 2; // size hint
int vertex_count = cache[r_idx];
r_idx += 1; // vertex count
r_idx += vertex_count; // vertex
r_idx += vertex_count * 2; // uvs
int index_count = cache[r_idx];
r_idx += 1; // index count
r_idx += index_count; // indices
}
file->close();
}
}
#endif
progress.step(TTR("Running Custom Script..."), 2); progress.step(TTR("Running Custom Script..."), 2);
String post_import_script_path = p_options["import_script/path"]; String post_import_script_path = p_options["import_script/path"];

View File

@ -119,7 +119,7 @@ class ResourceImporterScene : public ResourceImporter {
}; };
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner); void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache); void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches);
void _add_shapes(Node *p_node, const List<Ref<Shape3D>> &p_shapes); void _add_shapes(Node *p_node, const List<Ref<Shape3D>> &p_shapes);
public: public:

View File

@ -583,7 +583,7 @@ Ref<NavigationMesh> EditorSceneImporterMesh::create_navigation_mesh() {
return nm; return nm;
} }
extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache); extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y);
struct EditorSceneImporterMeshLightmapSurface { struct EditorSceneImporterMeshLightmapSurface {
Ref<Material> material; Ref<Material> material;
@ -593,22 +593,24 @@ struct EditorSceneImporterMeshLightmapSurface {
String name; String name;
}; };
Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size) { Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache) {
ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED); ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes."); ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
Vector<float> vertices; LocalVector<float> vertices;
Vector<float> normals; LocalVector<float> normals;
Vector<int> indices; LocalVector<int> indices;
Vector<float> uv; LocalVector<float> uv;
Vector<Pair<int, int>> uv_indices; LocalVector<Pair<int, int>> uv_indices;
Vector<EditorSceneImporterMeshLightmapSurface> lightmap_surfaces; Vector<EditorSceneImporterMeshLightmapSurface> lightmap_surfaces;
// Keep only the scale // Keep only the scale
Transform transform = p_base_transform; Basis basis = p_base_transform.get_basis();
transform.origin = Vector3(); Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length());
transform.looking_at(Vector3(1, 0, 0), Vector3(0, 1, 0));
Transform transform;
transform.scale(scale);
Basis normal_basis = transform.basis.inverse().transposed(); Basis normal_basis = transform.basis.inverse().transposed();
@ -623,15 +625,10 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices, &s.format); SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices, &s.format);
Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX]; PackedVector3Array rvertices = arrays[Mesh::ARRAY_VERTEX];
int vc = rvertices.size(); int vc = rvertices.size();
const Vector3 *r = rvertices.ptr();
Vector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL]; PackedVector3Array rnormals = arrays[Mesh::ARRAY_NORMAL];
ERR_FAIL_COND_V_MSG(rnormals.size() == 0, ERR_UNAVAILABLE, "Normals are required for lightmap unwrap.");
const Vector3 *rn = rnormals.ptr();
int vertex_ofs = vertices.size() / 3; int vertex_ofs = vertices.size() / 3;
@ -640,24 +637,29 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
uv_indices.resize(vertex_ofs + vc); uv_indices.resize(vertex_ofs + vc);
for (int j = 0; j < vc; j++) { for (int j = 0; j < vc; j++) {
Vector3 v = transform.xform(r[j]); Vector3 v = transform.xform(rvertices[j]);
Vector3 n = normal_basis.xform(rn[j]).normalized(); Vector3 n = normal_basis.xform(rnormals[j]).normalized();
vertices.write[(j + vertex_ofs) * 3 + 0] = v.x; vertices[(j + vertex_ofs) * 3 + 0] = v.x;
vertices.write[(j + vertex_ofs) * 3 + 1] = v.y; vertices[(j + vertex_ofs) * 3 + 1] = v.y;
vertices.write[(j + vertex_ofs) * 3 + 2] = v.z; vertices[(j + vertex_ofs) * 3 + 2] = v.z;
normals.write[(j + vertex_ofs) * 3 + 0] = n.x; normals[(j + vertex_ofs) * 3 + 0] = n.x;
normals.write[(j + vertex_ofs) * 3 + 1] = n.y; normals[(j + vertex_ofs) * 3 + 1] = n.y;
normals.write[(j + vertex_ofs) * 3 + 2] = n.z; normals[(j + vertex_ofs) * 3 + 2] = n.z;
uv_indices.write[j + vertex_ofs] = Pair<int, int>(i, j); uv_indices[j + vertex_ofs] = Pair<int, int>(i, j);
} }
Vector<int> rindices = arrays[Mesh::ARRAY_INDEX]; PackedInt32Array rindices = arrays[Mesh::ARRAY_INDEX];
int ic = rindices.size(); int ic = rindices.size();
float eps = 1.19209290e-7F; // Taken from xatlas.h
if (ic == 0) { if (ic == 0) {
for (int j = 0; j < vc / 3; j++) { for (int j = 0; j < vc / 3; j++) {
if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) { Vector3 p0 = transform.xform(rvertices[j * 3 + 0]);
Vector3 p1 = transform.xform(rvertices[j * 3 + 1]);
Vector3 p2 = transform.xform(rvertices[j * 3 + 2]);
if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue; continue;
} }
@ -667,15 +669,18 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
} }
} else { } else {
const int *ri = rindices.ptr();
for (int j = 0; j < ic / 3; j++) { for (int j = 0; j < ic / 3; j++) {
if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) { Vector3 p0 = transform.xform(rvertices[rindices[j * 3 + 0]]);
Vector3 p1 = transform.xform(rvertices[rindices[j * 3 + 1]]);
Vector3 p2 = transform.xform(rvertices[rindices[j * 3 + 2]]);
if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue; continue;
} }
indices.push_back(vertex_ofs + ri[j * 3 + 0]);
indices.push_back(vertex_ofs + ri[j * 3 + 1]); indices.push_back(vertex_ofs + rindices[j * 3 + 0]);
indices.push_back(vertex_ofs + ri[j * 3 + 2]); indices.push_back(vertex_ofs + rindices[j * 3 + 1]);
indices.push_back(vertex_ofs + rindices[j * 3 + 2]);
} }
} }
@ -684,6 +689,9 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
//unwrap //unwrap
bool use_cache = true; // Used to request cache generation and to know if cache was used
uint8_t *gen_cache;
int gen_cache_size;
float *gen_uvs; float *gen_uvs;
int *gen_vertices; int *gen_vertices;
int *gen_indices; int *gen_indices;
@ -692,7 +700,7 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
int size_x; int size_x;
int size_y; int size_y;
bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y, r_cache_data, r_cache_size, r_used_cache); bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), p_src_cache.ptr(), &use_cache, &gen_cache, &gen_cache_size, &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y);
if (!ok) { if (!ok) {
return ERR_CANT_CREATE; return ERR_CANT_CREATE;
@ -702,7 +710,7 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
clear(); clear();
//create surfacetools for each surface.. //create surfacetools for each surface..
Vector<Ref<SurfaceTool>> surfaces_tools; LocalVector<Ref<SurfaceTool>> surfaces_tools;
for (int i = 0; i < lightmap_surfaces.size(); i++) { for (int i = 0; i < lightmap_surfaces.size(); i++) {
Ref<SurfaceTool> st; Ref<SurfaceTool> st;
@ -714,11 +722,12 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
} }
print_verbose("Mesh: Gen indices: " + itos(gen_index_count)); print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
//go through all indices //go through all indices
for (int i = 0; i < gen_index_count; i += 3) { for (int i = 0; i < gen_index_count; i += 3) {
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_indices.size(), ERR_BUG); ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], (int)uv_indices.size(), ERR_BUG);
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_indices.size(), ERR_BUG); ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], (int)uv_indices.size(), ERR_BUG);
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_indices.size(), ERR_BUG); ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], (int)uv_indices.size(), ERR_BUG);
ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG); ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG);
@ -728,49 +737,54 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second]; SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_COLOR) { if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_COLOR) {
surfaces_tools.write[surface]->set_color(v.color); surfaces_tools[surface]->set_color(v.color);
} }
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TEX_UV) { if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TEX_UV) {
surfaces_tools.write[surface]->set_uv(v.uv); surfaces_tools[surface]->set_uv(v.uv);
} }
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_NORMAL) { if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_NORMAL) {
surfaces_tools.write[surface]->set_normal(v.normal); surfaces_tools[surface]->set_normal(v.normal);
} }
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TANGENT) { if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TANGENT) {
Plane t; Plane t;
t.normal = v.tangent; t.normal = v.tangent;
t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1; t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
surfaces_tools.write[surface]->set_tangent(t); surfaces_tools[surface]->set_tangent(t);
} }
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_BONES) { if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_BONES) {
surfaces_tools.write[surface]->set_bones(v.bones); surfaces_tools[surface]->set_bones(v.bones);
} }
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_WEIGHTS) { if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_WEIGHTS) {
surfaces_tools.write[surface]->set_weights(v.weights); surfaces_tools[surface]->set_weights(v.weights);
} }
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]); Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
surfaces_tools.write[surface]->set_uv2(uv2); surfaces_tools[surface]->set_uv2(uv2);
surfaces_tools.write[surface]->add_vertex(v.vertex); surfaces_tools[surface]->add_vertex(v.vertex);
} }
} }
//generate surfaces //generate surfaces
for (unsigned int i = 0; i < surfaces_tools.size(); i++) {
for (int i = 0; i < surfaces_tools.size(); i++) { surfaces_tools[i]->index();
surfaces_tools.write[i]->index(); Array arrays = surfaces_tools[i]->commit_to_arrays();
Array arrays = surfaces_tools.write[i]->commit_to_arrays(); add_surface(surfaces_tools[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools[i]->get_material(), surfaces_tools[i]->get_meta("name"));
add_surface(surfaces_tools.write[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools.write[i]->get_material(), surfaces_tools.write[i]->get_meta("name"));
} }
set_lightmap_size_hint(Size2(size_x, size_y)); set_lightmap_size_hint(Size2(size_x, size_y));
if (!r_used_cache) { if (gen_cache_size > 0) {
//free stuff r_dst_cache.resize(gen_cache_size);
::free(gen_vertices); memcpy(r_dst_cache.ptrw(), gen_cache, gen_cache_size);
::free(gen_indices); memfree(gen_cache);
::free(gen_uvs); }
if (!use_cache) {
// Cache was not used, free the buffers
memfree(gen_vertices);
memfree(gen_indices);
memfree(gen_uvs);
} }
return OK; return OK;

View File

@ -105,7 +105,7 @@ public:
Vector<Ref<Shape3D>> convex_decompose() const; Vector<Ref<Shape3D>> convex_decompose() const;
Ref<Shape3D> create_trimesh_shape() const; Ref<Shape3D> create_trimesh_shape() const;
Ref<NavigationMesh> create_navigation_mesh(); Ref<NavigationMesh> create_navigation_mesh();
Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size); Error lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache);
void set_lightmap_size_hint(const Size2i &p_size); void set_lightmap_size_hint(const Size2i &p_size);
Size2i get_lightmap_size_hint() const; Size2i get_lightmap_size_hint() const;

View File

@ -162,8 +162,8 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
MeshInstance &mi = mesh_instances.write[m_i]; MeshInstance &mi = mesh_instances.write[m_i];
Size2i s = Size2i(mi.data.albedo_on_uv2->get_width(), mi.data.albedo_on_uv2->get_height()); Size2i s = Size2i(mi.data.albedo_on_uv2->get_width(), mi.data.albedo_on_uv2->get_height());
sizes.push_back(s); sizes.push_back(s);
atlas_size.width = MAX(atlas_size.width, s.width); atlas_size.width = MAX(atlas_size.width, s.width + 2);
atlas_size.height = MAX(atlas_size.height, s.height); atlas_size.height = MAX(atlas_size.height, s.height + 2);
} }
int max = nearest_power_of_2_templated(atlas_size.width); int max = nearest_power_of_2_templated(atlas_size.width);
@ -186,10 +186,12 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
//determine best texture array atlas size by bruteforce fitting //determine best texture array atlas size by bruteforce fitting
while (atlas_size.x <= p_max_texture_size && atlas_size.y <= p_max_texture_size) { while (atlas_size.x <= p_max_texture_size && atlas_size.y <= p_max_texture_size) {
Vector<Vector2i> source_sizes = sizes; Vector<Vector2i> source_sizes;
Vector<int> source_indices; Vector<int> source_indices;
source_indices.resize(source_sizes.size()); source_sizes.resize(sizes.size());
source_indices.resize(sizes.size());
for (int i = 0; i < source_indices.size(); i++) { for (int i = 0; i < source_indices.size(); i++) {
source_sizes.write[i] = sizes[i] + Vector2i(2, 2); // Add padding between lightmaps
source_indices.write[i] = i; source_indices.write[i] = i;
} }
Vector<Vector3i> atlas_offsets; Vector<Vector3i> atlas_offsets;
@ -207,7 +209,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
if (ofs.z > 0) { if (ofs.z > 0) {
//valid //valid
ofs.z = slices; ofs.z = slices;
atlas_offsets.write[sidx] = ofs; atlas_offsets.write[sidx] = ofs + Vector3i(1, 1, 0); // Center lightmap in the reserved oversized region
} else { } else {
new_indices.push_back(sidx); new_indices.push_back(sidx);
new_sources.push_back(source_sizes[i]); new_sources.push_back(source_sizes[i]);
@ -272,7 +274,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
return BAKE_OK; return BAKE_OK;
} }
void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &grid_texture_sdf, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) { void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) {
HashMap<Vertex, uint32_t, VertexHash> vertex_map; HashMap<Vertex, uint32_t, VertexHash> vertex_map;
//fill triangles array and vertex array //fill triangles array and vertex array
@ -482,14 +484,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
img->save_png("res://grid_layer_" + itos(1000 + i).substr(1, 3) + ".png"); img->save_png("res://grid_layer_" + itos(1000 + i).substr(1, 3) + ".png");
} }
#endif #endif
if (p_step_function) {
p_step_function(0.45, TTR("Generating Signed Distance Field"), p_bake_userdata, true);
}
//generate SDF for raytracing
Vector<uint32_t> euclidean_pos = Geometry3D::generate_edf(solid, Vector3i(grid_size, grid_size, grid_size), false);
Vector<uint32_t> euclidean_neg = Geometry3D::generate_edf(solid, Vector3i(grid_size, grid_size, grid_size), true);
Vector<int8_t> sdf8 = Geometry3D::generate_sdf8(euclidean_pos, euclidean_neg);
/*****************************/ /*****************************/
/*** CREATE GPU STRUCTURES ***/ /*** CREATE GPU STRUCTURES ***/
@ -551,10 +545,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
tf.format = RD::DATA_FORMAT_R32G32_UINT; tf.format = RD::DATA_FORMAT_R32G32_UINT;
texdata.write[0] = grid_indices.to_byte_array(); texdata.write[0] = grid_indices.to_byte_array();
grid_texture = rd->texture_create(tf, RD::TextureView(), texdata); grid_texture = rd->texture_create(tf, RD::TextureView(), texdata);
//sdf
tf.format = RD::DATA_FORMAT_R8_SNORM;
texdata.write[0] = sdf8.to_byte_array();
grid_texture_sdf = rd->texture_create(tf, RD::TextureView(), texdata);
} }
} }
@ -755,8 +745,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
light_environment_tex = rd->texture_create(tfp, RD::TextureView(), tdata); light_environment_tex = rd->texture_create(tfp, RD::TextureView(), tdata);
#ifdef DEBUG_TEXTURES #ifdef DEBUG_TEXTURES
panorama_tex->convert(Image::FORMAT_RGB8); panorama_tex->save_exr("res://0_panorama.exr", false);
panorama_tex->save_png("res://0_panorama.png");
#endif #endif
} }
} }
@ -770,7 +759,6 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RID lights_buffer; RID lights_buffer;
RID triangle_cell_indices_buffer; RID triangle_cell_indices_buffer;
RID grid_texture; RID grid_texture;
RID grid_texture_sdf;
RID seams_buffer; RID seams_buffer;
RID probe_positions_buffer; RID probe_positions_buffer;
@ -783,11 +771,10 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->free(lights_buffer); \ rd->free(lights_buffer); \
rd->free(triangle_cell_indices_buffer); \ rd->free(triangle_cell_indices_buffer); \
rd->free(grid_texture); \ rd->free(grid_texture); \
rd->free(grid_texture_sdf); \
rd->free(seams_buffer); \ rd->free(seams_buffer); \
rd->free(probe_positions_buffer); rd->free(probe_positions_buffer);
_create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, box_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, grid_texture_sdf, seams_buffer, p_step_function, p_bake_userdata); _create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, box_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, seams_buffer, p_step_function, p_bake_userdata);
if (p_step_function) { if (p_step_function) {
p_step_function(0.47, TTR("Preparing shaders"), p_bake_userdata, true); p_step_function(0.47, TTR("Preparing shaders"), p_bake_userdata, true);
@ -883,27 +870,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RD::Uniform u; RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9; u.binding = 9;
u.ids.push_back(grid_texture_sdf);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 10;
u.ids.push_back(albedo_array_tex); u.ids.push_back(albedo_array_tex);
base_uniforms.push_back(u); base_uniforms.push_back(u);
} }
{ {
RD::Uniform u; RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 11; u.binding = 10;
u.ids.push_back(emission_array_tex); u.ids.push_back(emission_array_tex);
base_uniforms.push_back(u); base_uniforms.push_back(u);
} }
{ {
RD::Uniform u; RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 12; u.binding = 11;
u.ids.push_back(sampler); u.ids.push_back(sampler);
base_uniforms.push_back(u); base_uniforms.push_back(u);
} }
@ -937,13 +917,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img; Ref<Image> img;
img.instance(); img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAF, s); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAF, s);
img->convert(Image::FORMAT_RGBA8); img->save_exr("res://1_position_" + itos(i) + ".exr", false);
img->save_png("res://1_position_" + itos(i) + ".png");
s = rd->texture_get_data(normal_tex, i); s = rd->texture_get_data(normal_tex, i);
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->convert(Image::FORMAT_RGBA8); img->save_exr("res://1_normal_" + itos(i) + ".exr", false);
img->save_png("res://1_normal_" + itos(i) + ".png");
} }
#endif #endif
@ -966,27 +944,27 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
} }
ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
//unoccluder // Unoccluder
RID compute_shader_unocclude = rd->shader_create_from_bytecode(compute_shader->get_bytecode("unocclude")); RID compute_shader_unocclude = rd->shader_create_from_bytecode(compute_shader->get_bytecode("unocclude"));
ERR_FAIL_COND_V(compute_shader_unocclude.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen ERR_FAIL_COND_V(compute_shader_unocclude.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen
RID compute_shader_unocclude_pipeline = rd->compute_pipeline_create(compute_shader_unocclude); RID compute_shader_unocclude_pipeline = rd->compute_pipeline_create(compute_shader_unocclude);
//direct light // Direct light
RID compute_shader_primary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("primary")); RID compute_shader_primary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("primary"));
ERR_FAIL_COND_V(compute_shader_primary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen ERR_FAIL_COND_V(compute_shader_primary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen
RID compute_shader_primary_pipeline = rd->compute_pipeline_create(compute_shader_primary); RID compute_shader_primary_pipeline = rd->compute_pipeline_create(compute_shader_primary);
//indirect light // Indirect light
RID compute_shader_secondary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("secondary")); RID compute_shader_secondary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("secondary"));
ERR_FAIL_COND_V(compute_shader_secondary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen ERR_FAIL_COND_V(compute_shader_secondary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_secondary_pipeline = rd->compute_pipeline_create(compute_shader_secondary); RID compute_shader_secondary_pipeline = rd->compute_pipeline_create(compute_shader_secondary);
//dilate // Dilate
RID compute_shader_dilate = rd->shader_create_from_bytecode(compute_shader->get_bytecode("dilate")); RID compute_shader_dilate = rd->shader_create_from_bytecode(compute_shader->get_bytecode("dilate"));
ERR_FAIL_COND_V(compute_shader_dilate.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen ERR_FAIL_COND_V(compute_shader_dilate.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_dilate_pipeline = rd->compute_pipeline_create(compute_shader_dilate); RID compute_shader_dilate_pipeline = rd->compute_pipeline_create(compute_shader_dilate);
//dilate // Light probes
RID compute_shader_light_probes = rd->shader_create_from_bytecode(compute_shader->get_bytecode("light_probes")); RID compute_shader_light_probes = rd->shader_create_from_bytecode(compute_shader->get_bytecode("light_probes"));
ERR_FAIL_COND_V(compute_shader_light_probes.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen ERR_FAIL_COND_V(compute_shader_light_probes.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_light_probes_pipeline = rd->compute_pipeline_create(compute_shader_light_probes); RID compute_shader_light_probes_pipeline = rd->compute_pipeline_create(compute_shader_light_probes);
@ -1153,8 +1131,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img; Ref<Image> img;
img.instance(); img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->convert(Image::FORMAT_RGBA8); img->save_exr("res://2_light_primary_" + itos(i) + ".exr", false);
img->save_png("res://2_light_primary_" + itos(i) + ".png");
} }
#endif #endif
@ -1212,7 +1189,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RD::Uniform u; RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 6; u.binding = 6;
u.ids.push_back(light_environment_tex); //reuse unocclude tex u.ids.push_back(light_environment_tex);
uniforms.push_back(u); uniforms.push_back(u);
} }
} }
@ -1298,7 +1275,15 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
} }
} }
} }
if (b == 0) {
// This disables the environment for subsequent bounces
push_constant.environment_xform[3] = -99.0f;
}
} }
// Restore the correct environment transform
push_constant.environment_xform[3] = 0.0f;
} }
/* LIGHPROBES */ /* LIGHPROBES */
@ -1449,8 +1434,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img; Ref<Image> img;
img.instance(); img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->convert(Image::FORMAT_RGBA8); img->save_exr("res://4_light_secondary_" + itos(i) + ".exr", false);
img->save_png("res://4_light_secondary_" + itos(i) + ".png");
} }
#endif #endif
@ -1582,6 +1566,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
clear_colors.push_back(Color(0, 0, 0, 1)); clear_colors.push_back(Color(0, 0, 0, 1));
for (int i = 0; i < atlas_slices; i++) { for (int i = 0; i < atlas_slices; i++) {
int subslices = (p_bake_sh ? 4 : 1); int subslices = (p_bake_sh ? 4 : 1);
if (slice_seam_count[i] == 0) {
continue;
}
for (int k = 0; k < subslices; k++) { for (int k = 0; k < subslices; k++) {
RasterSeamsPushConstant seams_push_constant; RasterSeamsPushConstant seams_push_constant;
seams_push_constant.slice = uint32_t(i * subslices + k); seams_push_constant.slice = uint32_t(i * subslices + k);
@ -1654,8 +1643,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img; Ref<Image> img;
img.instance(); img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->convert(Image::FORMAT_RGBA8); img->save_exr("res://5_blendseams" + itos(i) + ".exr", false);
img->save_png("res://5_blendseams" + itos(i) + ".png");
} }
#endif #endif
if (p_step_function) { if (p_step_function) {
@ -1682,7 +1670,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img2; Ref<Image> img2;
img2.instance(); img2.instance();
img2->create(probe_values.size(), 1, false, Image::FORMAT_RGBAF, probe_data); img2->create(probe_values.size(), 1, false, Image::FORMAT_RGBAF, probe_data);
img2->save_png("res://6_lightprobes.png"); img2->save_exr("res://6_lightprobes.exr", false);
} }
#endif #endif
} }

View File

@ -231,7 +231,7 @@ class LightmapperRD : public Lightmapper {
Vector<Color> probe_values; Vector<Color> probe_values;
BakeError _blit_meshes_into_atlas(int p_max_texture_size, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata); BakeError _blit_meshes_into_atlas(int p_max_texture_size, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata);
void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &grid_texture_sdf, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata); void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata);
void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform); void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform);
public: public:

View File

@ -84,9 +84,8 @@ layout(set = 0, binding = 7, std430) restrict readonly buffer Probes {
probe_positions; probe_positions;
layout(set = 0, binding = 8) uniform utexture3D grid; layout(set = 0, binding = 8) uniform utexture3D grid;
layout(set = 0, binding = 9) uniform texture3D grid_sdf;
layout(set = 0, binding = 10) uniform texture2DArray albedo_tex; layout(set = 0, binding = 9) uniform texture2DArray albedo_tex;
layout(set = 0, binding = 11) uniform texture2DArray emission_tex; layout(set = 0, binding = 10) uniform texture2DArray emission_tex;
layout(set = 0, binding = 12) uniform sampler linear_sampler; layout(set = 0, binding = 11) uniform sampler linear_sampler;

View File

@ -96,15 +96,22 @@ params;
bool ray_hits_triangle(vec3 from, vec3 dir, float max_dist, vec3 p0, vec3 p1, vec3 p2, out float r_distance, out vec3 r_barycentric) { bool ray_hits_triangle(vec3 from, vec3 dir, float max_dist, vec3 p0, vec3 p1, vec3 p2, out float r_distance, out vec3 r_barycentric) {
const vec3 e0 = p1 - p0; const vec3 e0 = p1 - p0;
const vec3 e1 = p0 - p2; const vec3 e1 = p0 - p2;
vec3 triangleNormal = cross(e1, e0); vec3 triangle_normal = cross(e1, e0);
const vec3 e2 = (1.0 / dot(triangleNormal, dir)) * (p0 - from); float n_dot_dir = dot(triangle_normal, dir);
if (abs(n_dot_dir) < 0.01) {
return false;
}
const vec3 e2 = (p0 - from) / n_dot_dir;
const vec3 i = cross(dir, e2); const vec3 i = cross(dir, e2);
r_barycentric.y = dot(i, e1); r_barycentric.y = dot(i, e1);
r_barycentric.z = dot(i, e0); r_barycentric.z = dot(i, e0);
r_barycentric.x = 1.0 - (r_barycentric.z + r_barycentric.y); r_barycentric.x = 1.0 - (r_barycentric.z + r_barycentric.y);
r_distance = dot(triangleNormal, e2); r_distance = dot(triangle_normal, e2);
return (r_distance > params.bias) && (r_distance < max_dist) && all(greaterThanEqual(r_barycentric, vec3(0.0))); return (r_distance > params.bias) && (r_distance < max_dist) && all(greaterThanEqual(r_barycentric, vec3(0.0)));
} }
@ -307,8 +314,6 @@ void main() {
continue; continue;
} }
d /= lights.data[i].range;
attenuation = get_omni_attenuation(d, 1.0 / lights.data[i].range, lights.data[i].attenuation); attenuation = get_omni_attenuation(d, 1.0 / lights.data[i].range, lights.data[i].attenuation);
if (lights.data[i].type == LIGHT_TYPE_SPOT) { if (lights.data[i].type == LIGHT_TYPE_SPOT) {
@ -410,7 +415,7 @@ void main() {
uint tidx; uint tidx;
vec3 barycentric; vec3 barycentric;
vec3 light; vec3 light = vec3(0.0);
if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) { if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) {
//hit a triangle //hit a triangle
vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv; vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv;
@ -419,8 +424,8 @@ void main() {
vec3 uvw = vec3(barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2, float(triangles.data[tidx].slice)); vec3 uvw = vec3(barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2, float(triangles.data[tidx].slice));
light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb; light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
} else { } else if (params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce
//did not hit a triangle, reach out for the sky // Did not hit a triangle, reach out for the sky
vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir); vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
vec2 st = vec2( vec2 st = vec2(

View File

@ -169,7 +169,7 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
{ 0 }, // R { 0 }, // R
{ 1, 0 }, // GR { 1, 0 }, // GR
{ 2, 1, 0 }, // BGR { 2, 1, 0 }, // BGR
{ 2, 1, 0, 3 } // BGRA { 3, 2, 1, 0 } // ABGR
}; };
int channel_count = get_channel_count(format); int channel_count = get_channel_count(format);

View File

@ -29,26 +29,19 @@
/*************************************************************************/ /*************************************************************************/
#include "register_types.h" #include "register_types.h"
#include "core/error/error_macros.h"
#include "core/crypto/crypto_core.h" #include "core/crypto/crypto_core.h"
#include "thirdparty/xatlas/xatlas.h" #include "thirdparty/xatlas/xatlas.h"
#include <stdio.h> extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y);
#include <stdlib.h>
extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache); bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) {
bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uvs, int **r_vertices, int *r_vertex_count, int **r_indices, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache) {
CryptoCore::MD5Context ctx; CryptoCore::MD5Context ctx;
ctx.start(); ctx.start();
ctx.update((unsigned char *)&p_texel_size, sizeof(float)); ctx.update((unsigned char *)&p_texel_size, sizeof(float));
ctx.update((unsigned char *)p_indices, sizeof(int) * p_index_count); ctx.update((unsigned char *)p_indices, sizeof(int) * p_index_count);
ctx.update((unsigned char *)p_vertices, sizeof(float) * p_vertex_count); ctx.update((unsigned char *)p_vertices, sizeof(float) * p_vertex_count * 3);
ctx.update((unsigned char *)p_normals, sizeof(float) * p_vertex_count); ctx.update((unsigned char *)p_normals, sizeof(float) * p_vertex_count * 3);
unsigned char hash[16]; unsigned char hash[16];
ctx.finish(hash); ctx.finish(hash);
@ -56,38 +49,37 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
bool cached = false; bool cached = false;
unsigned int cache_idx = 0; unsigned int cache_idx = 0;
if (r_used_cache && r_cache_size) { *r_mesh_cache = nullptr;
//Check if hash is in cache data *r_mesh_cache_size = 0;
int *cache_data = r_cache_data; if (p_cache_data) {
//Check if hash is in cache data
int *cache_data = (int *)p_cache_data;
int n_entries = cache_data[0]; int n_entries = cache_data[0];
unsigned int r_idx = 1; unsigned int read_idx = 1;
for (int i = 0; i < n_entries; ++i) { for (int i = 0; i < n_entries; ++i) {
if (memcmp(&cache_data[r_idx], hash, 16) == 0) { if (memcmp(&cache_data[read_idx], hash, 16) == 0) {
cached = true; cached = true;
cache_idx = r_idx; cache_idx = read_idx;
break; break;
} }
r_idx += 4; // hash read_idx += 4; // hash
r_idx += 2; // size hint read_idx += 2; // size hint
int vertex_count = cache_data[r_idx]; int vertex_count = cache_data[read_idx];
r_idx += 1; // vertex count read_idx += 1; // vertex count
r_idx += vertex_count; // vertex read_idx += vertex_count; // vertex
r_idx += vertex_count * 2; // uvs read_idx += vertex_count * 2; // uvs
int index_count = cache_data[r_idx]; int index_count = cache_data[read_idx];
r_idx += 1; // index count read_idx += 1; // index count
r_idx += index_count; // indices read_idx += index_count; // indices
} }
} }
if (r_used_cache && cached) { if (cached) {
int *cache_data = r_cache_data; int *cache_data = (int *)p_cache_data;
// Return cache data pointer to the caller
r_cache_data = &cache_data[cache_idx];
cache_idx += 4; cache_idx += 4;
@ -99,96 +91,92 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
// Load vertices // Load vertices
*r_vertex_count = cache_data[cache_idx]; *r_vertex_count = cache_data[cache_idx];
cache_idx++; cache_idx++;
*r_vertices = &cache_data[cache_idx]; *r_vertex = &cache_data[cache_idx];
cache_idx += *r_vertex_count; cache_idx += *r_vertex_count;
// Load UVs // Load UVs
*r_uvs = (float *)&cache_data[cache_idx]; *r_uv = (float *)&cache_data[cache_idx];
cache_idx += *r_vertex_count * 2; cache_idx += *r_vertex_count * 2;
// Load indices // Load indices
*r_index_count = cache_data[cache_idx]; *r_index_count = cache_data[cache_idx];
cache_idx++; cache_idx++;
*r_indices = &cache_data[cache_idx]; *r_index = &cache_data[cache_idx];
} else {
// set up input mesh
xatlas::MeshDecl input_mesh;
input_mesh.indexData = p_indices;
input_mesh.indexCount = p_index_count;
input_mesh.indexFormat = xatlas::IndexFormat::UInt32;
// Return cache data size to the caller input_mesh.vertexCount = p_vertex_count;
r_cache_size = sizeof(int) * (4 + 2 + 1 + *r_vertex_count + (*r_vertex_count * 2) + 1 + *r_index_count); // hash + size hint + vertex_count + vertices + uvs + index_count + indices input_mesh.vertexPositionData = p_vertices;
r_used_cache = true; input_mesh.vertexPositionStride = sizeof(float) * 3;
return true; input_mesh.vertexNormalData = p_normals;
} input_mesh.vertexNormalStride = sizeof(uint32_t) * 3;
input_mesh.vertexUvData = NULL;
input_mesh.vertexUvStride = 0;
//set up input mesh xatlas::ChartOptions chart_options;
xatlas::MeshDecl input_mesh; chart_options.fixWinding = true;
input_mesh.indexData = p_indices;
input_mesh.indexCount = p_index_count;
input_mesh.indexFormat = xatlas::IndexFormat::UInt32;
input_mesh.vertexCount = p_vertex_count; xatlas::PackOptions pack_options;
input_mesh.vertexPositionData = p_vertices; pack_options.padding = 1;
input_mesh.vertexPositionStride = sizeof(float) * 3; pack_options.maxChartSize = 4094; // Lightmap atlassing needs 2 for padding between meshes, so 4096-2
input_mesh.vertexNormalData = p_normals; pack_options.blockAlign = true;
input_mesh.vertexNormalStride = sizeof(uint32_t) * 3; pack_options.texelsPerUnit = 1.0 / p_texel_size;
input_mesh.vertexUvData = nullptr;
input_mesh.vertexUvStride = 0;
xatlas::ChartOptions chart_options; xatlas::Atlas *atlas = xatlas::Create();
xatlas::PackOptions pack_options;
pack_options.maxChartSize = 4096; xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
pack_options.blockAlign = true; ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
pack_options.padding = 1;
pack_options.texelsPerUnit = 1.0 / p_texel_size;
xatlas::Atlas *atlas = xatlas::Create(); xatlas::Generate(atlas, chart_options, pack_options);
printf("Adding mesh..\n");
xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
printf("Generate..\n"); *r_size_hint_x = atlas->width;
xatlas::Generate(atlas, chart_options, pack_options); *r_size_hint_y = atlas->height;
*r_size_hint_x = atlas->width; float w = *r_size_hint_x;
*r_size_hint_y = atlas->height; float h = *r_size_hint_y;
float w = *r_size_hint_x; if (w == 0 || h == 0) {
float h = *r_size_hint_y; xatlas::Destroy(atlas);
return false; //could not bake because there is no area
}
const xatlas::Mesh &output = atlas->meshes[0];
*r_vertex = (int *)memalloc(sizeof(int) * output.vertexCount);
ERR_FAIL_NULL_V_MSG(*r_vertex, false, "Out of memory.");
*r_uv = (float *)memalloc(sizeof(float) * output.vertexCount * 2);
ERR_FAIL_NULL_V_MSG(*r_uv, false, "Out of memory.");
*r_index = (int *)memalloc(sizeof(int) * output.indexCount);
ERR_FAIL_NULL_V_MSG(*r_index, false, "Out of memory.");
float max_x = 0;
float max_y = 0;
for (uint32_t i = 0; i < output.vertexCount; i++) {
(*r_vertex)[i] = output.vertexArray[i].xref;
(*r_uv)[i * 2 + 0] = output.vertexArray[i].uv[0] / w;
(*r_uv)[i * 2 + 1] = output.vertexArray[i].uv[1] / h;
max_x = MAX(max_x, output.vertexArray[i].uv[0]);
max_y = MAX(max_y, output.vertexArray[i].uv[1]);
}
*r_vertex_count = output.vertexCount;
for (uint32_t i = 0; i < output.indexCount; i++) {
(*r_index)[i] = output.indexArray[i];
}
*r_index_count = output.indexCount;
if (w == 0 || h == 0) {
xatlas::Destroy(atlas); xatlas::Destroy(atlas);
return false; //could not bake because there is no area
} }
const xatlas::Mesh &output = atlas->meshes[0]; if (*r_use_cache) {
// Build cache data for current mesh
*r_vertices = (int *)malloc(sizeof(int) * output.vertexCount);
ERR_FAIL_NULL_V_MSG(*r_vertices, false, "Out of memory.");
*r_uvs = (float *)malloc(sizeof(float) * output.vertexCount * 2);
ERR_FAIL_NULL_V_MSG(*r_uvs, false, "Out of memory.");
*r_indices = (int *)malloc(sizeof(int) * output.indexCount);
ERR_FAIL_NULL_V_MSG(*r_indices, false, "Out of memory.");
float max_x = 0.0;
float max_y = 0.0;
for (uint32_t i = 0; i < output.vertexCount; i++) {
(*r_vertices)[i] = output.vertexArray[i].xref;
(*r_uvs)[i * 2 + 0] = output.vertexArray[i].uv[0] / w;
(*r_uvs)[i * 2 + 1] = output.vertexArray[i].uv[1] / h;
max_x = MAX(max_x, output.vertexArray[i].uv[0]);
max_y = MAX(max_y, output.vertexArray[i].uv[1]);
}
printf("Final texture size: %f,%f - max %f,%f\n", w, h, max_x, max_y);
*r_vertex_count = output.vertexCount;
for (uint32_t i = 0; i < output.indexCount; i++) {
(*r_indices)[i] = output.indexArray[i];
}
*r_index_count = output.indexCount;
xatlas::Destroy(atlas);
if (r_used_cache) {
unsigned int new_cache_size = 4 + 2 + 1 + *r_vertex_count + (*r_vertex_count * 2) + 1 + *r_index_count; // hash + size hint + vertex_count + vertices + uvs + index_count + indices unsigned int new_cache_size = 4 + 2 + 1 + *r_vertex_count + (*r_vertex_count * 2) + 1 + *r_index_count; // hash + size hint + vertex_count + vertices + uvs + index_count + indices
new_cache_size *= sizeof(int); new_cache_size *= sizeof(int);
int *new_cache_data = (int *)memalloc(new_cache_size); int *new_cache_data = (int *)memalloc(new_cache_size);
@ -208,11 +196,11 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
new_cache_idx++; new_cache_idx++;
// vertices // vertices
memcpy(&new_cache_data[new_cache_idx], *r_vertices, sizeof(int) * *r_vertex_count); memcpy(&new_cache_data[new_cache_idx], *r_vertex, sizeof(int) * (*r_vertex_count));
new_cache_idx += *r_vertex_count; new_cache_idx += *r_vertex_count;
// uvs // uvs
memcpy(&new_cache_data[new_cache_idx], *r_uvs, sizeof(float) * *r_vertex_count * 2); memcpy(&new_cache_data[new_cache_idx], *r_uv, sizeof(float) * (*r_vertex_count) * 2);
new_cache_idx += *r_vertex_count * 2; new_cache_idx += *r_vertex_count * 2;
// index count // index count
@ -220,15 +208,15 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
new_cache_idx++; new_cache_idx++;
// indices // indices
memcpy(&new_cache_data[new_cache_idx], *r_indices, sizeof(int) * *r_index_count); memcpy(&new_cache_data[new_cache_idx], *r_index, sizeof(int) * (*r_index_count));
new_cache_idx += *r_index_count;
// Return cache data to the caller // Return cache data to the caller
r_cache_data = new_cache_data; *r_mesh_cache = (uint8_t *)new_cache_data;
r_cache_size = new_cache_size; *r_mesh_cache_size = new_cache_size;
r_used_cache = false;
} }
*r_use_cache = cached; // Return whether cache was used.
return true; return true;
} }

View File

@ -1401,7 +1401,7 @@ void ArrayMesh::regen_normal_maps() {
} }
//dirty hack //dirty hack
bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache); bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = NULL;
struct ArrayMeshLightmapSurface { struct ArrayMeshLightmapSurface {
Ref<Material> material; Ref<Material> material;
@ -1411,28 +1411,28 @@ struct ArrayMeshLightmapSurface {
}; };
Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) { Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) {
int *cache_data = nullptr; Vector<uint8_t> null_cache;
unsigned int cache_size = 0; return lightmap_unwrap_cached(p_base_transform, p_texel_size, null_cache, null_cache, false);
bool use_cache = false; // Don't use cache
return lightmap_unwrap_cached(cache_data, cache_size, use_cache, p_base_transform, p_texel_size);
} }
Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size) { Error ArrayMesh::lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache, bool p_generate_cache) {
ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED); ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes."); ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
Vector<float> vertices; LocalVector<float> vertices;
Vector<float> normals; LocalVector<float> normals;
Vector<int> indices; LocalVector<int> indices;
Vector<float> uv; LocalVector<float> uv;
Vector<Pair<int, int>> uv_indices; LocalVector<Pair<int, int>> uv_indices;
Vector<ArrayMeshLightmapSurface> lightmap_surfaces; Vector<ArrayMeshLightmapSurface> lightmap_surfaces;
// Keep only the scale // Keep only the scale
Transform transform = p_base_transform; Basis basis = p_base_transform.get_basis();
transform.origin = Vector3(); Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length());
transform.looking_at(Vector3(1, 0, 0), Vector3(0, 1, 0));
Transform transform;
transform.scale(scale);
Basis normal_basis = transform.basis.inverse().transposed(); Basis normal_basis = transform.basis.inverse().transposed();
@ -1446,14 +1446,12 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
Array arrays = surface_get_arrays(i); Array arrays = surface_get_arrays(i);
s.material = surface_get_material(i); s.material = surface_get_material(i);
SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices); SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices, &s.format);
Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX]; PackedVector3Array rvertices = arrays[Mesh::ARRAY_VERTEX];
int vc = rvertices.size(); int vc = rvertices.size();
const Vector3 *r = rvertices.ptr();
Vector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL]; PackedVector3Array rnormals = arrays[Mesh::ARRAY_NORMAL];
const Vector3 *rn = rnormals.ptr();
int vertex_ofs = vertices.size() / 3; int vertex_ofs = vertices.size() / 3;
@ -1462,24 +1460,29 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
uv_indices.resize(vertex_ofs + vc); uv_indices.resize(vertex_ofs + vc);
for (int j = 0; j < vc; j++) { for (int j = 0; j < vc; j++) {
Vector3 v = transform.xform(r[j]); Vector3 v = transform.xform(rvertices[j]);
Vector3 n = normal_basis.xform(rn[j]).normalized(); Vector3 n = normal_basis.xform(rnormals[j]).normalized();
vertices.write[(j + vertex_ofs) * 3 + 0] = v.x; vertices[(j + vertex_ofs) * 3 + 0] = v.x;
vertices.write[(j + vertex_ofs) * 3 + 1] = v.y; vertices[(j + vertex_ofs) * 3 + 1] = v.y;
vertices.write[(j + vertex_ofs) * 3 + 2] = v.z; vertices[(j + vertex_ofs) * 3 + 2] = v.z;
normals.write[(j + vertex_ofs) * 3 + 0] = n.x; normals[(j + vertex_ofs) * 3 + 0] = n.x;
normals.write[(j + vertex_ofs) * 3 + 1] = n.y; normals[(j + vertex_ofs) * 3 + 1] = n.y;
normals.write[(j + vertex_ofs) * 3 + 2] = n.z; normals[(j + vertex_ofs) * 3 + 2] = n.z;
uv_indices.write[j + vertex_ofs] = Pair<int, int>(i, j); uv_indices[j + vertex_ofs] = Pair<int, int>(i, j);
} }
Vector<int> rindices = arrays[Mesh::ARRAY_INDEX]; PackedInt32Array rindices = arrays[Mesh::ARRAY_INDEX];
int ic = rindices.size(); int ic = rindices.size();
float eps = 1.19209290e-7F; // Taken from xatlas.h
if (ic == 0) { if (ic == 0) {
for (int j = 0; j < vc / 3; j++) { for (int j = 0; j < vc / 3; j++) {
if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) { Vector3 p0 = transform.xform(rvertices[j * 3 + 0]);
Vector3 p1 = transform.xform(rvertices[j * 3 + 1]);
Vector3 p2 = transform.xform(rvertices[j * 3 + 2]);
if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue; continue;
} }
@ -1489,15 +1492,18 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
} }
} else { } else {
const int *ri = rindices.ptr();
for (int j = 0; j < ic / 3; j++) { for (int j = 0; j < ic / 3; j++) {
if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) { Vector3 p0 = transform.xform(rvertices[rindices[j * 3 + 0]]);
Vector3 p1 = transform.xform(rvertices[rindices[j * 3 + 1]]);
Vector3 p2 = transform.xform(rvertices[rindices[j * 3 + 2]]);
if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue; continue;
} }
indices.push_back(vertex_ofs + ri[j * 3 + 0]);
indices.push_back(vertex_ofs + ri[j * 3 + 1]); indices.push_back(vertex_ofs + rindices[j * 3 + 0]);
indices.push_back(vertex_ofs + ri[j * 3 + 2]); indices.push_back(vertex_ofs + rindices[j * 3 + 1]);
indices.push_back(vertex_ofs + rindices[j * 3 + 2]);
} }
} }
@ -1506,6 +1512,9 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
//unwrap //unwrap
bool use_cache = p_generate_cache; // Used to request cache generation and to know if cache was used
uint8_t *gen_cache;
int gen_cache_size;
float *gen_uvs; float *gen_uvs;
int *gen_vertices; int *gen_vertices;
int *gen_indices; int *gen_indices;
@ -1514,17 +1523,16 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
int size_x; int size_x;
int size_y; int size_y;
bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y, r_cache_data, r_cache_size, r_used_cache); bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), p_src_cache.ptr(), &use_cache, &gen_cache, &gen_cache_size, &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y);
if (!ok) { if (!ok) {
return ERR_CANT_CREATE; return ERR_CANT_CREATE;
} }
//remove surfaces
clear_surfaces(); clear_surfaces();
//create surfacetools for each surface.. //create surfacetools for each surface..
Vector<Ref<SurfaceTool>> surfaces_tools; LocalVector<Ref<SurfaceTool>> surfaces_tools;
for (int i = 0; i < lightmap_surfaces.size(); i++) { for (int i = 0; i < lightmap_surfaces.size(); i++) {
Ref<SurfaceTool> st; Ref<SurfaceTool> st;
@ -1535,11 +1543,12 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
} }
print_verbose("Mesh: Gen indices: " + itos(gen_index_count)); print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
//go through all indices //go through all indices
for (int i = 0; i < gen_index_count; i += 3) { for (int i = 0; i < gen_index_count; i += 3) {
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_indices.size(), ERR_BUG); ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], (int)uv_indices.size(), ERR_BUG);
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_indices.size(), ERR_BUG); ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], (int)uv_indices.size(), ERR_BUG);
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_indices.size(), ERR_BUG); ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], (int)uv_indices.size(), ERR_BUG);
ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG); ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG);
@ -1549,48 +1558,53 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second]; SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_COLOR) { if (lightmap_surfaces[surface].format & ARRAY_FORMAT_COLOR) {
surfaces_tools.write[surface]->set_color(v.color); surfaces_tools[surface]->set_color(v.color);
} }
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TEX_UV) { if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TEX_UV) {
surfaces_tools.write[surface]->set_uv(v.uv); surfaces_tools[surface]->set_uv(v.uv);
} }
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_NORMAL) { if (lightmap_surfaces[surface].format & ARRAY_FORMAT_NORMAL) {
surfaces_tools.write[surface]->set_normal(v.normal); surfaces_tools[surface]->set_normal(v.normal);
} }
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TANGENT) { if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TANGENT) {
Plane t; Plane t;
t.normal = v.tangent; t.normal = v.tangent;
t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1; t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
surfaces_tools.write[surface]->set_tangent(t); surfaces_tools[surface]->set_tangent(t);
} }
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_BONES) { if (lightmap_surfaces[surface].format & ARRAY_FORMAT_BONES) {
surfaces_tools.write[surface]->set_bones(v.bones); surfaces_tools[surface]->set_bones(v.bones);
} }
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) { if (lightmap_surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) {
surfaces_tools.write[surface]->set_weights(v.weights); surfaces_tools[surface]->set_weights(v.weights);
} }
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]); Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
surfaces_tools.write[surface]->set_uv2(uv2); surfaces_tools[surface]->set_uv2(uv2);
surfaces_tools.write[surface]->add_vertex(v.vertex); surfaces_tools[surface]->add_vertex(v.vertex);
} }
} }
//generate surfaces //generate surfaces
for (unsigned int i = 0; i < surfaces_tools.size(); i++) {
for (int i = 0; i < surfaces_tools.size(); i++) { surfaces_tools[i]->index();
surfaces_tools.write[i]->index(); surfaces_tools[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), lightmap_surfaces[i].format);
surfaces_tools.write[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), lightmap_surfaces[i].format);
} }
set_lightmap_size_hint(Size2(size_x, size_y)); set_lightmap_size_hint(Size2(size_x, size_y));
if (!r_used_cache) { if (gen_cache_size > 0) {
//free stuff r_dst_cache.resize(gen_cache_size);
::free(gen_vertices); memcpy(r_dst_cache.ptrw(), gen_cache, gen_cache_size);
::free(gen_indices); memfree(gen_cache);
::free(gen_uvs); }
if (!use_cache) {
// Cache was not used, free the buffers
memfree(gen_vertices);
memfree(gen_indices);
memfree(gen_uvs);
} }
return OK; return OK;

View File

@ -263,7 +263,7 @@ public:
void regen_normal_maps(); void regen_normal_maps();
Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05); Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05);
Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform = Transform(), float p_texel_size = 0.05); Error lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache, bool p_generate_cache = true);
virtual void reload_from_file() override; virtual void reload_from_file() override;

View File

@ -1698,6 +1698,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative
} }
render_list_params.uv_offset = Vector2(); render_list_params.uv_offset = Vector2();
render_list_params.force_wireframe = false;
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles
RD::get_singleton()->draw_list_end(); RD::get_singleton()->draw_list_end();

View File

@ -2554,6 +2554,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
light_data.softshadow_angle = angular_diameter; light_data.softshadow_angle = angular_diameter;
light_data.bake_mode = storage->light_get_bake_mode(base);
if (angular_diameter <= 0.0) { if (angular_diameter <= 0.0) {
light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF
@ -2621,6 +2622,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.color[1] = linear_col.g * energy; light_data.color[1] = linear_col.g * energy;
light_data.color[2] = linear_col.b * energy; light_data.color[2] = linear_col.b * energy;
light_data.specular_amount = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0; light_data.specular_amount = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0;
light_data.bake_mode = storage->light_get_bake_mode(base);
float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE)); float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
light_data.inv_radius = 1.0 / radius; light_data.inv_radius = 1.0 / radius;

View File

@ -497,7 +497,7 @@ private:
float soft_shadow_scale; float soft_shadow_scale;
uint32_t mask; uint32_t mask;
float shadow_volumetric_fog_fade; float shadow_volumetric_fog_fade;
uint32_t pad; uint32_t bake_mode;
float projector_rect[4]; float projector_rect[4];
}; };
@ -514,7 +514,8 @@ private:
uint32_t shadow_enabled; uint32_t shadow_enabled;
float fade_from; float fade_from;
float fade_to; float fade_to;
uint32_t pad[3]; uint32_t pad[2];
uint32_t bake_mode;
float shadow_volumetric_fog_fade; float shadow_volumetric_fog_fade;
float shadow_bias[4]; float shadow_bias[4];
float shadow_normal_bias[4]; float shadow_normal_bias[4];

View File

@ -1,3 +1,6 @@
#define LIGHT_BAKE_DISABLED 0
#define LIGHT_BAKE_DYNAMIC 1
#define LIGHT_BAKE_STATIC 2
struct LightData { //this structure needs to be as packed as possible struct LightData { //this structure needs to be as packed as possible
vec3 position; vec3 position;
@ -23,7 +26,7 @@ struct LightData { //this structure needs to be as packed as possible
float soft_shadow_scale; // scales the shadow kernel for blurrier shadows float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
uint mask; uint mask;
float shadow_volumetric_fog_fade; float shadow_volumetric_fog_fade;
uint pad; uint bake_mode;
vec4 projector_rect; //projector rect in srgb decal atlas vec4 projector_rect; //projector rect in srgb decal atlas
}; };
@ -60,7 +63,8 @@ struct DirectionalLightData {
bool shadow_enabled; bool shadow_enabled;
float fade_from; float fade_from;
float fade_to; float fade_to;
uvec3 pad; uvec2 pad;
uint bake_mode;
float shadow_volumetric_fog_fade; float shadow_volumetric_fog_fade;
vec4 shadow_bias; vec4 shadow_bias;
vec4 shadow_normal_bias; vec4 shadow_normal_bias;

View File

@ -1227,6 +1227,10 @@ void main() {
continue; //not masked continue; //not masked
} }
if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
continue; // Statically baked light and object uses lightmap, skip
}
float shadow = 1.0; float shadow = 1.0;
#ifdef USE_SOFT_SHADOWS #ifdef USE_SOFT_SHADOWS
@ -1676,6 +1680,10 @@ void main() {
continue; //not masked continue; //not masked
} }
if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
continue; // Statically baked light and object uses lightmap, skip
}
float shadow = light_process_omni_shadow(light_index, vertex, view); float shadow = light_process_omni_shadow(light_index, vertex, view);
shadow = blur_shadow(shadow); shadow = blur_shadow(shadow);
@ -1749,6 +1757,10 @@ void main() {
continue; //not masked continue; //not masked
} }
if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
continue; // Statically baked light and object uses lightmap, skip
}
float shadow = light_process_spot_shadow(light_index, vertex, view); float shadow = light_process_spot_shadow(light_index, vertex, view);
shadow = blur_shadow(shadow); shadow = blur_shadow(shadow);

View File

@ -2394,7 +2394,7 @@ void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cu
cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid));
} else if (base_type == RS::INSTANCE_LIGHTMAP) { } else if (base_type == RS::INSTANCE_LIGHTMAP) {
cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid));
} else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) { } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) {
bool keep = true; bool keep = true;

View File

@ -472,8 +472,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const Vector2 *src = array.ptr(); const Vector2 *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) { for (int i = 0; i < p_vertex_array_len; i++) {
uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) }; float uv[2] = { src[i].x, src[i].y };
memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 2); memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4);
} }
} break; } break;
case RS::ARRAY_CUSTOM0: case RS::ARRAY_CUSTOM0:

View File

@ -24,10 +24,6 @@ namespace oidn {
float AutoexposureNode::autoexposure(const Image& color) float AutoexposureNode::autoexposure(const Image& color)
{ {
assert(color.format == Format::Float3); assert(color.format == Format::Float3);
// -- GODOT start --
// We don't want to mess with TTB and we don't use autoexposure, so we disable this code
#if 0
// -- GODOT end --
constexpr float key = 0.18f; constexpr float key = 0.18f;
constexpr float eps = 1e-8f; constexpr float eps = 1e-8f;
@ -42,61 +38,66 @@ namespace oidn {
// Compute the average log luminance of the downsampled image // Compute the average log luminance of the downsampled image
using Sum = std::pair<float, int>; using Sum = std::pair<float, int>;
Sum sum = // -- GODOT start --
tbb::parallel_reduce( // Sum sum =
tbb::blocked_range2d<int>(0, HK, 0, WK), // tbb::parallel_reduce(
Sum(0.f, 0), // tbb::blocked_range2d<int>(0, HK, 0, WK),
[&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum // Sum(0.f, 0),
// [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
// {
// // Iterate over blocks
// for (int i = r.rows().begin(); i != r.rows().end(); ++i)
// {
// for (int j = r.cols().begin(); j != r.cols().end(); ++j)
// {
Sum sum = Sum(0.0f, 0);
for (int i = 0; i != HK; ++i)
{
for (int j = 0; j != WK; ++j)
{
// Compute the average luminance in the current block
const int beginH = int(ptrdiff_t(i) * H / HK);
const int beginW = int(ptrdiff_t(j) * W / WK);
const int endH = int(ptrdiff_t(i+1) * H / HK);
const int endW = int(ptrdiff_t(j+1) * W / WK);
float L = 0.f;
for (int h = beginH; h < endH; ++h)
{ {
// Iterate over blocks for (int w = beginW; w < endW; ++w)
for (int i = r.rows().begin(); i != r.rows().end(); ++i)
{ {
for (int j = r.cols().begin(); j != r.cols().end(); ++j) const float* rgb = (const float*)color.get(h, w);
{
// Compute the average luminance in the current block
const int beginH = int(ptrdiff_t(i) * H / HK);
const int beginW = int(ptrdiff_t(j) * W / WK);
const int endH = int(ptrdiff_t(i+1) * H / HK);
const int endW = int(ptrdiff_t(j+1) * W / WK);
float L = 0.f; const float r = maxSafe(rgb[0], 0.f);
const float g = maxSafe(rgb[1], 0.f);
const float b = maxSafe(rgb[2], 0.f);
for (int h = beginH; h < endH; ++h) L += luminance(r, g, b);
{
for (int w = beginW; w < endW; ++w)
{
const float* rgb = (const float*)color.get(h, w);
const float r = maxSafe(rgb[0], 0.f);
const float g = maxSafe(rgb[1], 0.f);
const float b = maxSafe(rgb[2], 0.f);
L += luminance(r, g, b);
}
}
L /= (endH - beginH) * (endW - beginW);
// Accumulate the log luminance
if (L > eps)
{
sum.first += log2(L);
sum.second++;
}
}
} }
}
return sum; L /= (endH - beginH) * (endW - beginW);
},
[](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); }, // Accumulate the log luminance
tbb::static_partitioner() if (L > eps)
); {
sum.first += log2(L);
sum.second++;
}
}
}
// return sum;
// },
// [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
// tbb::static_partitioner()
// );
// -- GODOT end --
return (sum.second > 0) ? (key / exp2(sum.first / float(sum.second))) : 1.f; return (sum.second > 0) ? (key / exp2(sum.first / float(sum.second))) : 1.f;
// -- GODOT start --
#endif
return 1.0;
// -- GODOT end --
} }
} // namespace oidn } // namespace oidn

View File

@ -280,28 +280,58 @@ index 8c2de09..ed8328c 100644
namespace oidn { namespace oidn {
diff --git a/core/transfer_function.cpp b/core/transfer_function.cpp diff --git a/core/transfer_function.cpp b/core/transfer_function.cpp
index 601f814..487f0a9 100644 index 601f814..ce5deca 100644
--- a/core/transfer_function.cpp --- a/core/transfer_function.cpp
+++ b/core/transfer_function.cpp +++ b/core/transfer_function.cpp
@@ -24,6 +24,10 @@ namespace oidn { @@ -38,16 +38,24 @@ namespace oidn {
float AutoexposureNode::autoexposure(const Image& color) // Compute the average log luminance of the downsampled image
{ using Sum = std::pair<float, int>;
assert(color.format == Format::Float3);
+// -- GODOT start --
+// We don't want to mess with TTB and we don't use autoexposure, so we disable this code
+#if 0
+// -- GODOT end --
constexpr float key = 0.18f; - Sum sum =
constexpr float eps = 1e-8f; - tbb::parallel_reduce(
@@ -89,6 +93,10 @@ namespace oidn { - tbb::blocked_range2d<int>(0, HK, 0, WK),
); - Sum(0.f, 0),
- [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
+ // -- GODOT start --
+ // Sum sum =
+ // tbb::parallel_reduce(
+ // tbb::blocked_range2d<int>(0, HK, 0, WK),
+ // Sum(0.f, 0),
+ // [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
+ // {
+ // // Iterate over blocks
+ // for (int i = r.rows().begin(); i != r.rows().end(); ++i)
+ // {
+ // for (int j = r.cols().begin(); j != r.cols().end(); ++j)
+ // {
+
+ Sum sum = Sum(0.0f, 0);
+
+ for (int i = 0; i != HK; ++i)
{
- // Iterate over blocks
- for (int i = r.rows().begin(); i != r.rows().end(); ++i)
- {
- for (int j = r.cols().begin(); j != r.cols().end(); ++j)
+ for (int j = 0; j != WK; ++j)
{
// Compute the average luminance in the current block
const int beginH = int(ptrdiff_t(i) * H / HK);
@@ -82,11 +90,12 @@ namespace oidn {
}
}
- return sum;
- },
- [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
- tbb::static_partitioner()
- );
+ // return sum;
+ // },
+ // [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
+ // tbb::static_partitioner()
+ // );
+ // -- GODOT end --
return (sum.second > 0) ? (key / exp2(sum.first / float(sum.second))) : 1.f; return (sum.second > 0) ? (key / exp2(sum.first / float(sum.second))) : 1.f;
+// -- GODOT start --
+#endif
+ return 1.0;
+// -- GODOT end --
} }
} // namespace oidn