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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user