Fix Sculpt Relax operation when deforming mesh boundaries
Previously, mesh boundaries were relaxed as any other vertex, which was causing artifacts and unwanted deformation. In order to prevent this, the mesh filter was using the automasking system to lock the boundary vertices, which was hacked into the tool. For the brush, the only solution was to enable boundary automasking to lock those vertices in plance. Now the relax vertex function slides the boundary vertices along the mesh boundary edges, relaxing all the topology correctly while preserving the shape of the mesh. The automasking hack in the relax mesh filter was also removed as now vertices slide correctly along the boundary. Reviewed By: sergey Differential Revision: https://developer.blender.org/D8350
This commit is contained in:
parent
0006526952
commit
221604cdd6
Notes:
blender-bot
2023-02-14 08:24:03 +01:00
Referenced by issue #79190, Cycles PMJ adaptive sampling working poorly with many bounces
|
@ -3147,21 +3147,49 @@ void SCULPT_relax_vertex(SculptSession *ss,
|
|||
{
|
||||
float smooth_pos[3];
|
||||
float final_disp[3];
|
||||
int count = 0;
|
||||
float boundary_normal[3];
|
||||
int avg_count = 0;
|
||||
int neighbor_count = 0;
|
||||
zero_v3(smooth_pos);
|
||||
zero_v3(boundary_normal);
|
||||
const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
|
||||
|
||||
SculptVertexNeighborIter ni;
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
|
||||
neighbor_count++;
|
||||
if (!filter_boundary_face_sets ||
|
||||
(filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
|
||||
add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
|
||||
count++;
|
||||
|
||||
/* When the vertex to relax is boundary, use only connected boundary vertices for the average
|
||||
* position. */
|
||||
if (is_boundary) {
|
||||
if (SCULPT_vertex_is_boundary(ss, ni.index)) {
|
||||
add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
|
||||
avg_count++;
|
||||
|
||||
/* Calculate a normal for the constraint plane using the edges of the boundary. */
|
||||
float to_neighbor[3];
|
||||
sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
|
||||
normalize_v3(to_neighbor);
|
||||
add_v3_v3(boundary_normal, to_neighbor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
|
||||
avg_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
|
||||
|
||||
if (count > 0) {
|
||||
mul_v3_fl(smooth_pos, 1.0f / (float)count);
|
||||
/* Don't modify corner vertices. */
|
||||
if (neighbor_count <= 2) {
|
||||
copy_v3_v3(r_final_pos, vd->co);
|
||||
return;
|
||||
}
|
||||
|
||||
if (avg_count > 0) {
|
||||
mul_v3_fl(smooth_pos, 1.0f / (float)avg_count);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(r_final_pos, vd->co);
|
||||
|
@ -3171,11 +3199,12 @@ void SCULPT_relax_vertex(SculptSession *ss,
|
|||
float plane[4];
|
||||
float smooth_closest_plane[3];
|
||||
float vno[3];
|
||||
if (vd->no) {
|
||||
normal_short_to_float_v3(vno, vd->no);
|
||||
|
||||
if (is_boundary && avg_count == 2) {
|
||||
normalize_v3_v3(vno, boundary_normal);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(vno, vd->fno);
|
||||
SCULPT_vertex_normal_get(ss, vd->index, vno);
|
||||
}
|
||||
|
||||
if (is_zero_v3(vno)) {
|
||||
|
@ -3256,6 +3285,7 @@ static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
|
|||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
|
||||
if (ss->cache->alt_smooth) {
|
||||
SCULPT_boundary_info_ensure(ob);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
|
||||
}
|
||||
|
|
|
@ -205,6 +205,7 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
|
|||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
|
||||
if (ss->cache->alt_smooth) {
|
||||
SCULPT_boundary_info_ensure(ob);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings);
|
||||
}
|
||||
|
|
|
@ -310,8 +310,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
|
|||
break;
|
||||
}
|
||||
case MESH_FILTER_RELAX: {
|
||||
SCULPT_relax_vertex(
|
||||
ss, &vd, clamp_f(fade * ss->filter_cache->automask[vd.index], 0.0f, 1.0f), false, val);
|
||||
SCULPT_relax_vertex(ss, &vd, clamp_f(fade, 0.0f, 1.0f), false, val);
|
||||
sub_v3_v3v3(disp, val, vd.co);
|
||||
break;
|
||||
}
|
||||
|
@ -543,6 +542,10 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
|
|||
|
||||
SCULPT_undo_push_begin("Mesh filter");
|
||||
|
||||
if (ELEM(filter_type, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
|
||||
SCULPT_boundary_info_ensure(ob);
|
||||
}
|
||||
|
||||
SCULPT_filter_cache_init(ob, sd, SCULPT_UNDO_COORDS);
|
||||
|
||||
if (use_face_sets) {
|
||||
|
@ -572,16 +575,6 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
|
|||
ss->filter_cache->enabled_axis[1] = deform_axis & MESH_FILTER_DEFORM_Y;
|
||||
ss->filter_cache->enabled_axis[2] = deform_axis & MESH_FILTER_DEFORM_Z;
|
||||
|
||||
if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_RELAX) {
|
||||
ss->filter_cache->automask = MEM_mallocN(totvert * sizeof(float),
|
||||
"Relax filter edge automask");
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
ss->filter_cache->automask[i] = 1.0f;
|
||||
}
|
||||
SCULPT_boundary_automasking_init(
|
||||
ob, AUTOMASK_INIT_BOUNDARY_EDGES, 1, ss->filter_cache->automask);
|
||||
}
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue