Fix #119398: Weighted normal modifier "Keep Sharp" option missing versioning

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, an auto smooth versioning modifier has to
be added before that modifier when the option is on.

Pull Request: https://projects.blender.org/blender/blender/pulls/119400
This commit is contained in:
Hans Goudey
2024-03-12 22:08:19 +01:00
committed by Hans Goudey
parent b7b7d3a937
commit 9141a8cb25
@@ -2117,9 +2117,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<GeometryNodeAssetTraits>(__func__);
@@ -2237,65 +2238,96 @@ static bNodeTree *add_auto_smooth_node_tree(Main &bmain)
return group;
}
static ModifierData *create_auto_smooth_modifier(Object &object,
const FunctionRef<bNodeTree *()> get_node_group,
const float angle)
{
auto *md = reinterpret_cast<NodesModifierData *>(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<IDPropertyUIDataFloat *>(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<Mesh *>(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<ModifierData *>(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<WeightedNormalModifierData *>(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<ModifierData *>(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<NodesModifierData *>(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<ModifierData *>(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<IDPropertyUIDataFloat *>(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());
}
}