Refactor: Sculpt: Refactor relax mesh filter

Part of #118145.
This is an intermediate step. Next the relax functions will be shared
with the brush. For now just getting rid of the iteration macro is
worth it.

Pull Request: https://projects.blender.org/blender/blender/pulls/126099
This commit is contained in:
Hans Goudey
2024-08-08 18:19:54 +02:00
committed by Hans Goudey
parent 0e2ef7f6f1
commit f09395c69e

View File

@@ -998,117 +998,359 @@ static void calc_random_filter(const Sculpt &sd,
}
}
static void calc_relax_filter(const Sculpt & /*sd*/,
static void calc_relax_filter(const Sculpt &sd,
const float strength,
Object &object,
const Span<bke::pbvh::Node *> nodes)
{
struct LocalData {
Vector<float> factors;
Vector<float3> positions;
Vector<float3> new_positions;
Vector<float3> translations;
};
SculptSession &ss = *object.sculpt;
bke::pbvh::update_normals(*ss.pbvh, ss.subdiv_ccg);
switch (ss.pbvh->type()) {
case bke::pbvh::Type::Mesh: {
Mesh &mesh = *static_cast<Mesh *>(object.data);
const Span<float3> positions_eval = BKE_pbvh_get_vert_positions(*ss.pbvh);
MutableSpan<float3> positions_orig = mesh.vert_positions_for_write();
threading::EnumerableThreadSpecific<LocalData> all_tls;
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
LocalData &tls = all_tls.local();
for (const int node_index : range) {
const Span<int> verts = bke::pbvh::node_unique_verts(*nodes[node_index]);
const Span<float3> positions = gather_data_mesh(positions_eval, verts, tls.positions);
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (const int i : range) {
SculptOrigVertData orig_data = SCULPT_orig_vert_data_init(
object, *nodes[i], undo::Type::Position);
auto_mask::NodeData automask_data = auto_mask::node_begin(
object, ss.filter_cache->automasking.get(), *nodes[i]);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (*ss.pbvh, nodes[i], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(orig_data, vd);
auto_mask::node_update(automask_data, vd);
float3 orig_co, val, disp, final_pos;
float fade = vd.mask;
fade = 1.0f - fade;
fade *= strength;
fade *= auto_mask::factor_get(
ss.filter_cache->automasking.get(), ss, vd.vertex, &automask_data);
if (fade == 0.0f) {
continue;
}
orig_co = vd.co;
smooth::relax_vertex(ss, vd.vertex, clamp_f(fade, 0.0f, 1.0f), false, val);
disp = val - float3(vd.co);
disp = to_orientation_space(*ss.filter_cache) * disp;
for (int it = 0; it < 3; it++) {
if (!ss.filter_cache->enabled_axis[it]) {
disp[it] = 0.0f;
tls.factors.resize(verts.size());
const MutableSpan<float> factors = tls.factors;
fill_factor_from_hide_and_mask(mesh, verts, factors);
if (ss.filter_cache->automasking) {
auto_mask::calc_vert_factors(
object, *ss.filter_cache->automasking, *nodes[node_index], verts, factors);
}
}
disp = to_object_space(*ss.filter_cache) * disp;
scale_factors(factors, strength);
clamp_factors(factors, 0.0f, 1.0f);
final_pos = orig_co + disp;
copy_v3_v3(vd.co, final_pos);
}
BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_positions_update(nodes[i]);
tls.new_positions.resize(verts.size());
const MutableSpan<float3> new_positions = tls.new_positions;
for (const int i : verts.index_range()) {
smooth::relax_vertex(ss, PBVHVertRef{verts[i]}, factors[i], false, new_positions[i]);
}
tls.translations.resize(verts.size());
const MutableSpan<float3> translations = tls.translations;
translations_from_new_positions(new_positions, positions, translations);
zero_disabled_axis_components(*ss.filter_cache, translations);
write_translations(sd, object, positions_eval, verts, translations, positions_orig);
BKE_pbvh_node_mark_positions_update(nodes[node_index]);
}
});
break;
}
});
case bke::pbvh::Type::Grids: {
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
threading::EnumerableThreadSpecific<LocalData> all_tls;
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
LocalData &tls = all_tls.local();
for (const int node_index : range) {
const Span<int> grids = bke::pbvh::node_grid_indices(*nodes[node_index]);
const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
tls.factors.resize(positions.size());
const MutableSpan<float> factors = tls.factors;
fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
if (ss.filter_cache->automasking) {
auto_mask::calc_grids_factors(
object, *ss.filter_cache->automasking, *nodes[node_index], grids, factors);
}
scale_factors(factors, strength);
clamp_factors(factors, 0.0f, 1.0f);
tls.new_positions.resize(positions.size());
const MutableSpan<float3> new_positions = tls.new_positions;
{
for (const int i : grids.index_range()) {
const int node_start = i * key.grid_area;
const int grid = grids[i];
const int start = grid * key.grid_area;
for (const int offset : IndexRange(key.grid_area)) {
const int node_vert = node_start + offset;
const int vert = start + offset;
smooth::relax_vertex(
ss, PBVHVertRef{vert}, factors[node_vert], false, new_positions[node_vert]);
}
}
}
tls.translations.resize(positions.size());
const MutableSpan<float3> translations = tls.translations;
translations_from_new_positions(new_positions, positions, translations);
zero_disabled_axis_components(*ss.filter_cache, translations);
clip_and_lock_translations(sd, ss, positions, translations);
apply_translations(translations, grids, subdiv_ccg);
BKE_pbvh_node_mark_positions_update(nodes[node_index]);
}
});
break;
}
case bke::pbvh::Type::BMesh: {
BMesh &bm = *ss.bm;
threading::EnumerableThreadSpecific<LocalData> all_tls;
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
LocalData &tls = all_tls.local();
for (const int node_index : range) {
const Set<BMVert *, 0> &verts = BKE_pbvh_bmesh_node_unique_verts(nodes[node_index]);
const Span<float3> positions = gather_bmesh_positions(verts, tls.positions);
tls.factors.resize(verts.size());
const MutableSpan<float> factors = tls.factors;
fill_factor_from_hide_and_mask(bm, verts, factors);
if (ss.filter_cache->automasking) {
auto_mask::calc_vert_factors(
object, *ss.filter_cache->automasking, *nodes[node_index], verts, factors);
}
scale_factors(factors, strength);
clamp_factors(factors, 0.0f, 1.0f);
tls.new_positions.resize(verts.size());
const MutableSpan<float3> new_positions = tls.new_positions;
{
int i = 0;
for (BMVert *vert : verts) {
smooth::relax_vertex(
ss, PBVHVertRef{intptr_t(vert)}, factors[i], false, new_positions[i]);
i++;
}
}
tls.translations.resize(verts.size());
const MutableSpan<float3> translations = tls.translations;
translations_from_new_positions(new_positions, positions, translations);
zero_disabled_axis_components(*ss.filter_cache, translations);
clip_and_lock_translations(sd, ss, positions, translations);
apply_translations(translations, verts);
BKE_pbvh_node_mark_positions_update(nodes[node_index]);
}
});
break;
}
}
}
static void calc_relax_face_sets_filter(const Sculpt & /*sd*/,
static void calc_relax_face_sets_filter(const Sculpt &sd,
const float strength,
Object &object,
const Span<bke::pbvh::Node *> nodes)
{
struct LocalData {
Vector<float> factors;
Vector<float3> positions;
Vector<float3> new_positions;
Vector<float3> translations;
};
SculptSession &ss = *object.sculpt;
bke::pbvh::update_normals(*ss.pbvh, ss.subdiv_ccg);
/* When using the relax face sets meshes filter,
* each 3 iterations, do a whole mesh relax to smooth the contents of the Face Set. */
/* This produces better results as the relax operation is no completely focused on the
* boundaries. */
/* When using the relax face sets meshes filter, each 3 iterations, do a whole mesh relax to
* smooth the contents of the Face Set. This produces better results as the relax operation is no
* completely focused on the boundaries. */
const bool relax_face_sets = !(ss.filter_cache->iteration_count % 3 == 0);
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (const int i : range) {
SculptOrigVertData orig_data = SCULPT_orig_vert_data_init(
object, *nodes[i], undo::Type::Position);
switch (ss.pbvh->type()) {
case bke::pbvh::Type::Mesh: {
Mesh &mesh = *static_cast<Mesh *>(object.data);
const Span<float3> positions_eval = BKE_pbvh_get_vert_positions(*ss.pbvh);
MutableSpan<float3> positions_orig = mesh.vert_positions_for_write();
const GroupedSpan<int> vert_to_face_map = ss.vert_to_face_map;
threading::EnumerableThreadSpecific<LocalData> all_tls;
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
LocalData &tls = all_tls.local();
for (const int node_index : range) {
const Span<int> verts = bke::pbvh::node_unique_verts(*nodes[node_index]);
const Span<float3> positions = gather_data_mesh(positions_eval, verts, tls.positions);
auto_mask::NodeData automask_data = auto_mask::node_begin(
object, ss.filter_cache->automasking.get(), *nodes[i]);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (*ss.pbvh, nodes[i], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(orig_data, vd);
auto_mask::node_update(automask_data, vd);
float3 orig_co, val, disp, final_pos;
float fade = vd.mask;
fade = 1.0f - fade;
fade *= strength;
fade *= auto_mask::factor_get(
ss.filter_cache->automasking.get(), ss, vd.vertex, &automask_data);
if (fade == 0.0f) {
continue;
}
orig_co = vd.co;
if (relax_face_sets == face_set::vert_has_unique_face_set(ss, vd.vertex)) {
continue;
}
smooth::relax_vertex(ss, vd.vertex, clamp_f(fade, 0.0f, 1.0f), relax_face_sets, val);
disp = val - float3(vd.co);
disp = to_orientation_space(*ss.filter_cache) * disp;
for (int it = 0; it < 3; it++) {
if (!ss.filter_cache->enabled_axis[it]) {
disp[it] = 0.0f;
tls.factors.resize(verts.size());
const MutableSpan<float> factors = tls.factors;
fill_factor_from_hide_and_mask(mesh, verts, factors);
if (ss.filter_cache->automasking) {
auto_mask::calc_vert_factors(
object, *ss.filter_cache->automasking, *nodes[node_index], verts, factors);
}
}
disp = to_object_space(*ss.filter_cache) * disp;
scale_factors(factors, strength);
clamp_factors(factors, 0.0f, 1.0f);
final_pos = orig_co + disp;
copy_v3_v3(vd.co, final_pos);
}
BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_positions_update(nodes[i]);
for (const int i : verts.index_range()) {
if (relax_face_sets ==
face_set::vert_has_unique_face_set(vert_to_face_map, ss.face_sets, verts[i]))
{
factors[i] = 0.0f;
}
}
tls.new_positions.resize(verts.size());
const MutableSpan<float3> new_positions = tls.new_positions;
for (const int i : verts.index_range()) {
if (factors[i] == 0.0f) {
new_positions[i] = positions[i];
continue;
}
smooth::relax_vertex(
ss, PBVHVertRef{verts[i]}, factors[i], relax_face_sets, new_positions[i]);
}
tls.translations.resize(verts.size());
const MutableSpan<float3> translations = tls.translations;
translations_from_new_positions(new_positions, positions, translations);
zero_disabled_axis_components(*ss.filter_cache, translations);
write_translations(sd, object, positions_eval, verts, translations, positions_orig);
BKE_pbvh_node_mark_positions_update(nodes[node_index]);
}
});
break;
}
});
case bke::pbvh::Type::Grids: {
const Mesh &base_mesh = *static_cast<const Mesh *>(object.data);
const OffsetIndices faces = base_mesh.faces();
const Span<int> corner_verts = base_mesh.corner_verts();
const GroupedSpan<int> vert_to_face_map = base_mesh.vert_to_face_map();
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
threading::EnumerableThreadSpecific<LocalData> all_tls;
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
LocalData &tls = all_tls.local();
for (const int node_index : range) {
const Span<int> grids = bke::pbvh::node_grid_indices(*nodes[node_index]);
const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
tls.factors.resize(positions.size());
const MutableSpan<float> factors = tls.factors;
fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
if (ss.filter_cache->automasking) {
auto_mask::calc_grids_factors(
object, *ss.filter_cache->automasking, *nodes[node_index], grids, factors);
}
scale_factors(factors, strength);
clamp_factors(factors, 0.0f, 1.0f);
for (const int i : grids.index_range()) {
const int node_start = i * key.grid_area;
const int grid = grids[i];
for (const short y : IndexRange(key.grid_size)) {
for (const short x : IndexRange(key.grid_size)) {
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
const int node_vert = node_start + offset;
if (relax_face_sets ==
face_set::vert_has_unique_face_set(vert_to_face_map,
corner_verts,
faces,
ss.face_sets,
subdiv_ccg,
SubdivCCGCoord{grid, x, y}))
{
factors[node_vert] = 0.0f;
}
}
}
}
tls.new_positions.resize(positions.size());
const MutableSpan<float3> new_positions = tls.new_positions;
{
for (const int i : grids.index_range()) {
const int node_start = i * key.grid_area;
const int grid = grids[i];
const int start = grid * key.grid_area;
for (const int offset : IndexRange(key.grid_area)) {
const int node_vert = node_start + offset;
const int vert = start + offset;
if (factors[node_vert] == 0.0f) {
new_positions[node_vert] = positions[node_vert];
continue;
}
smooth::relax_vertex(ss,
PBVHVertRef{vert},
factors[node_vert],
relax_face_sets,
new_positions[node_vert]);
}
}
}
tls.translations.resize(positions.size());
const MutableSpan<float3> translations = tls.translations;
translations_from_new_positions(new_positions, positions, translations);
zero_disabled_axis_components(*ss.filter_cache, translations);
clip_and_lock_translations(sd, ss, positions, translations);
apply_translations(translations, grids, subdiv_ccg);
BKE_pbvh_node_mark_positions_update(nodes[node_index]);
}
});
break;
}
case bke::pbvh::Type::BMesh: {
BMesh &bm = *ss.bm;
threading::EnumerableThreadSpecific<LocalData> all_tls;
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
LocalData &tls = all_tls.local();
for (const int node_index : range) {
const Set<BMVert *, 0> &verts = BKE_pbvh_bmesh_node_unique_verts(nodes[node_index]);
const Span<float3> positions = gather_bmesh_positions(verts, tls.positions);
tls.factors.resize(verts.size());
const MutableSpan<float> factors = tls.factors;
fill_factor_from_hide_and_mask(bm, verts, factors);
if (ss.filter_cache->automasking) {
auto_mask::calc_vert_factors(
object, *ss.filter_cache->automasking, *nodes[node_index], verts, factors);
}
scale_factors(factors, strength);
clamp_factors(factors, 0.0f, 1.0f);
int i = 0;
for (BMVert *vert : verts) {
if (relax_face_sets == face_set::vert_has_unique_face_set(vert)) {
factors[i] = 0.0f;
}
i++;
}
tls.new_positions.resize(verts.size());
const MutableSpan<float3> new_positions = tls.new_positions;
{
int i = 0;
for (BMVert *vert : verts) {
if (factors[i] == 0.0f) {
new_positions[i] = positions[i];
i++;
continue;
}
smooth::relax_vertex(
ss, PBVHVertRef{intptr_t(vert)}, factors[i], relax_face_sets, new_positions[i]);
i++;
}
}
tls.translations.resize(verts.size());
const MutableSpan<float3> translations = tls.translations;
translations_from_new_positions(new_positions, positions, translations);
zero_disabled_axis_components(*ss.filter_cache, translations);
clip_and_lock_translations(sd, ss, positions, translations);
apply_translations(translations, verts);
BKE_pbvh_node_mark_positions_update(nodes[node_index]);
}
});
break;
}
}
}
static void calc_surface_smooth_filter(const Sculpt &sd,