* Prototyped a faster smooth algo, currently disabled.

* Wrote a new API for wrangling temporary customdata layers across pbvh types:
  - SCULPT_temp_customlayer_ensure: makes sure a (named) customdata
    layer exists.  Works for multires; since these are temporary
    layers we can safely allocate them in a temporary CustomData
    structure (in ss->temp_vdata).
  - SCULPT_temp_customlayer_get: initializes a special structure,
    SculptCustomLayer, that is used to get per elem customdata.
  - SCULPT_temp_cdata_get: Uses a SculptCustomLayer ref along with
    a SculptVertexRef to look up the data.
This commit is contained in:
2021-05-14 18:26:41 -07:00
parent 6be2c079c1
commit cfd6d48aab
10 changed files with 423 additions and 60 deletions

View File

@@ -605,6 +605,8 @@ void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *da
void CustomData_unmark_temporary_nocopy(struct CustomData *data);
void CustomData_mark_temporary_nocopy(struct CustomData *data);
int CustomData_get_elem_size(CustomDataLayer *layer);
#ifdef __cplusplus
}
#endif

View File

@@ -27,6 +27,7 @@
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
#include "DNA_brush_enums.h"
#include "DNA_customdata_types.h"
#include "DNA_object_enums.h"
#ifdef __cplusplus
@@ -471,6 +472,12 @@ typedef struct SculptSession {
struct MPoly *mpoly;
struct MLoop *mloop;
// only assigned in PBVH_FACES and PBVH_GRIDS
CustomData *vdata, *edata, *ldata, *pdata;
// for grids
CustomData temp_vdata, temp_pdata;
/* These contain the vertex and poly counts of the final mesh. */
int totvert, totpoly;

View File

@@ -2107,6 +2107,11 @@ static const LayerTypeInfo *layerType_getInfo(int type)
return &LAYERTYPEINFO[type];
}
int CustomData_get_elem_size(CustomDataLayer *layer)
{
return layerType_getInfo(layer->type)->size;
}
static const char *layerType_getName(int type)
{
if (type < 0 || type >= CD_NUMTYPES) {

View File

@@ -1630,7 +1630,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
Scene *scene = DEG_get_input_scene(depsgraph);
Sculpt *sd = scene->toolsettings->sculpt;
SculptSession *ss = ob->sculpt;
const Mesh *me = BKE_object_get_original_mesh(ob);
Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0;
@@ -1683,6 +1683,11 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->multires.level = 0;
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
ss->vcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
ss->vdata = &me->vdata;
ss->edata = &me->edata;
ss->ldata = &me->ldata;
ss->pdata = &me->pdata;
}
/* Sculpt Face Sets. */
@@ -2233,7 +2238,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
pbvh = build_pbvh_for_dynamic_topology(ob);
ob->sculpt->pbvh = pbvh;
//reorder mesh elements to improve memory cache performance
// reorder mesh elements to improve memory cache performance
SCULPT_reorder_bmesh(ob->sculpt);
}
else {

View File

@@ -782,7 +782,8 @@ void BM_log_set_cd_offsets(BMLog *log, int cd_dyn_vert)
log->cd_dyn_vert = cd_dyn_vert;
}
void BM_log_set_bm(BMesh *bm, BMLog *log) {
void BM_log_set_bm(BMesh *bm, BMLog *log)
{
log->bm = bm;
}

View File

@@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
#include "BLI_compiler_attrs.h"
#include "BLI_heap.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
@@ -1105,20 +1106,20 @@ bool BM_face_point_inside_test(const BMFace *f, const float co[3])
* \note use_tag tags new flags and edges.
*/
void BM_face_triangulate(BMesh *bm,
BMFace *f,
BMFace **r_faces_new,
int *r_faces_new_tot,
BMEdge **r_edges_new,
int *r_edges_new_tot,
LinkNode **r_faces_double,
const int quad_method,
const int ngon_method,
const bool use_tag,
/* use for ngons only! */
MemArena *pf_arena,
BMFace *f,
BMFace **r_faces_new,
int *r_faces_new_tot,
BMEdge **r_edges_new,
int *r_edges_new_tot,
LinkNode **r_faces_double,
const int quad_method,
const int ngon_method,
const bool use_tag,
/* use for ngons only! */
MemArena *pf_arena,
/* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
struct Heap *pf_heap)
/* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
struct Heap *pf_heap)
{
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
const bool use_beauty = (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY);
@@ -1467,7 +1468,6 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
r_verts[3] = l->v;
}
/**
* faster alternative to:
* BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4);

View File

@@ -46,6 +46,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_colortools.h"
@@ -120,7 +121,6 @@ void SCULPT_vertex_random_access_ensure(SculptSession *ss)
}
}
/* Sculpt PBVH abstraction API
*
* This is read-only, for writing use PBVH vertex iterators. There vd.index matches
@@ -168,7 +168,7 @@ const float *SCULPT_vertex_origco_get(SculptSession *ss, SculptVertRef vertex)
const float *SCULPT_vertex_co_get(SculptSession *ss, SculptVertRef index)
{
if (ss->bm) {
return ((BMVert*)index.i)->co;
return ((BMVert *)index.i)->co;
}
switch (BKE_pbvh_type(ss->pbvh)) {
@@ -335,6 +335,132 @@ void SCULPT_vertex_persistent_normal_get(SculptSession *ss,
SCULPT_vertex_normal_get(ss, index, no);
}
static bool sculpt_temp_customlayer_get(SculptSession *ss,
AttributeDomain domain,
int proptype,
char *name,
SculptCustomLayer *out,
bool autocreate)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
CustomData *cdata = NULL;
if (!ss->bm) {
return false;
}
switch (domain) {
case ATTR_DOMAIN_POINT:
cdata = &ss->bm->vdata;
break;
case ATTR_DOMAIN_FACE:
cdata = &ss->bm->pdata;
break;
default:
return false;
}
int idx = CustomData_get_named_layer_index(cdata, proptype, name);
if (idx < 0) {
if (!autocreate) {
return false;
}
BM_data_layer_add_named(ss->bm, cdata, proptype, name);
idx = CustomData_get_named_layer_index(cdata, proptype, name);
cdata->layers[idx].flag |= CD_FLAG_TEMPORARY;
SCULPT_dyntopo_node_layers_update_offsets(ss);
}
out->data = NULL;
out->is_cdlayer = true;
out->layer = cdata->layers + idx;
out->cd_offset = out->layer->offset;
out->elemsize = CustomData_get_elem_size(out->layer);
break;
}
case PBVH_FACES: {
CustomData *cdata = NULL;
int totelem = 0;
switch (domain) {
case ATTR_DOMAIN_POINT:
totelem = ss->totvert;
cdata = ss->vdata;
break;
case ATTR_DOMAIN_FACE:
totelem = ss->totfaces;
cdata = ss->pdata;
break;
default:
return false;
}
int idx = CustomData_get_named_layer_index(cdata, proptype, name);
if (idx < 0) {
if (!autocreate) {
return false;
}
CustomData_add_layer_named(cdata, proptype, CD_CALLOC, NULL, totelem, name);
idx = CustomData_get_named_layer_index(cdata, proptype, name);
cdata->layers[idx].flag |= CD_FLAG_TEMPORARY;
}
out->data = NULL;
out->is_cdlayer = true;
out->layer = cdata->layers + idx;
out->cd_offset = -1;
out->data = out->layer->data;
out->elemsize = CustomData_get_elem_size(out->layer);
break;
}
case PBVH_GRIDS: {
CustomData *cdata = NULL;
int totelem = 0;
switch (domain) {
case ATTR_DOMAIN_POINT:
totelem = BKE_pbvh_get_grid_num_vertices(ss->pbvh);
cdata = &ss->temp_vdata;
break;
case ATTR_DOMAIN_FACE:
// not supported
return false;
default:
return false;
}
int idx = CustomData_get_named_layer_index(cdata, proptype, name);
if (idx < 0) {
if (!autocreate) {
return false;
}
CustomData_add_layer_named(cdata, proptype, CD_CALLOC, NULL, totelem, name);
idx = CustomData_get_named_layer_index(cdata, proptype, name);
}
out->data = NULL;
out->is_cdlayer = true;
out->layer = cdata->layers + idx;
out->cd_offset = -1;
out->data = out->layer->data;
out->elemsize = CustomData_get_elem_size(out->layer);
break;
}
}
return true;
}
float SCULPT_vertex_mask_get(SculptSession *ss, SculptVertRef index)
{
BMVert *v;
@@ -358,6 +484,21 @@ float SCULPT_vertex_mask_get(SculptSession *ss, SculptVertRef index)
return 0.0f;
}
bool SCULPT_temp_customlayer_ensure(SculptSession *ss,
AttributeDomain domain,
int proptype,
char *name)
{
SculptCustomLayer scl;
return sculpt_temp_customlayer_get(ss, domain, proptype, name, &scl, true);
}
bool SCULPT_temp_customlayer_get(
SculptSession *ss, AttributeDomain domain, int proptype, char *name, SculptCustomLayer *scl)
{
return sculpt_temp_customlayer_get(ss, domain, proptype, name, scl, true);
}
SculptVertRef SCULPT_active_vertex_get(SculptSession *ss)
{
if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) {
@@ -1095,10 +1236,9 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter,
iter->size++;
}
static void sculpt_vertex_neighbor_add_nocheck(SculptVertexNeighborIter *iter,
SculptVertRef neighbor,
int neighbor_index)
SculptVertRef neighbor,
int neighbor_index)
{
if (iter->size >= iter->capacity) {
iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
@@ -1147,7 +1287,8 @@ static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
iter, BKE_pbvh_make_vref((intptr_t)e->v2), BM_elem_index_get(e->v2));
e = e->v1_disk_link.next;
} else {
}
else {
sculpt_vertex_neighbor_add_nocheck(
iter, BKE_pbvh_make_vref((intptr_t)e->v1), BM_elem_index_get(e->v1));
@@ -1527,7 +1668,9 @@ void SCULPT_floodfill_add_initial(SculptFloodFill *flood, SculptVertRef vertex)
BLI_gsqueue_push(flood->queue, &vertex);
}
void SCULPT_floodfill_add_and_skip_initial(SculptSession *ss, SculptFloodFill *flood, SculptVertRef vertex)
void SCULPT_floodfill_add_and_skip_initial(SculptSession *ss,
SculptFloodFill *flood,
SculptVertRef vertex)
{
BLI_gsqueue_push(flood->queue, &vertex);
BLI_BITMAP_ENABLE(flood->visited_vertices, BKE_pbvh_vertex_index_to_table(ss->pbvh, vertex));
@@ -1675,7 +1818,7 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush *brush)
{
return SCULPT_TOOL_HAS_TOPOLOGY_RAKE(brush->sculpt_tool) &&
(brush->topology_rake_factor > 0.0f) && (ss->bm != NULL);
(brush->topology_rake_factor > 0.0f) && (ss->bm != NULL);
}
/**
@@ -3492,14 +3635,12 @@ static void bmesh_topology_rake(
for (iteration = 0; iteration <= count; iteration++) {
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
.strength = factor,
.rake_projection = brush->topology_rake_projection
};
SculptThreadedTaskData data = {.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
.strength = factor,
.rake_projection = brush->topology_rake_projection};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@@ -6882,10 +7023,11 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
float spacing = (float)brush->topology_rake_spacing / 100.0f;
use_topology_rake = use_topology_rake &&
paint_stroke_apply_subspacing(ss->cache->stroke,
spacing,
PAINT_MODE_SCULPT,
&ss->cache->last_rake_t[SCULPT_get_symmetry_pass(ss)]);
paint_stroke_apply_subspacing(
ss->cache->stroke,
spacing,
PAINT_MODE_SCULPT,
&ss->cache->last_rake_t[SCULPT_get_symmetry_pass(ss)]);
}
if (use_topology_rake) {

View File

@@ -138,6 +138,9 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm)
MemArena *pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
LinkNode *f_double = NULL;
BMFace **faces_array = NULL;
BLI_array_declare(faces_array);
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (f->len <= 3) {
continue;
@@ -146,9 +149,9 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm)
bool sel = BM_elem_flag_test(f, BM_ELEM_SELECT);
int faces_array_tot = f->len;
BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
printf("%d: ", f->head.hflag);
BLI_array_clear(faces_array);
BLI_array_grow_items(faces_array, faces_array_tot);
// BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
BM_face_triangulate(bm,
f,
@@ -163,8 +166,6 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm)
pf_arena,
NULL);
printf("%d, ", f->head.hflag);
for (int i = 0; i < faces_array_tot; i++) {
BMFace *f2 = faces_array[i];
@@ -181,8 +182,6 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm)
}
}
printf("\n");
while (f_double) {
LinkNode *next = f_double->next;
BM_face_kill(bm, f_double->link);
@@ -191,6 +190,7 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm)
}
BLI_memarena_free(pf_arena);
MEM_SAFE_FREE(faces_array);
ss->totfaces = ss->totpoly = ss->bm->totface;
ss->totvert = ss->bm->totvert;

View File

@@ -30,12 +30,16 @@
#include "DNA_vec_types.h"
#include "BLI_bitmap.h"
#include "BLI_compiler_compat.h"
#include "BLI_gsqueue.h"
#include "BLI_threads.h"
#include "BKE_attribute.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "bmesh.h"
struct AutomaskingCache;
struct KeyBlock;
struct Object;
@@ -747,6 +751,14 @@ struct SculptRakeData {
float follow_co[3];
};
typedef struct SculptCustomLayer {
bool is_cdlayer; // false for multires data
void *data; // only valid for multires and face
int elemsize;
int cd_offset; // for bmesh
CustomDataLayer *layer; // not for multires
} SculptCustomLayer;
/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
typedef struct SculptThreadedTaskData {
struct bContext *C;
@@ -866,6 +878,7 @@ typedef struct SculptThreadedTaskData {
float smooth_projection;
float rake_projection;
SculptCustomLayer *scl;
} SculptThreadedTaskData;
/*************** Brush testing declarations ****************/
@@ -1519,3 +1532,31 @@ int SCULPT_get_symmetry_pass(const SculptSession *ss);
void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss);
void SCULPT_reorder_bmesh(SculptSession *ss);
static inline void *SCULPT_temp_cdata_get(SculptVertRef vertex, SculptCustomLayer *scl)
{
if (scl->data) {
char *p = (char *)scl->data;
return p + scl->elemsize * (int)vertex.i;
}
else {
BMVert *v = (BMVert *)vertex.i;
return BM_ELEM_CD_GET_VOID_P(v, scl->cd_offset);
}
}
/*
create a custom vertex or face attribute.
always create all of your attributes together with SCULPT_temp_customlayer_ensure,
then initialize their SculptCustomLayer's with SCULPT_temp_customlayer_get
afterwards. Otherwise customdata offsets will be wrong (for PBVH_BMESH).
return true on success. if false layer was not created.
*/
bool SCULPT_temp_customlayer_ensure(SculptSession *ss,
AttributeDomain domain,
int proptype,
char *name);
bool SCULPT_temp_customlayer_get(
SculptSession *ss, AttributeDomain domain, int proptype, char *name, SculptCustomLayer *scl);

View File

@@ -33,6 +33,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_mesh.h"
@@ -141,9 +142,95 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
}
}
void SCULPT_neighbor_coords_average_interior_velocity(SculptSession *ss,
float result[3],
SculptVertRef vertex,
float projection,
SculptCustomLayer *scl)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
int neighbor_count = 0;
const bool is_boundary = SCULPT_vertex_is_boundary(ss, vertex);
const float *co = SCULPT_vertex_co_get(ss, vertex);
float no[3];
if (projection > 0.0f) {
SCULPT_vertex_normal_get(ss, vertex, no);
}
float vel[3];
copy_v3_v3(vel, (float *)SCULPT_temp_cdata_get(vertex, scl));
mul_v3_fl(vel, 0.4f);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
neighbor_count++;
float tmp[3];
bool ok = false;
float *vel2 = SCULPT_temp_cdata_get(ni.vertex, scl);
// propegate smooth velocities a bit
madd_v3_v3fl(vel2, vel, 1.0f / (float)ni.size);
if (is_boundary) {
/* Boundary vertices use only other boundary vertices. */
if (SCULPT_vertex_is_boundary(ss, ni.vertex)) {
copy_v3_v3(tmp, SCULPT_vertex_co_get(ss, ni.vertex));
ok = true;
}
}
else {
/* Interior vertices use all neighbors. */
copy_v3_v3(tmp, SCULPT_vertex_co_get(ss, ni.vertex));
ok = true;
}
if (!ok) {
continue;
}
if (projection > 0.0f) {
sub_v3_v3(tmp, co);
float fac = dot_v3v3(tmp, no);
madd_v3_v3fl(tmp, no, -fac * projection);
add_v3_v3(avg, tmp);
}
else {
add_v3_v3(avg, tmp);
}
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
/* Do not modify corner vertices. */
if (neighbor_count <= 2) {
copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex));
return;
}
/* Avoid division by 0 when there are no neighbors. */
if (total == 0) {
copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex));
return;
}
mul_v3_v3fl(result, avg, 1.0f / total);
if (projection > 0.0f) {
add_v3_v3(result, co);
}
}
/* For bmesh: Average surrounding verts based on an orthogonality measure.
* Naturally converges to a quad-like structure. */
void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v, float projection)
void SCULPT_bmesh_four_neighbor_average(float avg[3],
float direction[3],
BMVert *v,
float projection)
{
float avg_co[3] = {0.0f, 0.0f, 0.0f};
@@ -161,7 +248,7 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert
float vec[3];
sub_v3_v3v3(vec, v_other->co, v->co);
madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no)*projection);
madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no) * projection);
normalize_v3(vec);
/* fac is a measure of how orthogonal or parallel the edge is
@@ -180,7 +267,7 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert
/* Preserve volume. */
float vec[3];
sub_v3_v3(avg, v->co);
mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no)*projection);
mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no) * projection);
sub_v3_v3(avg, vec);
add_v3_v3(avg, v->co);
}
@@ -193,9 +280,9 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert
* account. */
void SCULPT_neighbor_coords_average(SculptSession *ss,
float result[3],
SculptVertRef vertex,
float projection)
float result[3],
SculptVertRef vertex,
float projection)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
float *co, no[3];
@@ -497,6 +584,63 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
}
#endif
static void do_smooth_brush_task_cb_ex_scl(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;
float bstrength = data->strength;
float projection = data->smooth_projection;
SculptCustomLayer *scl = data->scl;
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);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
sqrtf(test.dist),
vd.no,
vd.fno,
(vd.mask ? *vd.mask : 0.0f),
vd.vertex,
thread_id);
float avg[3], val[3];
SCULPT_neighbor_coords_average_interior_velocity(ss, avg, vd.vertex, projection, scl);
sub_v3_v3v3(val, avg, vd.co);
float *vel = (float *)SCULPT_temp_cdata_get(vd.vertex, scl);
interp_v3_v3v3(vel, vel, val, 0.5);
madd_v3_v3v3fl(val, vd.co, vel, 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(Sculpt *sd,
Object *ob,
PBVHNode **nodes,
@@ -519,6 +663,18 @@ void SCULPT_smooth(Sculpt *sd,
count = (int)(bstrength * max_iterations);
last = max_iterations * (bstrength - count * fract);
SculptCustomLayer scl;
#if 0
bool have_scl = smooth_mask ? false :
SCULPT_temp_customlayer_ensure(
ss, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, "__scl_smooth_vel");
if (have_scl) {
SCULPT_temp_customlayer_get(ss, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, "__scl_smooth_vel", &scl);
}
#else
bool have_scl = false;
#endif
if (type == PBVH_FACES && !ss->pmap) {
BLI_assert(!"sculpt smooth: pmap missing");
return;
@@ -536,19 +692,23 @@ 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,
};
SculptThreadedTaskData data = {.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
.smooth_mask = smooth_mask,
.strength = strength,
.smooth_projection = projection,
.scl = have_scl ? &scl : NULL};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_task_cb_ex, &settings);
if (have_scl) {
BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_task_cb_ex_scl, &settings);
}
else {
BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_task_cb_ex, &settings);
}
#ifdef PROXY_ADVANCED
BKE_pbvh_gather_proxyarray(ss->pbvh, nodes, totnode);