diff --git a/modules/fbx/fbx_document.cpp b/modules/fbx/fbx_document.cpp index 7ad89d1cbc11..81eb2b91a2a4 100644 --- a/modules/fbx/fbx_document.cpp +++ b/modules/fbx/fbx_document.cpp @@ -611,9 +611,50 @@ Error FBXDocument::_parse_meshes(Ref p_state) { array[Mesh::ARRAY_VERTEX] = _decode_vertex_attrib_vec3(fbx_mesh->vertex_position, indices); } - // Normals always exist as they're generated if missing, - // see `ufbx_load_opts.generate_missing_normals`. - Vector normals = _decode_vertex_attrib_vec3(fbx_mesh->vertex_normal, indices); + // Generate normals respecting FBX smoothing groups + Vector normals; + normals.resize(vertex_num); + + HashMap normal_accum_smooth; + HashMap normal_count_smooth; + HashMap normal_accum_faceted; + HashMap normal_count_faceted; + + for (size_t face_idx = 0; face_idx < fbx_mesh->faces.count; face_idx++) { + ufbx_face face = fbx_mesh->faces.data[face_idx]; + + if (face.num_indices >= 3) { + Vector3 v0 = _as_vec3(fbx_mesh->vertex_position[face.index_begin]); + Vector3 v1 = _as_vec3(fbx_mesh->vertex_position[face.index_begin + 1]); + Vector3 v2 = _as_vec3(fbx_mesh->vertex_position[face.index_begin + 2]); + + Vector3 face_normal = Plane(v0, v1, v2).normal; + + bool is_smooth = (face_idx < fbx_mesh->face_smoothing.count) && fbx_mesh->face_smoothing.data[face_idx]; + + HashMap &normal_accum = is_smooth ? normal_accum_smooth : normal_accum_faceted; + HashMap &normal_count = is_smooth ? normal_count_smooth : normal_count_faceted; + + normal_accum[v0] += face_normal; + normal_accum[v1] += face_normal; + normal_accum[v2] += face_normal; + normal_count[v0]++; + normal_count[v1]++; + normal_count[v2]++; + } + } + + for (int i = 0; i < vertex_num; i++) { + Vector3 vertex_pos = _as_vec3(fbx_mesh->vertex_position[indices[i]]); + + if (normal_count_smooth.has(vertex_pos) && normal_count_smooth[vertex_pos] > 0) { + normals.write[i] = (normal_accum_smooth[vertex_pos] / normal_count_smooth[vertex_pos]).normalized(); + } else if (normal_count_faceted.has(vertex_pos) && normal_count_faceted[vertex_pos] > 0) { + normals.write[i] = (normal_accum_faceted[vertex_pos] / normal_count_faceted[vertex_pos]).normalized(); + } else { + normals.write[i] = Vector3(0, 1, 0); + } + } array[Mesh::ARRAY_NORMAL] = normals; if (fbx_mesh->vertex_tangent.exists) { @@ -2053,7 +2094,7 @@ Error FBXDocument::_parse(Ref p_state, const String &p_path, Ref