diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 86e3bb3ed66..ef334b1610b 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -2115,9 +2115,10 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh) /** \name Auto Smooth Conversion * \{ */ +namespace blender::bke { + static bNodeTree *add_auto_smooth_node_tree(Main &bmain) { - using namespace blender; bNodeTree *group = ntreeAddTree(&bmain, DATA_("Auto Smooth"), "GeometryNodeTree"); if (!group->geometry_node_asset_traits) { group->geometry_node_asset_traits = MEM_new(__func__); @@ -2235,65 +2236,96 @@ static bNodeTree *add_auto_smooth_node_tree(Main &bmain) return group; } +static ModifierData *create_auto_smooth_modifier(Object &object, + const FunctionRef get_node_group, + const float angle) +{ + auto *md = reinterpret_cast(BKE_modifier_new(eModifierType_Nodes)); + STRNCPY(md->modifier.name, DATA_("Auto Smooth")); + BKE_modifier_unique_name(&object.modifiers, &md->modifier); + md->node_group = get_node_group(); + + md->settings.properties = idprop::create_group("Nodes Modifier Settings").release(); + IDProperty *angle_prop = idprop::create(DATA_("Socket_1"), angle).release(); + auto *ui_data = reinterpret_cast(IDP_ui_data_ensure(angle_prop)); + ui_data->base.rna_subtype = PROP_ANGLE; + ui_data->soft_min = 0.0f; + ui_data->soft_max = DEG2RADF(180.0f); + IDP_AddToGroup(md->settings.properties, angle_prop); + IDP_AddToGroup(md->settings.properties, + idprop::create(DATA_("Input_1_use_attribute"), 0).release()); + IDP_AddToGroup(md->settings.properties, + idprop::create(DATA_("Input_1_attribute_name"), "").release()); + + BKE_modifiers_persistent_uid_init(object, md->modifier); + return &md->modifier; +} + +} // namespace blender::bke + void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain) { - using namespace blender; - bNodeTree *auto_smooth_node_tree = nullptr; + using namespace blender::bke; + + /* Add the node group lazily and share it among all objects in the main database. */ + bNodeTree *node_group = nullptr; + const auto add_node_group = [&]() { + node_group = add_auto_smooth_node_tree(bmain); + BKE_ntree_update_main_tree(&bmain, node_group, nullptr); + return node_group; + }; + LISTBASE_FOREACH (Object *, object, &bmain.objects) { if (object->type != OB_MESH) { continue; } Mesh *mesh = static_cast(object->data); + const float angle = mesh->smoothresh_legacy; if (!(mesh->flag & ME_AUTOSMOOTH_LEGACY)) { continue; } + mesh->flag &= ~ME_AUTOSMOOTH_LEGACY; + + /* Auto-smooth disabled sharp edge tagging when the evaluated mesh had custom normals. + * When the original mesh has custom normals, that's a good sign the evaluated mesh will + * have custom normals as well. */ if (CustomData_has_layer(&mesh->corner_data, CD_CUSTOMLOOPNORMAL)) { - /* Auto-smooth disabled sharp edge tagging when the evaluated mesh had custom normals. - * When the original mesh has custom normals, that's a good sign the evaluated mesh will - * have custom normals as well. */ continue; } - if (ModifierData *last_md = static_cast(object->modifiers.last)) { + + /* The "Weighted Normal" modifier has a "Keep Sharp" option that used to recalculate the sharp + * edge tags based on the mesh's smoothing angle. To keep the same behavior, a new modifier has + * to be added before that modifier when the option is on. */ + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + if (md->type == eModifierType_WeightedNormal) { + WeightedNormalModifierData *nmd = reinterpret_cast(md); + if ((nmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0) { + ModifierData *new_md = create_auto_smooth_modifier(*object, add_node_group, angle); + BLI_insertlinkbefore(&object->modifiers, object->modifiers.last, new_md); + } + } + } + + /* Some modifiers always generate custom normals which disabled sharp edge tagging, making + * adding a modifier at the end unnecessary. Conceptually this is similar to checking if the + * evaluated mesh had custom normals. */ + ModifierData *last_md = static_cast(object->modifiers.last); + if (last_md) { if (ELEM(last_md->type, eModifierType_WeightedNormal, eModifierType_NormalEdit)) { - /* These modifiers always generate custom normals which disabled sharp edge tagging. */ continue; } } - if (!auto_smooth_node_tree) { - auto_smooth_node_tree = add_auto_smooth_node_tree(bmain); - BKE_ntree_update_main_tree(&bmain, auto_smooth_node_tree, nullptr); - } - auto *md = reinterpret_cast(BKE_modifier_new(eModifierType_Nodes)); - STRNCPY(md->modifier.name, DATA_("Auto Smooth")); - BKE_modifier_unique_name(&object->modifiers, &md->modifier); - md->node_group = auto_smooth_node_tree; - mesh->flag &= ~ME_AUTOSMOOTH_LEGACY; - if (!BLI_listbase_is_empty(&object->modifiers) && - static_cast(object->modifiers.last)->type == eModifierType_Subsurf) - { + ModifierData *new_md = create_auto_smooth_modifier(*object, add_node_group, angle); + if (last_md && last_md->type == eModifierType_Subsurf) { /* Add the auto smooth node group before the last subdivision surface modifier if possible. * Subdivision surface modifiers have special handling for interpolating face corner normals, * and recalculating them afterwards isn't usually helpful and can be much slower. */ - BLI_insertlinkbefore(&object->modifiers, object->modifiers.last, md); + BLI_insertlinkbefore(&object->modifiers, object->modifiers.last, new_md); } else { - BLI_addtail(&object->modifiers, md); + BLI_addtail(&object->modifiers, new_md); } - BKE_modifiers_persistent_uid_init(*object, md->modifier); - - md->settings.properties = bke::idprop::create_group("Nodes Modifier Settings").release(); - IDProperty *angle_prop = - bke::idprop::create(DATA_("Socket_1"), mesh->smoothresh_legacy).release(); - auto *ui_data = reinterpret_cast(IDP_ui_data_ensure(angle_prop)); - ui_data->base.rna_subtype = PROP_ANGLE; - ui_data->soft_min = 0.0f; - ui_data->soft_max = DEG2RADF(180.0f); - IDP_AddToGroup(md->settings.properties, angle_prop); - IDP_AddToGroup(md->settings.properties, - bke::idprop::create(DATA_("Input_1_use_attribute"), 0).release()); - IDP_AddToGroup(md->settings.properties, - bke::idprop::create(DATA_("Input_1_attribute_name"), "").release()); } }