Fix #128820: Mask filter behaves incorrectly with hidden faces

The usage of `hide::node_visible_verts` in this function does not work
as intended, as the resulting span is misaligned with the sliced
per-node mask data. To fix this issue, this commit adds a similar helper
function to copy all hidden vert data and applies changes to all of the
node vertices.

Pull Request: https://projects.blender.org/blender/blender/pulls/128828
This commit is contained in:
Sean Kim
2024-10-10 22:40:38 +02:00
committed by Sean Kim
parent 1d11123da7
commit 57c4e9dd2c

View File

@@ -46,6 +46,23 @@ enum class FilterType {
ContrastDecrease = 6,
};
BLI_NOINLINE static void copy_old_hidden_mask_mesh(const Span<int> verts,
const Span<bool> hide_vert,
const Span<float> mask,
const MutableSpan<float> new_mask)
{
BLI_assert(verts.size() == new_mask.size());
if (hide_vert.is_empty()) {
return;
}
for (const int i : verts.index_range()) {
if (hide_vert[verts[i]]) {
new_mask[i] = mask[verts[i]];
}
}
}
BLI_NOINLINE static void multiply_add(const Span<float> src,
const float factor,
const float offset,
@@ -109,7 +126,6 @@ struct FilterLocalData {
static void apply_new_mask_mesh(const Depsgraph &depsgraph,
Object &object,
const Span<bool> hide_vert,
const IndexMask &node_mask,
const OffsetIndices<int> node_verts,
const Span<float> new_mask,
@@ -117,15 +133,13 @@ static void apply_new_mask_mesh(const Depsgraph &depsgraph,
{
bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
MutableSpan<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
threading::EnumerableThreadSpecific<Vector<int>> all_tls;
Array<bool> node_changed(node_mask.min_array_size(), false);
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
Vector<int> &tls = all_tls.local();
const Span<int> verts = hide::node_visible_verts(nodes[i], hide_vert, tls);
const Span<int> verts = nodes[i].verts();
const Span<float> new_node_mask = new_mask.slice(node_verts[pos]);
if (array_utils::indexed_data_equal<float>(mask, verts, new_node_mask)) {
if (array_utils::indexed_data_equal<float>(mask, verts, new_mask)) {
return;
}
undo::push_node(depsgraph, object, &nodes[i], undo::Type::Mask);
@@ -142,6 +156,7 @@ static void smooth_mask_mesh(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const GroupedSpan<int> vert_to_face_map,
const Span<bool> hide_poly,
const Span<bool> hide_vert,
const Span<float> mask,
const bke::pbvh::MeshNode &node,
FilterLocalData &tls,
@@ -154,12 +169,14 @@ static void smooth_mask_mesh(const OffsetIndices<int> faces,
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
smooth::neighbor_data_average_mesh(mask, neighbors, new_mask);
copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
}
static void sharpen_mask_mesh(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const GroupedSpan<int> vert_to_face_map,
const Span<bool> hide_poly,
const Span<bool> hide_vert,
const Span<float> mask,
const bke::pbvh::MeshNode &node,
FilterLocalData &tls,
@@ -178,12 +195,14 @@ static void sharpen_mask_mesh(const OffsetIndices<int> faces,
smooth::neighbor_data_average_mesh(mask, neighbors, new_mask);
sharpen_masks(node_mask, new_mask);
copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
}
static void grow_mask_mesh(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const GroupedSpan<int> vert_to_face_map,
const Span<bool> hide_poly,
const Span<bool> hide_vert,
const Span<float> mask,
const bke::pbvh::MeshNode &node,
FilterLocalData &tls,
@@ -201,12 +220,14 @@ static void grow_mask_mesh(const OffsetIndices<int> faces,
new_mask[i] = std::max(mask[neighbor], new_mask[i]);
}
}
copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
}
static void shrink_mask_mesh(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const GroupedSpan<int> vert_to_face_map,
const Span<bool> hide_poly,
const Span<bool> hide_vert,
const Span<float> mask,
const bke::pbvh::MeshNode &node,
FilterLocalData &tls,
@@ -224,6 +245,7 @@ static void shrink_mask_mesh(const OffsetIndices<int> faces,
new_mask[i] = std::min(mask[neighbor], new_mask[i]);
}
}
copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
}
static bool increase_contrast_mask_mesh(const Depsgraph &depsgraph,
@@ -240,6 +262,7 @@ static bool increase_contrast_mask_mesh(const Depsgraph &depsgraph,
tls.new_mask.resize(verts.size());
const MutableSpan<float> new_mask = tls.new_mask;
mask_increase_contrast(node_mask, new_mask);
copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
if (node_mask == new_mask.as_span()) {
return false;
@@ -265,6 +288,7 @@ static bool decrease_contrast_mask_mesh(const Depsgraph &depsgraph,
tls.new_mask.resize(verts.size());
const MutableSpan<float> new_mask = tls.new_mask;
mask_decrease_contrast(node_mask, new_mask);
copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
if (node_mask == new_mask.as_span()) {
return false;
@@ -721,13 +745,13 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
corner_verts,
vert_to_face_map,
hide_poly,
hide_vert,
mask.span,
nodes[i],
tls,
new_masks.as_mutable_span().slice(node_offsets[pos]));
});
apply_new_mask_mesh(
*depsgraph, ob, hide_vert, node_mask, node_offsets, new_masks, mask.span);
apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
break;
}
case FilterType::Sharpen: {
@@ -737,13 +761,13 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
corner_verts,
vert_to_face_map,
hide_poly,
hide_vert,
mask.span,
nodes[i],
tls,
new_masks.as_mutable_span().slice(node_offsets[pos]));
});
apply_new_mask_mesh(
*depsgraph, ob, hide_vert, node_mask, node_offsets, new_masks, mask.span);
apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
break;
}
case FilterType::Grow: {
@@ -753,13 +777,13 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
corner_verts,
vert_to_face_map,
hide_poly,
hide_vert,
mask.span,
nodes[i],
tls,
new_masks.as_mutable_span().slice(node_offsets[pos]));
});
apply_new_mask_mesh(
*depsgraph, ob, hide_vert, node_mask, node_offsets, new_masks, mask.span);
apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
break;
}
case FilterType::Shrink: {
@@ -769,13 +793,13 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
corner_verts,
vert_to_face_map,
hide_poly,
hide_vert,
mask.span,
nodes[i],
tls,
new_masks.as_mutable_span().slice(node_offsets[pos]));
});
apply_new_mask_mesh(
*depsgraph, ob, hide_vert, node_mask, node_offsets, new_masks, mask.span);
apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
break;
}
case FilterType::ContrastIncrease: {