Sculpt dyntopo:

* Fixed noise on using autosmooth with tools that use original
  coorinates.  While this was most prominent with DynTopo,
  it did happen with other tools.
* The solution is to smooth the original coordinates as well
  as the explicit coordinates if the active tool requires
  original data.

* I decided to replace the original coordinates system for
  PBVH_FACES and PBVH_GRIDS with the same MDynTopoVert structure
  DynTopo uses.  The alternative would have been extremely messy
  code.

* Todo: Rename MDynTopoVert to. . .SculptInfoVert?
* Todo: Cache boundary flag and corner info in MDynTopoVert->flag
        for PBVH_FACES/GRIDS similar to PBVH_BMESH.
This commit is contained in:
Joseph Eagar 2021-09-13 19:24:21 -07:00
parent 0676928408
commit 3df335d330
19 changed files with 372 additions and 153 deletions

View File

@ -34,6 +34,7 @@
extern "C" {
#endif
struct MDynTopoVert;
struct BMFace;
struct BMesh;
struct BlendDataReader;
@ -658,6 +659,8 @@ typedef struct SculptSession {
int stroke_id, boundary_symmetry;
bool fast_draw; // hides facesets/masks and forces smooth to save GPU bandwidth
struct MDynTopoVert *mdyntopo_verts; // for non-bmesh
int mdyntopo_verts_size;
} SculptSession;
void BKE_sculptsession_free(struct Object *ob);
@ -665,6 +668,7 @@ void BKE_sculptsession_free_deformMats(struct SculptSession *ss);
void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
bool BKE_sculptsession_check_mdyntopo(SculptSession *ss, int totvert);
/* Create new color layer on object if it doesn't have one and if experimental feature set has
* sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise. */

View File

@ -269,6 +269,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
const struct MPoly *mpoly,
const struct MLoop *mloop,
struct MVert *verts,
struct MDynTopoVert *mdyntopo_verts,
int totvert,
struct CustomData *vdata,
struct CustomData *ldata,

View File

@ -1552,7 +1552,8 @@ static void layerDynTopoVert_interp(
float mul = 1.0f / totweight;
mul_v3_fl(co, mul);
mul_v3_fl(no, mul);
normalize_v3(no);
mul_v4_fl(color, mul);
origmask *= mul;

View File

@ -560,10 +560,26 @@ static BMEdge *bmesh_edge_create_log(PBVH *pbvh, BMVert *v1, BMVert *v2, BMEdge
BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v, float fac)
{
float co[3];
float origco[3], origco1[3];
float origno1[3];
float tan[3];
float tot = 0.0;
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
if (mv1->stroke_id != pbvh->stroke_id) {
copy_v3_v3(origco1, v->co);
copy_v3_v3(origno1, v->no);
}
else {
copy_v3_v3(origco1, mv1->origco);
copy_v3_v3(origno1, dot_v3v3(mv1->origno, mv1->origno) == 0.0f ? v->no : mv1->origno);
}
// BKE_pbvh_bmesh_check_origdata(pbvh, v, pbvh->stroke_id);
zero_v3(co);
zero_v3(origco);
// this is a manual edge walk
@ -572,11 +588,14 @@ BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v, float fac)
return;
}
pbvh_check_vert_boundary(pbvh, v);
if (mv1->flag & DYNVERT_NEED_BOUNDARY) {
return; // can't update boundary in thread
}
// pbvh_check_vert_boundary(pbvh, v);
const int cd_dyn_vert = pbvh->cd_dyn_vert;
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(cd_dyn_vert, v);
const bool bound1 = mv1->flag & DYNVERT_SMOOTH_BOUNDARY;
if (mv1->flag & DYNVERT_SMOOTH_CORNER) {
@ -601,6 +620,18 @@ BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v, float fac)
madd_v3_v3fl(tan, v->no, -d * 0.99f);
add_v3_v3(co, tan);
if (mv2->stroke_id == pbvh->stroke_id) {
sub_v3_v3v3(tan, mv2->origco, origco1);
}
else {
sub_v3_v3v3(tan, v2->co, origco1);
}
d = dot_v3v3(tan, origno1);
madd_v3_v3fl(tan, origno1, -d * 0.99f);
add_v3_v3(origco, tan);
tot += 1.0f;
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
@ -610,12 +641,32 @@ BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v, float fac)
}
mul_v3_fl(co, 1.0f / tot);
float x = v->co[0], y = v->co[1], z = v->co[2];
mul_v3_fl(origco, 1.0f / tot);
volatile float x = v->co[0], y = v->co[1], z = v->co[2];
volatile float nx = x + co[0] * fac, ny = y + co[1] * fac, nz = z + co[2] * fac;
// conflicts here should be pretty rare.
atomic_cas_float(&v->co[0], x, x + co[0] * fac);
atomic_cas_float(&v->co[1], y, y + co[1] * fac);
atomic_cas_float(&v->co[2], z, z + co[2] * fac);
atomic_cas_float(&v->co[0], x, nx);
atomic_cas_float(&v->co[1], y, ny);
atomic_cas_float(&v->co[2], z, nz);
// conflicts here should be pretty rare.
x = mv1->origco[0];
y = mv1->origco[1];
z = mv1->origco[2];
nx = x + origco[0] * fac;
ny = y + origco[1] * fac;
nz = z + origco[2] * fac;
atomic_cas_float(&mv1->origco[0], x, nx);
atomic_cas_float(&mv1->origco[1], y, ny);
atomic_cas_float(&mv1->origco[2], z, nz);
volatile int stroke_id = mv1->stroke_id;
// atomic_cas_int32(&mv1->stroke_id, stroke_id, pbvh->stroke_id);
}
static void pbvh_kill_vert(PBVH *pbvh, BMVert *v)
@ -3624,8 +3675,10 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
// snap customdata
if (snap) {
int ni_conn = BM_ELEM_CD_GET_INT(v_conn, pbvh->cd_vert_node_offset);
const float v_ws[2] = {0.5f, 0.5f};
const void *v_blocks[2] = {v_del->head.data, v_conn->head.data};
CustomData_bmesh_interp(&pbvh->bm->vdata, v_blocks, v_ws, NULL, 2, v_conn->head.data);
BM_ELEM_CD_SET_INT(v_conn, pbvh->cd_vert_node_offset, ni_conn);

View File

@ -85,6 +85,8 @@ void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss);
void SCULPT_dyntopo_node_layers_add(SculptSession *ss);
BMesh *SCULPT_dyntopo_empty_bmesh();
static void init_mdyntopo_layer(SculptSession *ss, int totvert);
static void palette_init_data(ID *id)
{
Palette *palette = (Palette *)id;
@ -1483,6 +1485,11 @@ void BKE_sculptsession_free(Object *ob)
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
if (ss->mdyntopo_verts) {
MEM_freeN(ss->mdyntopo_verts);
ss->mdyntopo_verts = NULL;
}
if (ss->bm_log && BM_log_free(ss->bm_log, true)) {
ss->bm_log = NULL;
}
@ -1671,7 +1678,6 @@ static void sculpt_update_object(Depsgraph *depsgraph,
}
ss->shapekey_active = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
ss->boundary_symmetry = (int)BKE_get_fset_boundary_symflag(ob);
/* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
@ -1724,6 +1730,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->fast_draw = (scene->toolsettings->sculpt->flags & SCULPT_FAST_DRAW) != 0;
PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
BLI_assert(pbvh == ss->pbvh);
UNUSED_VARS_NDEBUG(pbvh);
@ -2190,11 +2197,14 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
BKE_sculpt_sync_face_set_visibility(me, NULL);
BKE_sculptsession_check_mdyntopo(ob->sculpt, me->totvert);
BKE_pbvh_build_mesh(pbvh,
me,
me->mpoly,
me->mloop,
me->mvert,
ob->sculpt->mdyntopo_verts,
me->totvert,
&me->vdata,
&me->ldata,
@ -2235,11 +2245,40 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden,
ob->sculpt->fast_draw);
BKE_sculptsession_check_mdyntopo(ob->sculpt, BKE_pbvh_get_grid_num_vertices(pbvh));
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
return pbvh;
}
bool BKE_sculptsession_check_mdyntopo(SculptSession *ss, int totvert)
{
if (!ss->bm && (!ss->mdyntopo_verts || totvert != ss->mdyntopo_verts_size)) {
init_mdyntopo_layer(ss, totvert);
return true;
}
return false;
}
static void init_mdyntopo_layer(SculptSession *ss, int totvert)
{
if (ss->mdyntopo_verts) {
MEM_freeN(ss->mdyntopo_verts);
}
ss->mdyntopo_verts = MEM_calloc_arrayN(totvert, sizeof(*ss->mdyntopo_verts), "mdyntopo_verts");
ss->mdyntopo_verts_size = totvert;
MDynTopoVert *mv = ss->mdyntopo_verts;
for (int i = 0; i < totvert; i++, mv++) {
mv->flag = DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_VALENCE | DYNVERT_NEED_DISK_SORT;
mv->stroke_id = -1;
}
}
PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
{
if (ob == NULL || ob->sculpt == NULL) {
@ -2331,6 +2370,9 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
}
else if (ob->type == OB_MESH) {
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
BKE_sculptsession_check_mdyntopo(ob->sculpt, me_eval_deform->totvert);
pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide);
}
#endif

View File

@ -607,6 +607,8 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
const MPoly *mpoly,
const MLoop *mloop,
MVert *verts,
MDynTopoVert *mdyntopo_verts,
int totvert,
struct CustomData *vdata,
struct CustomData *ldata,
@ -624,6 +626,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
pbvh->mloop = mloop;
pbvh->looptri = looptri;
pbvh->verts = verts;
pbvh->mdyntopo_verts = mdyntopo_verts;
pbvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
pbvh->totvert = totvert;
pbvh->leaf_limit = LEAF_LIMIT;

View File

@ -833,6 +833,8 @@ void BKE_pbvh_bmesh_update_origvert(
bool BKE_pbvh_bmesh_check_origdata(PBVH *pbvh, BMVert *v, int stroke_id)
{
// keep this up to date with surface_smooth_v_safe in dyntopo.c
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
if (mv->stroke_id != stroke_id) {

View File

@ -26,6 +26,7 @@
/** \file
* \ingroup bli
*/
struct MDynTopoVert;
/* Axis-aligned bounding box */
typedef struct {
@ -217,6 +218,7 @@ struct PBVH {
int balance_counter;
int stroke_id; // used to keep origdata up to date in PBVH_BMESH
struct MDynTopoVert *mdyntopo_verts;
};
/* pbvh.c */

View File

@ -158,15 +158,40 @@ int SCULPT_vertex_count_get(SculptSession *ss)
return 0;
}
const float *SCULPT_vertex_origco_get(SculptSession *ss, SculptVertRef vertex)
MDynTopoVert *SCULPT_vertex_get_mdyntopo(SculptSession *ss, SculptVertRef vertex)
{
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BMVert *v = (BMVert *)vertex.i;
return BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v)->origco;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
BMVert *v = (BMVert *)vertex.i;
return BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v);
}
case PBVH_GRIDS:
case PBVH_FACES: {
return ss->mdyntopo_verts + vertex.i;
}
}
// XXX implement me
return SCULPT_vertex_co_get(ss, vertex);
return NULL;
}
float *SCULPT_vertex_origco_get(SculptSession *ss, SculptVertRef vertex)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
BMVert *v = (BMVert *)vertex.i;
return BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v)->origco;
}
case PBVH_GRIDS:
case PBVH_FACES: {
MDynTopoVert *mv = ss->mdyntopo_verts + vertex.i;
return ss->mdyntopo_verts[vertex.i].origco;
}
}
return NULL;
}
const float *SCULPT_vertex_co_get(SculptSession *ss, SculptVertRef index)
@ -2284,6 +2309,9 @@ typedef enum StrokeFlags {
void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, SculptUndoNode *unode)
{
SculptSession *ss = ob->sculpt;
// do nothing
BMesh *bm = ss->bm;
memset(data, 0, sizeof(*data));
@ -2295,12 +2323,9 @@ void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, Scul
if (bm) {
data->bm_log = ss->bm_log;
}
else {
data->datatype = data->unode->type;
data->coords = data->unode->co;
data->normals = data->unode->no;
data->vmasks = data->unode->mask;
data->colors = data->unode->col;
// data->datatype = data->unode->type;
}
}
@ -2316,75 +2341,58 @@ void SCULPT_orig_vert_data_init(SculptOrigVertData *data,
SculptUndoNode *unode = NULL;
data->ss = ob->sculpt;
/*do not allocate an undo node for bmesh pbvh*/
// don't need undo node here anymore
if (!ob->sculpt->bm) {
unode = SCULPT_undo_push_node(ob, node, type);
// unode = SCULPT_undo_push_node(ob, node, type);
}
SCULPT_orig_vert_data_unode_init(data, ob, unode);
data->datatype = type;
}
/**
* Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
*/
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
void SCULPT_vertex_check_origdata(SculptSession *ss, SculptVertRef vertex)
{
// check if we need to update original data for current stroke
if (orig_data->bm_log) {
MDynTopoVert *mv = BKE_PBVH_DYNVERT(iter->cd_dyn_vert, iter->bm_vert);
if (mv->stroke_id != orig_data->ss->stroke_id) {
mv->stroke_id = orig_data->ss->stroke_id;
MDynTopoVert *mv = ss->bm ? BKE_PBVH_DYNVERT(ss->cd_dyn_vert, (BMVert *)vertex.i) :
ss->mdyntopo_verts + vertex.i;
copy_v3_v3(mv->origco, iter->bm_vert->co);
copy_v3_v3(mv->origno, iter->bm_vert->no);
if (mv->stroke_id != ss->stroke_id) {
mv->stroke_id = ss->stroke_id;
const int cd_vcol = iter->cd_vcol_offset;
const int cd_mask = iter->cd_vert_mask_offset;
copy_v3_v3(mv->origco, SCULPT_vertex_co_get(ss, vertex));
SCULPT_vertex_normal_get(ss, vertex, mv->origno);
if (cd_vcol >= 0) {
MPropCol *col = BM_ELEM_CD_GET_VOID_P(iter->bm_vert, cd_vcol);
copy_v4_v4(mv->origcolor, col->color);
}
if (cd_mask >= 0) {
mv->origmask = BM_ELEM_CD_GET_FLOAT(iter->bm_vert, cd_mask);
}
const float *color = SCULPT_vertex_color_get(ss, vertex);
if (color) {
copy_v4_v4(mv->origcolor, color);
}
mv->origmask = SCULPT_vertex_mask_get(ss, vertex);
}
}
/**
* DEPRECATED use Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
*/
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, SculptVertRef vertex)
{
// check if we need to update original data for current stroke
MDynTopoVert *mv = SCULPT_vertex_get_mdyntopo(orig_data->ss, vertex);
SCULPT_vertex_check_origdata(orig_data->ss, vertex);
if (orig_data->datatype == SCULPT_UNDO_COORDS) {
if (orig_data->bm_log) {
orig_data->co = BKE_PBVH_DYNVERT(iter->cd_dyn_vert, iter->bm_vert)->origco;
float *no = mv->origno;
normal_float_to_short_v3(orig_data->_no, no);
float *no = BKE_PBVH_DYNVERT(iter->cd_dyn_vert, iter->bm_vert)->origno;
normal_float_to_short_v3(orig_data->_no, no);
orig_data->no = orig_data->_no;
orig_data->col = iter->cd_vcol_offset >= 0 ?
BKE_PBVH_DYNVERT(iter->cd_dyn_vert, iter->bm_vert)->origcolor :
NULL;
}
else {
orig_data->co = orig_data->coords[iter->i];
orig_data->no = orig_data->normals[iter->i];
}
orig_data->no = orig_data->_no;
orig_data->co = mv->origco;
}
else if (orig_data->datatype == SCULPT_UNDO_COLOR) {
if (orig_data->bm_log) {
orig_data->col = BKE_PBVH_DYNVERT(iter->cd_dyn_vert, iter->bm_vert)->origcolor;
}
else {
orig_data->col = orig_data->colors[iter->i];
}
orig_data->col = mv->origcolor;
}
else if (orig_data->datatype == SCULPT_UNDO_MASK) {
if (orig_data->bm_log) {
orig_data->mask = BKE_PBVH_DYNVERT(iter->cd_dyn_vert, iter->bm_vert)->origmask;
}
else {
orig_data->mask = orig_data->vmasks[iter->i];
}
orig_data->mask = mv->origmask;
}
}
@ -2547,7 +2555,7 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
SCULPT_orig_vert_data_unode_init(&orig_data, data->ob, unode);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
copy_v3_v3(vd.co, orig_data.co);
@ -4050,20 +4058,25 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
}
#endif
SCULPT_bmesh_four_neighbor_average(ss,
avg,
direction2,
vd.bm_vert,
data->rake_projection,
check_fsets,
data->cd_temp,
data->cd_dyn_vert);
int steps = data->do_origco ? 2 : 1;
sub_v3_v3v3(val, avg, vd.co);
for (int step = 0; step < steps; step++) {
float *co = step ? (float *)SCULPT_vertex_origco_get(ss, vd.vertex) : vd.co;
madd_v3_v3v3fl(val, vd.co, val, fade);
SCULPT_bmesh_four_neighbor_average(ss,
avg,
direction2,
vd.bm_vert,
data->rake_projection,
check_fsets,
data->cd_temp,
data->cd_dyn_vert,
step);
SCULPT_clip(sd, ss, vd.co, val);
sub_v3_v3v3(val, avg, co);
madd_v3_v3v3fl(val, co, val, fade);
SCULPT_clip(sd, ss, co, val);
}
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@ -4146,7 +4159,8 @@ static void bmesh_topology_rake(
.strength = factor,
.cd_temp = cd_temp,
.cd_dyn_vert = ss->cd_dyn_vert,
.rake_projection = brush->topology_rake_projection};
.rake_projection = brush->topology_rake_projection,
.do_origco = SCULPT_stroke_needs_original(brush)};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@ -4220,7 +4234,7 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
do_mask_brush_draw(sd, ob, nodes, totnode);
break;
case BRUSH_MASK_SMOOTH:
SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true, 0.0f);
SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true, 0.0f, false);
break;
}
}
@ -4537,7 +4551,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
@ -4620,7 +4634,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
@ -4789,7 +4803,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
@ -5188,7 +5202,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
@ -5289,7 +5303,7 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
&params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
float final_disp[3];
switch (brush->elastic_deform_type) {
case BRUSH_ELASTIC_DEFORM_GRAB:
@ -5740,7 +5754,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
@ -5813,7 +5827,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
@ -5916,7 +5930,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
@ -7710,11 +7724,18 @@ void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings
totnode,
brush->autosmooth_factor * (1.0f - ss->cache->pressure),
false,
brush->autosmooth_projection);
brush->autosmooth_projection,
false);
}
else {
SCULPT_smooth(
sd, ob, nodes, totnode, brush->autosmooth_factor, false, brush->autosmooth_projection);
SCULPT_smooth(sd,
ob,
nodes,
totnode,
brush->autosmooth_factor,
false,
brush->autosmooth_projection,
false);
}
if (brush->autosmooth_radius_factor != 1.0f) {

View File

@ -1589,7 +1589,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
continue;
}
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
continue;
@ -1638,7 +1638,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
continue;
}
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
continue;
@ -1684,7 +1684,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
continue;
}
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
continue;
@ -1730,7 +1730,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
continue;
}
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
continue;
@ -1781,7 +1781,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
continue;
}
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
continue;
@ -1827,7 +1827,7 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
continue;
}
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
continue;
@ -1913,7 +1913,7 @@ static void SCULPT_boundary_autosmooth(SculptSession *ss, SculptBoundary *bounda
float sco[3];
SCULPT_neighbor_coords_average_interior(
ss, sco, vd.vertex, ss->cache->brush->autosmooth_projection, NULL);
ss, sco, vd.vertex, ss->cache->brush->autosmooth_projection, NULL, false);
float *co = SCULPT_brush_deform_target_vertex_co_get(
ss, ss->cache->brush->deform_target, &vd);
@ -1952,7 +1952,7 @@ static void SCULPT_boundary_build_smoothco(SculptSession *ss, SculptBoundary *bo
float sco[3];
SCULPT_neighbor_coords_average_interior(ss, sco, vd.vertex, projection, NULL);
SCULPT_neighbor_coords_average_interior(ss, sco, vd.vertex, projection, NULL, false);
float *co = SCULPT_brush_deform_target_vertex_co_get(
ss, ss->cache->brush->deform_target, &vd);

View File

@ -768,6 +768,11 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
SCULPT_pbvh_clear(ob);
if (ss->mdyntopo_verts) {
MEM_freeN(ss->mdyntopo_verts);
ss->mdyntopo_verts = NULL;
}
ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & SCULPT_DYNTOPO_SMOOTH_SHADING) !=
0;

