* Added a "color boundary" tool that tries to smooth out vcol boundaries

This commit is contained in:
Joseph Eagar 2020-11-03 19:08:37 -08:00
parent 37a657a45f
commit 901654dcbf
7 changed files with 210 additions and 4 deletions

View File

@ -1799,6 +1799,14 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_SPHERE;
break;
case SCULPT_TOOL_VCOL_BOUNDARY:
br->flag &= ~BRUSH_SPACE_ATTEN;
br->spacing = 5;
br->alpha = 0.7f;
br->surface_smooth_shape_preservation = 0.5f;
br->surface_smooth_current_vertex = 0.5f;
br->surface_smooth_iterations = 4;
break;
default:
break;
}
@ -1858,6 +1866,7 @@ void BKE_brush_sculpt_reset(Brush *br)
br->sub_col[2] = 0.005f;
break;
case SCULPT_TOOL_VCOL_BOUNDARY:
case SCULPT_TOOL_SIMPLIFY:
case SCULPT_TOOL_PAINT:
case SCULPT_TOOL_MASK:

View File

@ -697,6 +697,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
brush->sculpt_tool = SCULPT_TOOL_PAINT;
}
brush_name = "Color Boundary";
brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_VCOL_BOUNDARY;
}
brush_name = "Smear";
brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (!brush) {

View File

@ -1512,6 +1512,7 @@ static bool sculpt_tool_needs_original(const char sculpt_tool)
SCULPT_TOOL_DRAW_SHARP,
SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_SMOOTH,
SCULPT_TOOL_VCOL_BOUNDARY,
SCULPT_TOOL_BOUNDARY,
SCULPT_TOOL_POSE);
}
@ -2733,6 +2734,8 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_SMOOTH:
return flip * alpha * pressure * feather;
case SCULPT_TOOL_VCOL_BOUNDARY:
return flip * alpha * pressure * feather;
case SCULPT_TOOL_PINCH:
if (flip > 0.0f) {
@ -6308,6 +6311,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
case SCULPT_TOOL_PAINT:
SCULPT_do_paint_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_VCOL_BOUNDARY:
SCULPT_smooth_vcol_boundary(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SMEAR:
SCULPT_do_smear_brush(sd, ob, nodes, totnode);
break;

View File

@ -519,6 +519,11 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float result[3],
SculptVertRef index);
void SCULPT_smooth_vcol_boundary(Sculpt *sd,
Object *ob,
PBVHNode **nodes,
const int totnode);
void SCULPT_smooth(Sculpt *sd,
Object *ob,
PBVHNode **nodes,

View File

@ -299,8 +299,7 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
}
#ifdef PROXY_ADVANCED
static void do_smooth_brush_task_cb_ex(
void *__restrict userdata,
static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
@ -348,7 +347,7 @@ static void do_smooth_brush_task_cb_ex(
while (ni < MAX_PROXY_NEIGHBORS && p->neighbors[i][ni].node >= 0) {
ProxyKey *key = p->neighbors[i] + ni;
PBVHNode *n2 = ss->pbvh->nodes + key->node;
// printf("%d %d %d %p\n", key->node, key->pindex, ss->pbvh->totnode, n2);
if (key->pindex < 0 || key->pindex >= n2->proxyverts.size) {
@ -675,3 +674,179 @@ void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
0, totnode, &data, SCULPT_do_surface_smooth_brush_displace_task_cb_ex, &settings);
}
}
static void do_smooth_vcol_boundary_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
const Brush *brush = data->brush;
const bool smooth_mask = data->smooth_mask;
float bstrength = data->strength;
PBVHVertexIter vd;
CLAMP(bstrength, 0.0f, 1.0f);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
float avg[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float tot = 0.0f;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (!vd.col) {
continue;
}
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * SCULPT_brush_strength_factor(
ss,
brush,
vd.co,
sqrtf(test.dist),
vd.no,
vd.fno,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
vd.vertex,
thread_id);
madd_v3_v3fl(avg, vd.col, fade);
tot += fade;
}
}
BKE_pbvh_vertex_iter_end;
if (tot == 0.0f) {
return;
}
tot = 1.0f / tot;
mul_v3_fl(avg, tot);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * SCULPT_brush_strength_factor(
ss,
brush,
vd.co,
sqrtf(test.dist),
vd.no,
vd.fno,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
vd.vertex,
thread_id);
if (!vd.col) {
continue;
}
float avg2[3], val[3];
float tot2 = 0.0f;
zero_v3(avg2);
copy_v4_v4(avg, vd.col);
madd_v3_v3fl(avg2, vd.co, 0.5f);
tot2 += 0.5f;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
const float *col = SCULPT_vertex_color_get(ss, ni.vertex);
const float *co = SCULPT_vertex_co_get(ss, ni.vertex);
//simple color metric
float dv[4];
sub_v4_v4v4(dv, col, avg);
float w = (fabs(dv[0]) + fabs(dv[1]) + fabs(dv[2]) + fabs(dv[3])) / 4.0;
//w = 1.0f - w;
//w = fabs(0.5 - w);
w *= w * w;
madd_v3_v3fl(avg2, co, w);
tot2 += w;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (tot2 == 0.0) {
continue;
}
mul_v3_fl(avg2, 1.0 / tot2);
sub_v3_v3v3(val, avg2, vd.co);
madd_v3_v3v3fl(val, vd.co, val, fade);
SCULPT_clip(sd, ss, vd.co, val);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
BKE_pbvh_vertex_iter_end;
}
void SCULPT_smooth_vcol_boundary(Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
const int max_iterations = 4;
const float fract = 1.0f / max_iterations;
PBVHType type = BKE_pbvh_type(ss->pbvh);
int iteration, count;
float last;
CLAMP(bstrength, 0.0f, 1.0f);
count = (int)(bstrength * max_iterations);
last = max_iterations * (bstrength - count * fract);
if (type == PBVH_FACES && !ss->pmap) {
BLI_assert(!"sculpt smooth: pmap missing");
return;
}
if (type != PBVH_BMESH) {
SCULPT_vertex_random_access_ensure(ss);
}
SCULPT_boundary_info_ensure(ob);
#ifdef PROXY_ADVANCED
int datamask = PV_CO | PV_NEIGHBORS | PV_NO | PV_INDEX | PV_MASK;
BKE_pbvh_ensure_proxyarrays(ss, ss->pbvh, nodes, totnode, datamask);
BKE_pbvh_load_proxyarrays(ss->pbvh, nodes, totnode, PV_CO | PV_NO | PV_MASK);
#endif
for (iteration = 0; iteration <= count; iteration++) {
const float strength = (iteration != count) ? 1.0f : last;
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
.smooth_mask = false,
.strength = strength,
};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(
0, totnode, &data, do_smooth_vcol_boundary_brush_task_cb_ex, &settings);
#ifdef PROXY_ADVANCED
BKE_pbvh_gather_proxyarray(ss->pbvh, nodes, totnode);
#endif
}
}

