From 3d7359a38fc50b60c3a22beae5f67bc95be0cb0e Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Wed, 27 Nov 2024 22:03:15 +0100 Subject: [PATCH] Fix #130969: OBJ import shading artifacts when file contains zero-area faces When OBJ file contains vertex normals, this can in some cases confuse the custom loop normals code inside Blender. Since it does not simply just use custom normals, but rather projects them into "lnor space". But that "lnor space" calculation can go haywire sometimes, when degenerate faces are present in the input. Mark zero-area faces as "sharp" before doing custom normals. This will make them not try to share the "smooth fan" lnor space with other faces, and things will look correct. Previously, OBJ importer was (wrongly) always setting all faces as "sharp", which avoided this problem, but caused other issues. Pull Request: https://projects.blender.org/blender/blender/pulls/131041 --- .../wavefront_obj/importer/obj_import_mesh.cc | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc index 256ba9cc1ff..e28a1b00406 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -205,18 +205,16 @@ void MeshFromGeometry::create_faces(Mesh *mesh, bool use_vertex_groups) dverts = mesh->deform_verts_for_write(); } + Span positions = mesh->vert_positions(); MutableSpan face_offsets = mesh->face_offsets_for_write(); MutableSpan corner_verts = mesh->corner_verts_for_write(); bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); bke::SpanAttributeWriter material_indices = attributes.lookup_or_add_for_write_only_span("material_index", bke::AttrDomain::Face); - const bool do_sharp = !has_normals(); - bke::SpanAttributeWriter sharp_faces; - if (do_sharp) { - sharp_faces = attributes.lookup_or_add_for_write_span("sharp_face", - bke::AttrDomain::Face); - } + const bool set_face_sharpness = !has_normals(); + bke::SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_span( + "sharp_face", bke::AttrDomain::Face); int corner_index = 0; @@ -229,9 +227,12 @@ void MeshFromGeometry::create_faces(Mesh *mesh, bool use_vertex_groups) } face_offsets[face_idx] = corner_index; - if (do_sharp) { + if (set_face_sharpness) { + /* If we have no vertex normals, set face sharpness flag based on + * whether smooth shading is off. */ sharp_faces.span[face_idx] = !curr_face.shaded_smooth; } + material_indices.span[face_idx] = curr_face.material_index; /* Importing obj files without any materials would result in negative indices, which is not * supported. */ @@ -257,12 +258,23 @@ void MeshFromGeometry::create_faces(Mesh *mesh, bool use_vertex_groups) corner_index++; } + + if (!set_face_sharpness) { + /* If we do have vertex normals, we do not want to set face sharpness. + * Exception is, if degenerate faces (zero area, with co-colocated + * vertices) are present in the input data; this confuses custom + * corner normals calculation in Blender. Set such faces as sharp, + * they will be not shared across smooth vertex face fans. */ + const float area = bke::mesh::face_area_calc( + positions, corner_verts.slice(face_offsets[face_idx], curr_face.corner_count_)); + if (area < 1.0e-12f) { + sharp_faces.span[face_idx] = true; + } + } } material_indices.finish(); - if (do_sharp) { - sharp_faces.finish(); - } + sharp_faces.finish(); } void MeshFromGeometry::create_vertex_groups(Object *obj)