View File

@ -111,7 +111,7 @@ static void color_filter_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
float orig_color[3], final_color[4], hsv_color[3];
int hue;
float brightness, contrast, gain, delta, offset;

View File

@ -303,7 +303,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
@ -334,7 +334,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
switch (filter_type) {
case MESH_FILTER_SMOOTH:
fade = clamp_f(fade, -1.0f, 1.0f);
SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex, 0.0f, NULL);
SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex, 0.0f, NULL, false);
sub_v3_v3v3(val, avg, orig_co);
madd_v3_v3v3fl(val, orig_co, val, fade);
sub_v3_v3v3(disp, val, orig_co);

View File

@ -217,8 +217,9 @@ void SCULPT_vertex_neighbors_get(const struct SculptSession *ss,
SculptVertRef SCULPT_active_vertex_get(SculptSession *ss);
const float *SCULPT_active_vertex_co_get(SculptSession *ss);
const float *SCULPT_vertex_origco_get(SculptSession *ss, SculptVertRef vertex);
float *SCULPT_vertex_origco_get(SculptSession *ss, SculptVertRef vertex);
void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
MDynTopoVert *SCULPT_vertex_get_mdyntopo(SculptSession *ss, SculptVertRef vertex);
/* Returns PBVH deformed vertices array if shape keys or deform modifiers are used, otherwise
* returns mesh original vertices array. */
@ -646,7 +647,8 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
float projection,
bool check_fsets,
int cd_temp,
int cd_dyn_vert);
int cd_dyn_vert,
bool do_origco);
/* Smoothing api */
void SCULPT_neighbor_coords_average(
@ -659,7 +661,8 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float result[3],
SculptVertRef index,
float projection,
SculptCustomLayer *bound_scl);
SculptCustomLayer *bound_scl,
bool do_origco);
void SCULPT_smooth_vcol_boundary(
Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength);
@ -670,7 +673,8 @@ void SCULPT_smooth(Sculpt *sd,
const int totnode,
float bstrength,
const bool smooth_mask,
float projection);
float projection,
bool do_origco);
void SCULPT_do_smooth_brush(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float projection);
@ -923,6 +927,7 @@ typedef struct SculptThreadedTaskData {
float smooth_projection;
float rake_projection;
SculptCustomLayer *scl, *scl2;
bool do_origco;
} SculptThreadedTaskData;
/*************** Brush testing declarations ****************/
@ -1446,11 +1451,13 @@ void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
const float angle);
void SCULPT_cache_free(StrokeCache *cache);
void SCULPT_vertex_check_origdata(SculptSession *ss, SculptVertRef vertex);
void SCULPT_orig_vert_data_init(SculptOrigVertData *data,
Object *ob,
PBVHNode *node,
SculptUndoType type);
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, SculptVertRef vertex);
void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data,
Object *ob,
struct SculptUndoNode *unode);
@ -1692,3 +1699,13 @@ void SCULPT_replay_log_append(struct Sculpt *sd, struct SculptSession *ss, struc
void SCULPT_replay_test(void);
#endif
#define SCULPT_stroke_needs_original(brush) \
ELEM(brush->sculpt_tool, \
SCULPT_TOOL_DRAW_SHARP, \
SCULPT_TOOL_GRAB, \
SCULPT_TOOL_ROTATE, \
SCULPT_TOOL_THUMB, \
SCULPT_TOOL_ELASTIC_DEFORM, \
SCULPT_TOOL_BOUNDARY, \
SCULPT_TOOL_POSE)

View File

@ -140,7 +140,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
IMB_colormanagement_srgb_to_scene_linear_v3(brush_color);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
bool affect_vertex = false;
float distance_to_stroke_location = 0.0f;

View File

@ -175,7 +175,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata,
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
float total_disp[3];
zero_v3(total_disp);

View File

@ -78,9 +78,17 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float result[3],
SculptVertRef vertex,
float projection,
SculptCustomLayer *bound_scl)
SculptCustomLayer *bound_scl,
bool do_origco)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
MDynTopoVert *mv = SCULPT_vertex_get_mdyntopo(ss, vertex);
if (do_origco) {
SCULPT_vertex_check_origdata(ss, vertex);
}
float total = 0.0f;
int neighbor_count = 0;
bool check_fsets = ss->cache->brush->flag2 & BRUSH_SMOOTH_PRESERVE_FACE_SETS;
@ -97,11 +105,16 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
const SculptBoundaryType is_boundary = SCULPT_vertex_is_boundary(ss, vertex, bflag);
const float *co = SCULPT_vertex_co_get(ss, vertex);
const float *co = do_origco ? mv->origco : SCULPT_vertex_co_get(ss, vertex);
float no[3];
if (true || projection > 0.0f) {
SCULPT_vertex_normal_get(ss, vertex, no);
if (do_origco) {
copy_v3_v3(no, mv->origno);
}
else {
SCULPT_vertex_normal_get(ss, vertex, no);
}
}
const bool weighted = (ss->cache->brush->flag2 & BRUSH_SMOOTH_USE_AREA_WEIGHT) && !is_boundary;
@ -131,6 +144,16 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
MDynTopoVert *mv2 = SCULPT_vertex_get_mdyntopo(ss, ni.vertex);
const float *co2;
if (!do_origco || mv2->stroke_id != ss->stroke_id) {
co2 = SCULPT_vertex_co_get(ss, ni.vertex);
}
else {
co2 = mv2->origco;
}
neighbor_count++;
float tmp[3], w;
@ -186,12 +209,12 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
w *= slide_fset;
sub_v3_v3v3(t, SCULPT_vertex_co_get(ss, ni.vertex), co);
sub_v3_v3v3(t, co2, co);
madd_v3_v3v3fl(tmp, co, no, dot_v3v3(t, no));
ok = true;
}
else if (final_boundary) {
copy_v3_v3(tmp, SCULPT_vertex_co_get(ss, ni.vertex));
copy_v3_v3(tmp, co2);
ok = true;
do_diffuse = false;
}
@ -200,7 +223,7 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
}
}
else {
copy_v3_v3(tmp, SCULPT_vertex_co_get(ss, ni.vertex));
copy_v3_v3(tmp, co2);
ok = true;
}
@ -210,7 +233,7 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
makes more rounded edges.
*/
copy_v3_v3(tmp, SCULPT_vertex_co_get(ss, ni.vertex));
copy_v3_v3(tmp, co2);
ok = true;
float len = len_v3v3(co, tmp);
@ -228,7 +251,13 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
btot += w2;
float no2[3];
SCULPT_vertex_normal_get(ss, ni.vertex, no2);
if (!do_origco || mv2->stroke_id != ss->stroke_id) {
SCULPT_vertex_normal_get(ss, ni.vertex, no2);
}
else {
copy_v3_v3(no2, mv2->origno);
}
float radius = ss->cache->radius * 10.0f;
@ -280,13 +309,13 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
/* Do not modify corner vertices. */
if (neighbor_count <= 2 && is_boundary) {
copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex));
copy_v3_v3(result, co);
return;
}
/* Avoid division by 0 when there are no neighbors. */
if (total == 0.0f) {
copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex));
copy_v3_v3(result, co);
return;
}
@ -475,11 +504,12 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
float projection,
bool check_fsets,
int cd_temp,
int cd_dyn_vert)
int cd_dyn_vert,
bool do_origco)
{
float avg_co[3] = {0.0f, 0.0f, 0.0f};
float tot_co = 0.0f;
float buckets[8] = {0};
// zero_v3(direction);
@ -493,6 +523,17 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
const bool weighted = (ss->cache->brush->flag2 & BRUSH_SMOOTH_USE_AREA_WEIGHT);
float *areas;
SCULPT_vertex_check_origdata(ss, (SculptVertRef){.i = (intptr_t)v});
if (do_origco) {
// SCULPT_vertex_check_origdata(ss, (SculptVertRef){.i = (intptr_t)v});
madd_v3_v3fl(direction, mv->origno, -dot_v3v3(mv->origno, direction));
normalize_v3(direction);
}
float *co1 = do_origco ? mv->origco : v->co;
float *no1 = do_origco ? mv->origno : v->no;
if (weighted) {
SculptVertRef vertex = {.i = (intptr_t)v};
@ -508,12 +549,12 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
copy_v3_v3(dir, direction);
}
else {
closest_vec_to_perp(dir, direction, v->no, buckets, 1.0f); // col[3]);
closest_vec_to_perp(dir, direction, no1, buckets, 1.0f); // col[3]);
}
float totdir3 = 0.0f;
const float selfw = (float)mv->valence * 0.25f;
const float selfw = (float)mv->valence * 0.0025f;
madd_v3_v3fl(dir3, direction, selfw);
totdir3 += selfw;
@ -538,6 +579,18 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
//}
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(cd_dyn_vert, v_other);
float *co2;
float *no2;
if (!do_origco || mv2->stroke_id != ss->stroke_id) {
co2 = v_other->co;
no2 = v_other->no;
}
else {
co2 = mv2->origco;
no2 = mv2->origno;
}
// bool bound = (mv2->flag &
// (DYNVERT_BOUNDARY)); // | DYNVERT_FSET_BOUNDARY | DYNVERT_SHARP_BOUNDARY));
// bool bound2 = (mv2->flag &
@ -552,8 +605,8 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
if (bound) {
had_bound = true;
sub_v3_v3v3(dir2, v_other->co, v->co);
madd_v3_v3fl(dir2, v->no, -dot_v3v3(v->no, dir2));
sub_v3_v3v3(dir2, co2, co1);
madd_v3_v3fl(dir2, no1, -dot_v3v3(no1, dir2));
normalize_v3(dir2);
dirw = 100000.0f;
}
@ -566,7 +619,7 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
}
}
closest_vec_to_perp(dir, dir2, v->no, buckets, bucketw); // col2[3]);
closest_vec_to_perp(dir, dir2, no1, buckets, bucketw); // col2[3]);
madd_v3_v3fl(dir3, dir2, dirw);
totdir3 += dirw;
@ -577,9 +630,9 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
}
float vec[3];
sub_v3_v3v3(vec, v_other->co, v->co);
sub_v3_v3v3(vec, co2, co1);
madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no) * projection);
madd_v3_v3fl(vec, no1, -dot_v3v3(vec, no1) * projection);
normalize_v3(vec);
/* fac is a measure of how orthogonal or parallel the edge is
@ -610,7 +663,7 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
fac *= areas[area_i];
}
madd_v3_v3fl(avg_co, v_other->co, fac);
madd_v3_v3fl(avg_co, co2, fac);
tot_co += fac;
}
@ -620,14 +673,19 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
/* Preserve volume. */
float vec[3];
sub_v3_v3(avg, v->co);
mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no) * projection);
sub_v3_v3(avg, co1);
mul_v3_v3fl(vec, no1, dot_v3v3(avg, no1) * projection);
sub_v3_v3(avg, vec);
add_v3_v3(avg, v->co);
add_v3_v3(avg, co1);
}
else {
// zero_v3(avg);
copy_v3_v3(avg, v->co);
copy_v3_v3(avg, co1);
}
// do not update in do_origco
if (do_origco) {
return;
}
if (totdir3 > 0.0f) {
@ -658,7 +716,7 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
}
// negate_v3(col);
vec_transform(col, v->no, bi);
vec_transform(col, no1, bi);
// negate_v3(col);
}
}
@ -1077,10 +1135,16 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
// continue;
//}
SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex, projection, bound_scl);
sub_v3_v3v3(val, avg, vd.co);
madd_v3_v3v3fl(val, vd.co, val, fade);
SCULPT_clip(sd, ss, vd.co, val);
int steps = data->do_origco ? 2 : 1;
for (int step = 0; step < steps; step++) {
float *co = step ? (float *)SCULPT_vertex_origco_get(ss, vd.vertex) : vd.co;
SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex, projection, bound_scl, step);
sub_v3_v3v3(val, avg, co);
madd_v3_v3v3fl(val, co, val, fade);
SCULPT_clip(sd, ss, co, val);
}
}
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@ -1159,7 +1223,8 @@ void SCULPT_smooth(Sculpt *sd,
const int totnode,
float bstrength,
const bool smooth_mask,
float projection)
float projection,
bool do_origco)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
@ -1221,15 +1286,18 @@ void SCULPT_smooth(Sculpt *sd,
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 = smooth_mask,
.strength = strength,
.smooth_projection = projection,
.scl = have_scl ? &scl : NULL,
.scl2 = bound_scl};
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
.smooth_mask = smooth_mask,
.strength = strength,
.smooth_projection = projection,
.scl = have_scl ? &scl : NULL,
.scl2 = bound_scl,
.do_origco = SCULPT_stroke_needs_original(ss->cache->brush),
};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@ -1263,7 +1331,7 @@ void SCULPT_do_smooth_brush(
}
else {
/* Regular mode, smooth. */
SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false, projection);
SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false, projection, false);
}
}
@ -1350,7 +1418,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;

View File

@ -165,7 +165,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
float transformed_co[3], orig_co[3], disp[3];
float *start_co;
float fade = vd.mask ? *vd.mask : 0.0f;

View File

@ -1602,7 +1602,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
}
if (ss->deform_modifiers_active) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, unode->index[vd.i]);