From 27c1e659697c2bc223fa65347948f372b06ddaf9 Mon Sep 17 00:00:00 2001 From: JFonS Date: Fri, 5 Feb 2021 19:12:54 +0100 Subject: [PATCH] Assorted CPU lightmapper fixes - Fix crash when a ray hits a texel with a UV2 coordinate exactly equal to 1.0. - Take BakedLightmap extents into account. - Clear capture data between bakes. - Fix minor issues with seam correction. --- modules/lightmapper_cpu/lightmapper_cpu.cpp | 35 ++++++++--- scene/3d/baked_lightmap.cpp | 67 ++++++++++++++------- scene/3d/baked_lightmap.h | 1 + 3 files changed, 74 insertions(+), 29 deletions(-) diff --git a/modules/lightmapper_cpu/lightmapper_cpu.cpp b/modules/lightmapper_cpu/lightmapper_cpu.cpp index ba07451cdf7..9b4fd8148d7 100644 --- a/modules/lightmapper_cpu/lightmapper_cpu.cpp +++ b/modules/lightmapper_cpu/lightmapper_cpu.cpp @@ -393,11 +393,11 @@ Vector3 LightmapperCPU::_fix_sample_position(const Vector3 &p_position, const Ve Vector3 target = p_texel_center + rotated_offset; Vector3 ray_vector = target - corrected; - Vector3 ray_back_offset = -ray_vector.normalized() * parameters.bias; + Vector3 ray_back_offset = -ray_vector.normalized() * parameters.bias / 2.0; Vector3 ray_origin = corrected + ray_back_offset; ray_vector = target - ray_origin; float ray_length = ray_vector.length(); - LightmapRaycaster::Ray ray(ray_origin + p_normal * parameters.bias, ray_vector.normalized(), 0.0f, ray_length + parameters.bias); + LightmapRaycaster::Ray ray(ray_origin + p_normal * parameters.bias, ray_vector.normalized(), 0.0f, ray_length + parameters.bias / 2.0); bool hit = raycaster->intersect(ray); if (hit) { @@ -476,8 +476,10 @@ void LightmapperCPU::_plot_triangle(const Vector2 *p_vertices, const Vector3 *p_ Vector2 p = centroid; p[i] += 1; Vector3 bary = Geometry::barycentric_coordinates_2d(p, v0, v1, v2); - Vector3 pos = p0 * bary[0] + p1 * bary[1] + p2 * bary[2]; - texel_size[i] = centroid_pos.distance_to(pos); + if (bary.length() <= 1.0) { + Vector3 pos = p0 * bary[0] + p1 * bary[1] + p2 * bary[2]; + texel_size[i] = centroid_pos.distance_to(pos); + } } Vector pixel_polygon; @@ -676,7 +678,7 @@ void LightmapperCPU::_plot_triangle(const Vector2 *p_vertices, const Vector3 *p_ Vector2 texel_center = Vector2(i, j) + Vector2(0.5f, 0.5f); Vector3 texel_center_bary = Geometry::barycentric_coordinates_2d(texel_center, v0, v1, v2); - if (!Math::is_nan(texel_center_bary.x) && !Math::is_nan(texel_center_bary.y) && !Math::is_nan(texel_center_bary.z) && !Math::is_inf(texel_center_bary.x) && !Math::is_inf(texel_center_bary.y) && !Math::is_inf(texel_center_bary.z)) { + if (texel_center_bary.length_squared() <= 1.3 && !Math::is_nan(texel_center_bary.x) && !Math::is_nan(texel_center_bary.y) && !Math::is_nan(texel_center_bary.z) && !Math::is_inf(texel_center_bary.x) && !Math::is_inf(texel_center_bary.y) && !Math::is_inf(texel_center_bary.z)) { Vector3 texel_center_pos = p0 * texel_center_bary[0] + p1 * texel_center_bary[1] + p2 * texel_center_bary[2]; pos = _fix_sample_position(pos, texel_center_pos, normal, tangent, bitangent, texel_size); } @@ -855,8 +857,8 @@ void LightmapperCPU::_compute_indirect_light(uint32_t p_idx, void *r_lightmap) { unsigned int hit_mesh_id = ray.geomID; const Vector2i &size = mesh_instances[hit_mesh_id].size; - int x = ray.u * size.x; - int y = ray.v * size.y; + int x = CLAMP(ray.u * size.x, 0, size.x - 1); + int y = CLAMP(ray.v * size.y, 0, size.y - 1); const int idx = scene_lightmap_indices[hit_mesh_id][y * size.x + x]; @@ -988,7 +990,7 @@ void LightmapperCPU::_post_process(uint32_t p_idx, void *r_output) { void LightmapperCPU::_compute_seams(const MeshInstance &p_mesh, LocalVector &r_seams) { float max_uv_distance = 1.0f / MAX(p_mesh.size.x, p_mesh.size.y); max_uv_distance *= max_uv_distance; // We use distance_to_squared(), so wee need to square the max distance as well - float max_pos_distance = 0.0005f; + float max_pos_distance = 0.00025f; float max_normal_distance = 0.05f; const Vector &points = p_mesh.data.points; @@ -1026,9 +1028,26 @@ void LightmapperCPU::_compute_seams(const MeshInstance &p_mesh, LocalVectorfree(baked_light); + } + baked_light = VS::get_singleton()->lightmap_capture_create(); +} + void BakedLightmapData::_set_user_data(const Array &p_data) { // Detect old lightmapper format @@ -226,6 +234,7 @@ void BakedLightmapData::_bind_methods() { ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path); ClassDB::bind_method(D_METHOD("get_user_lightmap", "user_idx"), &BakedLightmapData::get_user_lightmap); ClassDB::bind_method(D_METHOD("clear_users"), &BakedLightmapData::clear_users); + ClassDB::bind_method(D_METHOD("clear_data"), &BakedLightmapData::clear_data); ADD_PROPERTY(PropertyInfo(Variant::AABB, "bounds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bounds", "get_bounds"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "cell_space_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_space_transform", "get_cell_space_transform"); @@ -317,6 +326,9 @@ Size2i BakedLightmap::_compute_lightmap_size(const MeshesFound &p_mesh) { } void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector &meshes, Vector &lights) { + + AABB bounds = AABB(-extents, extents * 2.0); + MeshInstance *mi = Object::cast_to(p_at_node); if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT) && mi->is_visible_in_tree()) { Ref mesh = mi->get_mesh(); @@ -339,27 +351,34 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector } if (surfaces_found && all_have_uv2_and_normal) { - MeshesFound mf; - mf.cast_shadows = mi->get_cast_shadows_setting() != GeometryInstance::SHADOW_CASTING_SETTING_OFF; - mf.generate_lightmap = mi->get_generate_lightmap(); - mf.xform = get_global_transform().affine_inverse() * mi->get_global_transform(); - mf.node_path = get_path_to(mi); - mf.subindex = -1; - mf.mesh = mesh; - static const int lightmap_scale[4] = { 1, 2, 4, 8 }; //GeometryInstance3D::LIGHTMAP_SCALE_MAX = { 1, 2, 4, 8 }; - mf.lightmap_scale = lightmap_scale[mi->get_lightmap_scale()]; + Transform mesh_xform = get_global_transform().affine_inverse() * mi->get_global_transform(); - Ref all_override = mi->get_material_override(); - for (int i = 0; i < mesh->get_surface_count(); i++) { - if (all_override.is_valid()) { - mf.overrides.push_back(all_override); - } else { - mf.overrides.push_back(mi->get_surface_material(i)); + AABB aabb = mesh_xform.xform(mesh->get_aabb()); + + if (bounds.intersects(aabb)) { + MeshesFound mf; + mf.cast_shadows = mi->get_cast_shadows_setting() != GeometryInstance::SHADOW_CASTING_SETTING_OFF; + mf.generate_lightmap = mi->get_generate_lightmap(); + mf.xform = mesh_xform; + mf.node_path = get_path_to(mi); + mf.subindex = -1; + mf.mesh = mesh; + + static const int lightmap_scale[4] = { 1, 2, 4, 8 }; //GeometryInstance3D::LIGHTMAP_SCALE_MAX = { 1, 2, 4, 8 }; + mf.lightmap_scale = lightmap_scale[mi->get_lightmap_scale()]; + + Ref all_override = mi->get_material_override(); + for (int i = 0; i < mesh->get_surface_count(); i++) { + if (all_override.is_valid()) { + mf.overrides.push_back(all_override); + } else { + mf.overrides.push_back(mi->get_surface_material(i)); + } } - } - meshes.push_back(mf); + meshes.push_back(mf); + } } } } @@ -383,10 +402,16 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector continue; } - MeshesFound mf; + Transform mesh_xform = xf * bmeshes[i + 1]; - Transform mesh_xf = bmeshes[i + 1]; - mf.xform = xf * mesh_xf; + AABB aabb = mesh_xform.xform(mesh->get_aabb()); + + if (!bounds.intersects(aabb)) { + continue; + } + + MeshesFound mf; + mf.xform = mesh_xform; mf.node_path = get_path_to(s); mf.subindex = i / 2; mf.lightmap_scale = 1; @@ -770,7 +795,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa if (get_light_data().is_valid()) { data = get_light_data(); set_light_data(Ref()); //clear - data->clear_users(); + data->clear_data(); } else { data.instance(); } diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h index 33f9a62a57c..8ee9d2dd0af 100644 --- a/scene/3d/baked_lightmap.h +++ b/scene/3d/baked_lightmap.h @@ -91,6 +91,7 @@ public: Rect2 get_user_lightmap_uv_rect(int p_user) const; int get_user_instance(int p_user) const; void clear_users(); + void clear_data(); virtual RID get_rid() const; BakedLightmapData();