Sculpt: Implement accumulate for paint and

other fixes

* The paint brush now supports accumulate.
* Fixed bug with PBVH_FACES not setting
  MSculptVert update flags correctly in
  face set draw brush.
* Topology rake now has a mode where it
  simply propegates directions from
  boundaries.
This commit is contained in:
Joseph Eagar 2021-10-18 03:44:32 -07:00
parent a55b58476e
commit 5cc582fec7
8 changed files with 49 additions and 73 deletions

View File

@ -218,6 +218,7 @@ places in rna_engine_codebase are relevent:
MAKE_ENUM(topology_rake_mode, "Topology Rake Mode", "", 1, {
{0, "BRUSH_DIRECTION", "NONE", "Stroke", "Stroke Direction"},
{1, "CURVATURE", "NONE", "Curvature", "Follow mesh curvature"},
{2, "NONE", "NONE", "Boundary Only", "Boundaries only"},
{-1}
})

View File

@ -1466,30 +1466,7 @@ static float maskcb_get(EdgeQueueContext *eq_ctx, BMEdge *e)
static float calc_weighted_edge_split(EdgeQueueContext *eq_ctx, BMVert *v1, BMVert *v2)
{
#ifdef FANCY_EDGE_WEIGHTS
float l = len_squared_v3v3(v1->co, v2->co);
// float val = (float)BM_vert_edge_count(v1) + (float)BM_vert_edge_count(v2);
MSculptVert *mv1 = BKE_PBVH_SCULPTVERT(eq_ctx->cd_sculpt_vert, v1);
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(eq_ctx->cd_sculpt_vert, v2);
float val = (float)(mv1->valence + mv2->valence) * 0.5f;
val -= 6.0f;
val = MAX2(val, 1.0f);
// val = powf(val, 0.5);
l *= val;
return l;
#elif 0 // penalize 4-valence verts
float l = len_squared_v3v3(v1->co, v2->co);
if (BM_vert_edge_count(v1) == 4 || BM_vert_edge_count(v2) == 4) {
l *= 0.25f;
}
return l;
#else
# ifdef WITH_ADAPTIVE_CURVATURE
#ifdef WITH_ADAPTIVE_CURVATURE
MSculptVert *mv1 = BKE_PBVH_SCULPTVERT(eq_ctx->cd_sculpt_vert, v1);
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(eq_ctx->cd_sculpt_vert, v2);
@ -1499,33 +1476,25 @@ static float calc_weighted_edge_split(EdgeQueueContext *eq_ctx, BMVert *v1, BMVe
fac = min_ff(fac, 4.0f);
return fac * len_squared_v3v3(v1->co, v2->co);
# else
#else
return len_squared_v3v3(v1->co, v2->co);
# endif
#endif
}
BLI_INLINE float calc_weighted_edge_collapse(EdgeQueueContext *eq_ctx, BMVert *v1, BMVert *v2)
{
return calc_weighted_edge_split(eq_ctx, v1, v2);
float len_sq = len_squared_v3v3(v1->co, v2->co);
#ifdef FANCY_EDGE_WEIGHTS
float l = len_squared_v3v3(v1->co, v2->co);
// float val = (float)BM_vert_edge_count(v1) + (float)BM_vert_edge_count(v2);
#if 0 // this rule here seems to improve topology, but need to study it more
MSculptVert *mv1 = BKE_PBVH_SCULPTVERT(eq_ctx->cd_sculpt_vert, v1);
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(eq_ctx->cd_sculpt_vert, v2);
float val = (float)(mv1->valence + mv2->valence) * 0.5f;
val -= 6.0f;
val = MAX2(val, 1.0f);
// val = powf(val, 0.5);
l *= val;
return l;
#else
return len_squared_v3v3(v1->co, v2->co);
if (mv1->valence == 5 && mv2->valence == 5) {
len_sq *= 0.25;
}
#endif
return len_sq;
}
/* only tag'd edges are in the queue */
@ -3625,8 +3594,6 @@ static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
bool snap = !(mv2->flag & SCULPTVERT_ALL_CORNER);
BMLoop *l;
/* snap customdata */
if (snap) {
int ni_conn = BM_ELEM_CD_GET_INT(v_conn, pbvh->cd_vert_node_offset);
@ -5704,8 +5671,6 @@ cd_sculpt_vert, etc*/
DynTopoState *BKE_dyntopo_init(BMesh *bm, PBVH *existing_pbvh)
{
PBVH *pbvh;
PBVHNode _node;
PBVH _start;
if (!existing_pbvh) {
pbvh = MEM_callocN(sizeof(*pbvh), "pbvh");

View File

@ -1643,7 +1643,9 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
// also check e->l->radial_next, in case we are not manifold
// which can mess up the loop order
if (e->l->radial_next != e->l) {
float th = saacos(dot_v3v3(e->l->f->no, e->l->radial_next->f->no)) * M_1_PI * 0.25f;
float th = saacos(dot_v3v3(e->l->f->no, e->l->radial_next->f->no));
th *= M_1_PI * 0.25f;
// th = th * 0.5 + 0.5;
curv += th;
totcurv += 1.0f;

View File

@ -3730,6 +3730,9 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
const Brush *brush = data->brush;
PBVHNode *node = data->nodes[n];
int mode = SCULPT_get_int(ss, topology_rake_mode, sd, brush);
const bool use_curvature = mode == 1;
bool do_reproject = SCULPT_need_reproject(ss);
float direction[3];
@ -3755,7 +3758,6 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
const bool use_curvature = data->use_curvature;
int check_fsets = ss->cache->brush->flag2 & BRUSH_SMOOTH_PRESERVE_FACE_SETS;
check_fsets = check_fsets ? SCULPT_BOUNDARY_FACE_SET : 0;
@ -3801,6 +3803,10 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
if (use_curvature) {
SCULPT_curvature_dir_get(ss, vd.vertex, direction2, false);
}
else if (mode == 2) { // zero
zero_v3(direction);
zero_v3(direction2);
}
else {
copy_v3_v3(direction2, direction);
}
@ -3821,7 +3827,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
}
#endif
// check origdata to be sure we don't mess it up
/* check origdata to be sure we don't mess it up */
SCULPT_vertex_check_origdata(ss, vd.vertex);
float *co = vd.co;
@ -3882,6 +3888,7 @@ void SCULPT_bmesh_topology_rake(Sculpt *sd,
// vector4, nto color
SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_COLOR, "_rake_temp", false);
int cd_temp = SCULPT_dyntopo_get_templayer(ss, CD_PROP_COLOR, "_rake_temp");
#ifdef SCULPT_DIAGONAL_EDGE_MARKS
@ -3938,17 +3945,15 @@ void SCULPT_bmesh_topology_rake(Sculpt *sd,
for (iteration = 0; iteration <= count; iteration++) {
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
.strength = factor,
.cd_temp = cd_temp,
.use_curvature = SCULPT_get_int(ss, topology_rake_mode, sd, brush),
.cd_sculpt_vert = ss->cd_sculpt_vert,
.rake_projection = brush->topology_rake_projection,
.do_origco = needs_origco};
SculptThreadedTaskData data = {.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
.strength = factor,
.cd_temp = cd_temp,
.cd_sculpt_vert = ss->cd_sculpt_vert,
.rake_projection = brush->topology_rake_projection,
.do_origco = needs_origco};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);

View File

@ -397,7 +397,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
MVert *v = &ss->mvert[ml->v];
float fno[3];
MSculptVert *mv = ss->mdyntopo_verts + i;
MSculptVert *mv = ss->mdyntopo_verts + ml->v;
MV_ADD_FLAG(mv, SCULPTVERT_NEED_BOUNDARY);

View File

@ -1076,7 +1076,7 @@ typedef struct SculptThreadedTaskData {
ThreadMutex mutex;
// Layer brush
int cd_temp, cd_sculpt_vert;
int cd_temp, cd_temp2, cd_temp3, cd_sculpt_vert;
float smooth_projection;
float rake_projection;

View File

@ -124,6 +124,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
const SculptCustomLayer *buffer_scl = data->scl;
const SculptCustomLayer *stroke_id_scl = data->scl2;
const bool do_accum = SCULPT_get_int(ss, accumulate, NULL, brush);
PBVHVertexIter vd;
// SculptOrigVertData orig_data;
@ -222,11 +224,19 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
paint_color, paint_color, wet_mix_color, ss->cache->paint_brush.wet_mix);
blend_color_mix_float(color_buffer, color_buffer, paint_color);
/* Final mix over the original color using brush alpha. */
/* Final mix over the color/original-color using brush alpha. */
mul_v4_v4fl(buffer_color, color_buffer, alpha);
MSculptVert *mv = SCULPT_vertex_get_mdyntopo(ss, vd.vertex);
IMB_blend_color_float(vd.col, mv->origcolor, buffer_color, brush->blend);
if (do_accum) {
mul_v4_fl(buffer_color, fade);
IMB_blend_color_float(vd.col, vd.col, buffer_color, brush->blend);
vd.col[3] = 1.0f;
}
else {
MSculptVert *mv = SCULPT_vertex_get_mdyntopo(ss, vd.vertex);
IMB_blend_color_float(vd.col, mv->origcolor, buffer_color, brush->blend);
}
CLAMP4(vd.col, 0.0f, 1.0f);

View File

@ -787,6 +787,7 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
const float selfw = (float)mv->valence * 0.0025f;
madd_v3_v3fl(dir3, direction, selfw);
totdir3 += selfw;
BMIter eiter;
@ -800,14 +801,7 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
float dir2[3];
float *col2 = BM_ELEM_CD_GET_VOID_P(v_other, cd_temp);
float bucketw = 1.0f; // col2[3] < col[3] ? 2.0f : 1.0f;
// bucketw /= 0.00001f + len_v3v3(e->v1->co, e->v2->co);
// if (weighted) {
// bucketw = 1.0 / (0.000001 + areas[area_i]);
//}
// if (e == v->e) {
// bucketw *= 2.0;
//}
float bucketw = 1.0f;
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(cd_sculpt_vert, v_other);
float *co2;
@ -834,7 +828,7 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
int bound = SCULPT_edge_is_boundary(ss, (SculptEdgeRef){.i = (intptr_t)e}, bflag);
float dirw = 1.0f;
if (bound) {
if (bound) { // || v_other->head.hflag & BM_ELEM_SELECT) { // XXX
had_bound = true;
sub_v3_v3v3(dir2, co2, co1);
@ -860,7 +854,6 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
tot_co = 0.0f;
continue;
}
float vec[3];
sub_v3_v3v3(vec, co2, co1);