View File

@ -830,6 +830,7 @@ typedef enum eBrushSculptTool {
SCULPT_TOOL_SMEAR = 29,
SCULPT_TOOL_BOUNDARY = 30,
SCULPT_TOOL_DISPLACEMENT_ERASER = 31,
SCULPT_TOOL_VCOL_BOUNDARY = 32,
} eBrushSculptTool;
/* Brush.uv_sculpt_tool */
@ -872,6 +873,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_ELASTIC_DEFORM, \
SCULPT_TOOL_POSE, \
SCULPT_TOOL_PAINT, \
SCULPT_TOOL_VCOL_BOUNDARY, \
SCULPT_TOOL_DRAW_FACE_SETS, \
SCULPT_TOOL_SMEAR, \
\

View File

@ -136,7 +136,8 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_SCULPT_DRAW, "Paint", ""},
{SCULPT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SCULPT_DRAW, "Smear", ""},
{SCULPT_TOOL_DRAW_FACE_SETS, "DRAW_FACE_SETS", ICON_BRUSH_MASK, "Draw Face Sets", ""},
{0, NULL, 0, NULL, NULL},
{SCULPT_TOOL_VCOL_BOUNDARY, "VCOL_BOUNDARY", ICON_BRUSH_MASK, "Color Boundary", ""},
{0, NULL, 0, NULL, NULL},
};
/* clang-format on */