Make weight paint blur thread safe, and fix smear ignoring mirror.

Instead of trying to be clever with swaps and lazy updating the weight
data, simply recalculate one single array. To improve performance, use
threading for that.
This commit is contained in:
Alexander Gavrilov 2017-10-07 12:45:21 +03:00
parent 83ce02879f
commit 6b8abefcc6
1 changed files with 40 additions and 37 deletions

View File

@ -1197,11 +1197,9 @@ struct WPaintData {
int defbase_tot;
/* Special storage for smear brush, avoid feedback loop - update each step and swap. */
struct {
float *weight_prev;
float *weight_curr;
} smear;
/* original weight values for use in blur/smear */
float *precomputed_weight;
bool precomputed_weight_ready;
};
/* Initialize the stroke cache invariants from operator properties */
@ -1427,24 +1425,8 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
wpd->mirror.lock = tmpflags;
}
if (vp->paint.brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
wpd->smear.weight_prev = MEM_mallocN(sizeof(float) * me->totvert, __func__);
const MDeformVert *dv = me->dvert;
if (wpd->do_multipaint) {
const bool do_auto_normalize = ((ts->auto_normalize != 0) && (wpd->vgroup_validmap != NULL));
for (int i = 0; i < me->totvert; i++, dv++) {
float weight = BKE_defvert_multipaint_collective_weight(
dv, wpd->defbase_tot, wpd->defbase_sel, wpd->defbase_tot_sel, do_auto_normalize);
CLAMP(weight, 0.0f, 1.0f);
wpd->smear.weight_prev[i] = weight;
}
}
else {
for (int i = 0; i < me->totvert; i++, dv++) {
wpd->smear.weight_prev[i] = defvert_find_weight(dv, wpd->active.index);
}
}
wpd->smear.weight_curr = MEM_dupallocN(wpd->smear.weight_prev);
if (ELEM(vp->paint.brush->vertexpaint_tool, PAINT_BLEND_SMEAR, PAINT_BLEND_BLUR)) {
wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
}
/* imat for normals */
@ -1502,6 +1484,33 @@ static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintIn
}
}
static void do_wpaint_precompute_weight_cb_ex(
void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
{
SculptThreadedTaskData *data = userdata;
const MDeformVert *dv = &data->me->dvert[n];
data->wpd->precomputed_weight[n] = wpaint_get_active_weight(dv, data->wpi);
}
static void precompute_weight_values(
bContext *C, Object *ob, Brush *brush, struct WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me)
{
if (wpd->precomputed_weight_ready && (brush->flag & BRUSH_ACCUMULATE) == 0)
return;
/* threaded loop over vertices */
SculptThreadedTaskData data = {
.C = C, .ob = ob, .wpd = wpd, .wpi = wpi, .me = me,
};
BLI_task_parallel_range_ex(
0, me->totvert, &data, NULL, 0, do_wpaint_precompute_weight_cb_ex,
true, false);
wpd->precomputed_weight_ready = true;
}
static void do_wpaint_brush_blur_task_cb_ex(
void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
{
@ -1550,8 +1559,7 @@ static void do_wpaint_brush_blur_task_cb_ex(
for (int k = 0; k < mp->totloop; k++) {
const int l_index = mp->loopstart + k;
const MLoop *ml = &data->me->mloop[l_index];
const MDeformVert *dv = &data->me->dvert[ml->v];
weight_final += wpaint_get_active_weight(dv, data->wpi);
weight_final += data->wpd->precomputed_weight[ml->v];
}
}
@ -1671,7 +1679,7 @@ static void do_wpaint_brush_smear_task_cb_ex(
if (stroke_dot > stroke_dot_max) {
stroke_dot_max = stroke_dot;
weight_final = data->wpd->smear.weight_prev[v_other_index];
weight_final = data->wpd->precomputed_weight[v_other_index];
do_color = true;
}
}
@ -1686,9 +1694,6 @@ static void do_wpaint_brush_smear_task_cb_ex(
do_weight_paint_vertex(
data->vp, data->ob, data->wpi,
v_index, final_alpha, (float)weight_final);
/* Access the weight again because it might not have been applied completely. */
data->wpd->smear.weight_curr[v_index] =
wpaint_get_active_weight(&data->me->dvert[v_index], data->wpi);
}
}
}
@ -2054,14 +2059,14 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
wpi.brush_alpha_value = brush_alpha_value;
/* *** done setting up WeightPaintInfo *** */
if (wpd->precomputed_weight) {
precompute_weight_values(C, ob, brush, wpd, &wpi, ob->data);
}
wpaint_do_symmetrical_brush_actions(C, ob, wp, sd, wpd, &wpi);
swap_m4m4(vc->rv3d->persmat, mat);
if (wp->paint.brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
SWAP(float *, wpd->smear.weight_curr, wpd->smear.weight_prev);
}
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
paint_last_stroke_update(scene, vc->ar, mval);
@ -2109,10 +2114,8 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN((void *)wpd->active.lock);
if (wpd->mirror.lock)
MEM_freeN((void *)wpd->mirror.lock);
if (wpd->smear.weight_prev)
MEM_freeN(wpd->smear.weight_prev);
if (wpd->smear.weight_curr)
MEM_freeN(wpd->smear.weight_curr);
if (wpd->precomputed_weight)
MEM_freeN(wpd->precomputed_weight);
MEM_freeN(wpd);
}