Sculpt: smothing ops now slide UVs

* Wrote a new function, SCULPT_reproject_cdata,
  to reproject loop customdata after smoothing.
* SCULPT_reproject_cdata is only called if UV
  layers exist.
* All of the smoothing tools (hopefully all)
  use it.
* This change is necassary to properly support vector
  displacement maps in the future; otherwise DynTopo
  will introduce lots of noise into the uv tangent
  space.
This commit is contained in:
Joseph Eagar 2021-10-15 13:40:02 -07:00
parent 7d25a5ab3f
commit 673e1fbac5
16 changed files with 415 additions and 30 deletions

View File

@ -1285,6 +1285,12 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
"show_origco",
toolsettings_only=True, ui_editing=False)
UnifiedPaintPanel.channel_unified(layout.column(),
context,
brush,
"save_temp_layers",
toolsettings_only=True, ui_editing=False)
col.separator()
col.operator("sculpt.set_limit_surface")

View File

@ -191,7 +191,7 @@ void BKE_brush_channel_free(BrushChannel *ch);
void BKE_brush_channel_copy_data(BrushChannel *dst, BrushChannel *src, bool keep_mappings);
void BKE_brush_channel_init(BrushChannel *ch, BrushChannelType *def);
BrushChannelSet *BKE_brush_channelset_create();
BrushChannelSet *BKE_brush_channelset_create(const char *info);
#ifdef DEBUG_CURVE_MAPPING_ALLOC
BrushChannelSet *_BKE_brush_channelset_copy(BrushChannelSet *src);
# define BKE_brush_channelset_copy(src) \

View File

@ -818,6 +818,8 @@ typedef struct SculptSession {
*/
struct SculptCustomLayer **layers_to_free;
int tot_layers_to_free;
bool save_temp_layers;
} SculptSession;
void BKE_sculptsession_free(struct Object *ob);

View File

@ -64,7 +64,7 @@ static void brush_init_data(ID *id)
MEMCPY_STRUCT_AFTER(brush, DNA_struct_default_get(Brush), id);
brush->channels = BKE_brush_channelset_create();
brush->channels = BKE_brush_channelset_create(NULL);
/* enable fake user by default */
id_fake_user_set(&brush->id);

View File

@ -278,6 +278,7 @@ places in rna_engine_codebase are relevent:
MAKE_FLOAT(tip_roundness, "Tip Roundness", "", 1.0f, 0.0f, 1.0f)
MAKE_BOOL(accumulate, "Accumulate", "", false)
MAKE_BOOL_EX(show_origco, "Show OrigCo", "", false, BRUSH_CHANNEL_INHERIT)
MAKE_BOOL_EX(save_temp_layers, "Save Temp Layers", "Developer option; save temporary vertex attributes", false, BRUSH_CHANNEL_INHERIT)
MAKE_ENUM(direction, "Direction", "", 0, {\
{0, "ADD", "ADD", "Add", "Add effect of brush"},
{1, "SUBTRACT", "REMOVE", "Subtract", "Subtract effect of brush"},

View File

@ -478,12 +478,30 @@ float BKE_brush_channel_curve_evaluate(BrushChannel *ch, float val, const float
return BKE_brush_curve_strength_ex(ch->curve.preset, ch->curve.curve, val, maxval);
}
BrushChannelSet *BKE_brush_channelset_create()
BrushChannelSet *BKE_brush_channelset_create(const char *info)
{
BrushChannelSet *chset = (BrushChannelSet *)MEM_callocN(sizeof(BrushChannelSet),
"BrushChannelSet");
static char *tags[512] = {0};
chset->namemap = BLI_ghash_str_new("BrushChannelSet");
char buf[512] = "BrushChannelSet", *tag;
if (info) {
strcat(buf, " ");
strcat(buf, info);
for (int i = 0; i < ARRAY_SIZE(tags); i++) {
if (tags[i] && STREQ(tags[i], buf)) {
tag = tags[i];
}
else if (!tags[i]) {
tags[i] = tag = strdup(buf);
}
}
}
BrushChannelSet *chset = (BrushChannelSet *)MEM_callocN(sizeof(BrushChannelSet),
info ? tag : "BrushChannelSet");
chset->namemap = BLI_ghash_str_new("BrushChannelSet ghash");
return chset;
}
@ -807,7 +825,7 @@ BrushChannelSet *_BKE_brush_channelset_copy(BrushChannelSet *src)
BrushChannelSet *BKE_brush_channelset_copy(BrushChannelSet *src)
#endif
{
BrushChannelSet *chset = BKE_brush_channelset_create();
BrushChannelSet *chset = BKE_brush_channelset_create(NULL);
if (!src->totchannel) {
return chset;
@ -871,7 +889,7 @@ void BKE_brush_commandlist_start(BrushCommandList *list,
if (cmd->params_final) {
BKE_brush_channelset_free(cmd->params_final);
}
cmd->params_final = BKE_brush_channelset_create();
cmd->params_final = BKE_brush_channelset_create("params_final");
BKE_brush_channelset_merge(cmd->params_final, cmd->params, chset_final);
@ -889,7 +907,7 @@ void BKE_brush_resolve_channels(Brush *brush, Sculpt *sd)
BKE_brush_channelset_free(brush->channels_final);
}
brush->channels_final = BKE_brush_channelset_create();
brush->channels_final = BKE_brush_channelset_create("channels_final");
BKE_brush_channelset_merge(brush->channels_final, brush->channels, sd->channels);
}
@ -1346,7 +1364,7 @@ BrushCommand *BKE_brush_commandlist_add(BrushCommandList *cl,
}
}
else {
cmd->params = BKE_brush_channelset_create();
cmd->params = BKE_brush_channelset_create("params");
}
cmd->params_final = NULL;
@ -1886,7 +1904,7 @@ BrushTex *BKE_brush_tex_create()
{
BrushTex *bt = MEM_callocN(sizeof(BrushTex), "BrushTex");
bt->channels = BKE_brush_channelset_create();
bt->channels = BKE_brush_channelset_create("brush tex");
return bt;
}

View File

@ -993,7 +993,7 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
bool setup_ui = !brush->channels || !brush->channels->totchannel;
if (!brush->channels) {
brush->channels = BKE_brush_channelset_create();
brush->channels = BKE_brush_channelset_create("brush");
}
BrushChannelSet *chset = brush->channels;
@ -1009,6 +1009,7 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH(sharp_mode);
ADDCH(show_origco);
ADDCH(save_temp_layers);
ADDCH(use_surface_falloff);
@ -1522,13 +1523,13 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
namestack_push(__func__);
if (!brush->channels) {
brush->channels = BKE_brush_channelset_create();
brush->channels = BKE_brush_channelset_create("brush 2");
}
if (brush->channels) {
// forcibly reset all non-user-defined channels for this brush
BrushChannelSet *chset = BKE_brush_channelset_create();
BrushChannelSet *chset = BKE_brush_channelset_create("brush 3");
Brush tmp = *brush;
tmp.channels = chset;
@ -1542,6 +1543,8 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
BKE_brush_channel_copy_data(ch, ch2, false);
}
}
BKE_brush_channelset_free(chset);
}
BrushChannelSet *chset = brush->channels;
@ -1851,6 +1854,7 @@ void BKE_brush_check_toolsettings(Sculpt *sd)
ADDCH(unprojected_radius);
ADDCH(show_origco);
ADDCH(save_temp_layers);
ADDCH(smooth_strength_factor);
ADDCH(smooth_strength_projection);

View File

@ -4678,10 +4678,15 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
int custom_max_steps,
bool disable_surface_relax)
{
/* disable surface smooth if uv layers are present, to avoid expensive reprojection operation */
if (CustomData_has_layer(&pbvh->bm->ldata, CD_MLOOPUV)) {
disable_surface_relax = true;
}
/* 2 is enough for edge faces - manifold edge */
BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32);
const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK);
const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
const int cd_face_node_offset = pbvh->cd_face_node_offset;

View File

@ -1700,6 +1700,9 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->building_vp_handle = false;
ss->scene = scene;
if (sd->channels) {
ss->save_temp_layers = BRUSHSET_GET_INT(sd->channels, save_temp_layers, NULL);
}
if (need_mask) {
if (mmd == NULL) {

View File

@ -1073,7 +1073,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
BKE_brush_channelset_read(reader, sce->toolsettings->sculpt->channels);
}
else if (sce->toolsettings->sculpt) {
sce->toolsettings->sculpt->channels = BKE_brush_channelset_create();
sce->toolsettings->sculpt->channels = BKE_brush_channelset_create("sculpt toolsettings");
}
if (sce->toolsettings->sculpt) {
@ -1640,7 +1640,7 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->sculpt->channels = BKE_brush_channelset_copy(ts->sculpt->channels);
}
else {
ts->sculpt->channels = BKE_brush_channelset_create();
ts->sculpt->channels = BKE_brush_channelset_create("sculpt toolsettings");
}
BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag);

View File

@ -514,6 +514,10 @@ static bool sculpt_temp_customlayer_get(SculptSession *ss,
bool autocreate,
SculptLayerParams *params)
{
if (ss->save_temp_layers && !params->simple_array) {
params->permanent = true;
}
bool simple_array = params->simple_array;
bool permanent = params->permanent;
bool nocopy = params->nocopy;
@ -4657,6 +4661,8 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
const Brush *brush = data->brush;
PBVHNode *node = data->nodes[n];
bool do_reproject = SCULPT_need_reproject(ss);
float direction[3];
copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
@ -4750,7 +4756,10 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
float *co = vd.co;
float oldco[3];
float oldno[3];
copy_v3_v3(oldco, co);
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
SCULPT_bmesh_four_neighbor_average(ss,
avg,
@ -4774,6 +4783,10 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
madd_v3_v3v3fl(val, co, val, fade);
SCULPT_clip(sd, ss, co, val);
if (do_reproject) {
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
}
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
@ -6064,6 +6077,8 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
const bool do_reproject = SCULPT_need_reproject;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
@ -6080,8 +6095,17 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
vd.vertex,
thread_id);
float oldco[3], oldno[3];
copy_v3_v3(oldco, vd.co);
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, SCULPT_BOUNDARY_DEFAULT, vd.co);
if (do_reproject) {
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
}
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
@ -12171,13 +12195,13 @@ void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerR
// should not happen!
printf("had to create brush->channels for brush '%s'!", brush->id.name + 2);
brush->channels = BKE_brush_channelset_create();
brush->channels = BKE_brush_channelset_create("brush 0");
BKE_brush_builtin_patch(brush, brush->sculpt_tool);
BKE_brush_channelset_compat_load(brush->channels, brush, true);
}
if (brush->channels && sd->channels) {
ss->cache->channels_final = BKE_brush_channelset_create();
ss->cache->channels_final = BKE_brush_channelset_create("channels_final");
BKE_brush_channelset_merge(ss->cache->channels_final, brush->channels, sd->channels);
}
else if (brush->channels) {

View File

@ -559,6 +559,10 @@ void SCULPT_dyntopo_ensure_templayer(SculptSession *ss,
const char *name,
bool not_temporary)
{
if (ss->save_temp_layers) {
not_temporary = true;
}
int li = CustomData_get_named_layer_index(&ss->bm->vdata, type, name);
if (li < 0) {

View File

@ -559,6 +559,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
bool do_reproject = SCULPT_need_reproject(ss);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@ -579,11 +581,19 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
CLAMP(fade, 0.0f, 1.0f);
float oldco[3], oldno[3];
copy_v3_v3(oldco, vd.co);
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
SCULPT_relax_vertex(
ss, &vd, fade * bstrength, SCULPT_BOUNDARY_DEFAULT | SCULPT_BOUNDARY_FACE_SET, vd.co);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
if (do_reproject) {
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
}
}
BKE_pbvh_vertex_iter_end;
}

View File

@ -346,10 +346,14 @@ static void mesh_filter_task_cb(void *__restrict userdata,
BKE_pbvh_check_tri_areas(ss->pbvh, node);
}
bool do_reproject = SCULPT_need_reproject(ss);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
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 orig_co[3], oldco[3], oldno[3], val[3], avg[3], normal[3], disp[3];
float disp2[3], transform[3][3], final_pos[3];
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
@ -363,6 +367,9 @@ static void mesh_filter_task_cb(void *__restrict userdata,
continue;
}
copy_v3_v3(oldco, vd.co);
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
if (ELEM(filter_type, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
copy_v3_v3(orig_co, vd.co);
}
@ -549,6 +556,16 @@ static void mesh_filter_task_cb(void *__restrict userdata,
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
if (do_reproject && ELEM(filter_type,
MESH_FILTER_SMOOTH,
MESH_FILTER_SURFACE_SMOOTH,
MESH_FILTER_RELAX,
MESH_FILTER_RELAX_FACE_SETS,
MESH_FILTER_ENHANCE_DETAILS,
MESH_FILTER_SHARPEN)) {
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
}
}
BKE_pbvh_vertex_iter_end;

View File

@ -779,22 +779,21 @@ void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], SculptVer
/* Mask the mesh boundaries smoothing only the mesh surface without using automasking. */
#if 0
void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float result[3],
SculptVertRef vertex,
float projection,
float slide_fset,
float bound_smooth,
SculptCustomLayer *bound_scl,
bool do_origco);
#endif
void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float result[3],
SculptVertRef vertex,
SculptSmoothArgs *args);
BLI_INLINE bool SCULPT_need_reproject(SculptSession *ss)
{
return ss->bm && CustomData_has_layer(&ss->bm->ldata, CD_MLOOPUV);
}
void SCULPT_reproject_cdata(SculptSession *ss,
SculptVertRef vertex,
float origco[3],
float origno[3]);
void SCULPT_smooth_vcol_boundary(
Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength);

View File

@ -25,13 +25,16 @@
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
#include "BLI_array.h"
#include "BLI_blenlib.h"
#include "BLI_compiler_attrs.h"
#include "BLI_compiler_compat.h"
#include "BLI_hash.h"
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
@ -77,6 +80,243 @@
#include "BLI_compiler_compat.h"
#include "BLI_utildefines.h"
void SCULPT_reproject_cdata(SculptSession *ss,
SculptVertRef vertex,
float origco[3],
float origno[3])
{
BMVert *v = (BMVert *)vertex.i;
if (!ss->bm || !v->e) {
return;
}
// int totuv = CustomData_number_of_layers(&ss->bm->ldata, CD_MLOOPUV);
CustomData *ldata = &ss->bm->ldata;
int totuv = 0;
CustomDataLayer *uvlayer = NULL;
if (ldata->typemap[CD_MLOOPUV] != -1) {
for (int i = ldata->typemap[CD_MLOOPUV];
i < ldata->totlayer && ldata->layers[i].type == CD_MLOOPUV;
i++) {
totuv++;
}
uvlayer = ldata->layers + ldata->typemap[CD_MLOOPUV];
}
BMEdge *e;
int tag = BM_ELEM_TAG_ALT;
float origin[3];
float ray[3];
copy_v3_v3(origin, v->co);
copy_v3_v3(ray, v->no);
negate_v3(ray);
struct IsectRayPrecalc precalc;
isect_ray_tri_watertight_v3_precalc(&precalc, ray);
float *lastuvs = BLI_array_alloca(lastuvs, totuv * 2);
e = v->e;
/* first clear some flags */
do {
e->head.api_flag &= ~tag;
BMLoop *l = e->l;
do {
l->head.hflag &= ~tag;
l->next->head.hflag &= ~tag;
l->prev->head.hflag &= ~tag;
} while ((l = l->radial_next) != e->l);
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
BMLoop **ls = NULL;
BLI_array_staticdeclare(ls, 32);
bool first = true;
bool bad = false;
do {
BMLoop *l = e->l;
if (!l) {
continue;
}
#if 0
bool bound = l == l->radial_next;
// check for faceset boundaries
bound = bound || (BM_ELEM_CD_GET_INT(l->f, ss->cd_faceset_offset) !=
BM_ELEM_CD_GET_INT(l->radial_next->f, ss->cd_faceset_offset));
// check for seam and sharp edges
bound = bound || (e->head.hflag & BM_ELEM_SEAM) || !(e->head.hflag & BM_ELEM_SMOOTH);
if (bound) {
continue;
}
#endif
do {
BMLoop *l2 = l->v != v ? l->next : l;
if (l2->head.hflag & tag) {
continue;
}
l2->head.hflag |= tag;
BLI_array_append(ls, l2);
for (int i = 0; i < totuv; i++) {
const int cd_uv = uvlayer[i].offset;
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l2, cd_uv);
// check that we are not part of a uv seam
if (!first) {
const float dx = lastuvs[i * 2] - luv->uv[0];
const float dy = lastuvs[i * 2 + 1] - luv->uv[1];
const float eps = 0.00001f;
if (fabsf(dx * dx + dy * dy) > eps) {
bad = true;
break;
}
}
lastuvs[i * 2] = luv->uv[0];
lastuvs[i * 2 + 1] = luv->uv[1];
}
if (bad) {
break;
}
} while ((l = l->radial_next) != e->l);
if (bad) {
break;
}
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
if (bad || !BLI_array_len(ls)) {
return;
}
int totloop = BLI_array_len(ls);
const float *v_proj_axis = v->no;
float v_proj[3][3];
MSculptVert *mv = BKE_PBVH_SCULPTVERT(ss->cd_sculpt_vert, v);
project_plane_normalized_v3_v3v3(v_proj[1], mv->origco, v_proj_axis);
/* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */
char *_blocks = alloca(ldata->totsize * totloop);
void **blocks = BLI_array_alloca(blocks, totloop);
for (int i = 0; i < totloop; i++, _blocks += ldata->totsize) {
blocks[i] = (void *)_blocks;
}
float vco[3], vno[3];
copy_v3_v3(vco, v->co);
copy_v3_v3(vno, v->no);
BMFace _fakef, *fakef = &_fakef;
#if 0
BMFace *projf = NULL;
// find face vertex projects into
for (int i = 0; i < totloop; i++) {
BMLoop *l = ls[i];
copy_v3_v3(ray, l->f->no);
negate_v3(ray);
float t, uv[2];
//*
bool hit = isect_ray_tri_v3(origin, ray, l->prev->v->co, origco, l->next->v->co, &t, uv);
if (hit) {
projf = l->f;
break;
} //*/
}
if (!projf) {
return;
}
#endif
// build fake f with original coordinates
for (int i = 0; i < totloop; i++) {
// create fake face
BMLoop *l = ls[i];
float no[3] = {0.0f, 0.0f, 0.0f};
BMLoop *fakels = BLI_array_alloca(fakels, l->f->len);
BMVert *fakevs = BLI_array_alloca(fakevs, l->f->len);
BMLoop *l2 = l->f->l_first;
BMLoop *fakel = fakels;
BMVert *fakev = fakevs;
int j = 0;
do {
*fakel = *l2;
fakel->next = fakels + ((j + 1) % l->f->len);
fakel->prev = fakels + ((j + l->f->len - 1) % l->f->len);
*fakev = *l2->v;
fakel->v = fakev;
SCULPT_vertex_check_origdata(ss, (SculptVertRef){.i = (intptr_t)l2->v});
if (l2->v == v) {
copy_v3_v3(fakev->co, origco);
copy_v3_v3(fakev->no, origno);
add_v3_v3(no, origno);
}
else {
add_v3_v3(no, l2->v->no);
}
fakel++;
fakev++;
j++;
} while ((l2 = l2->next) != l->f->l_first);
*fakef = *l->f;
fakef->l_first = fakels;
// set original face normal
// normalize_v3(no);
// copy_v3_v3(fakef->no, no);
// interpolate
BMLoop _interpl, *interpl = &_interpl;
MSculptVert saved = *mv;
*interpl = *l;
interpl->head.data = blocks[i];
// memcpy(interpl->head.data, l2->head.data, ldata->totsize);
BM_loop_interp_from_face(ss->bm, interpl, fakef, false, false);
*mv = saved;
CustomData_bmesh_copy_data(&ss->bm->ldata, &ss->bm->ldata, interpl->head.data, &l->head.data);
}
BLI_array_free(ls);
}
MINLINE float safe_shell_angle_to_dist(const float angle)
{
float th = cosf(angle);
@ -93,6 +333,11 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
SculptVertRef vertex,
SculptSmoothArgs *args)
{
if (args->do_origco) {
// copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex));
// return;
}
float avg[3] = {0.0f, 0.0f, 0.0f};
float projection = args->projection;
@ -133,6 +378,10 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
}
}
float startco[3], startno[3];
copy_v3_v3(startco, co);
copy_v3_v3(startno, no);
const bool weighted = args->do_weighted_smooth && !is_boundary;
float *areas = NULL;
@ -1131,7 +1380,13 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
// continue;
//}
float startco[3], startno[3];
copy_v3_v3(startco, vd.co);
SCULPT_vertex_normal_get(ss, vd.vertex, startno);
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;
@ -1166,6 +1421,9 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
madd_v3_v3v3fl(val, co, val, fade);
SCULPT_clip(sd, ss, co, val);
if (step == 0) {
SCULPT_reproject_cdata(ss, vd.vertex, startco, startno);
}
// interp_v3_v3v3(vel, vel, val, 0.5);
}
}
@ -1437,6 +1695,8 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
bool check_fsets = ss->cache->brush->flag2 & BRUSH_SMOOTH_PRESERVE_FACE_SETS;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
bool do_reproject = SCULPT_need_reproject(ss);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
@ -1454,6 +1714,11 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
thread_id);
float disp[3];
float oldco[3], oldno[3];
copy_v3_v3(oldco, vd.co);
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
SCULPT_surface_smooth_laplacian_step(ss,
disp,
vd.co,
@ -1469,6 +1734,10 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
if (do_reproject) {
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
}
modified = true;
}
BKE_pbvh_vertex_iter_end;
@ -1592,6 +1861,13 @@ static void SCULPT_do_directional_smooth_task_cb_ex(void *__restrict userdata,
float avg[3] = {0.0f, 0.0f, 0.0f};
int neighbor_count = 0;
float oldco[3], oldno[3];
copy_v3_v3(oldco, vd.co);
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
bool do_reproject = SCULPT_need_reproject(ss);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vertex_neighbor_disp[3];
@ -1618,6 +1894,10 @@ static void SCULPT_do_directional_smooth_task_cb_ex(void *__restrict userdata,
madd_v3_v3v3fl(final_disp, vd.co, final_disp, fade);
SCULPT_clip(data->sd, ss, vd.co, final_disp);
if (do_reproject) {
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
}
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
@ -1660,6 +1940,8 @@ static void SCULPT_do_uniform_weigths_smooth_task_cb_ex(void *__restrict userdat
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
bool do_reproject = SCULPT_need_reproject(ss);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@ -1677,6 +1959,11 @@ static void SCULPT_do_uniform_weigths_smooth_task_cb_ex(void *__restrict userdat
float len_accum = 0;
int tot_neighbors = 0;
float oldco[3], oldno[3];
copy_v3_v3(oldco, vd.co);
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
len_accum += len_v3v3(SCULPT_vertex_co_get(ss, vd.vertex),
@ -1718,6 +2005,11 @@ static void SCULPT_do_uniform_weigths_smooth_task_cb_ex(void *__restrict userdat
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
if (do_reproject) {
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
}
BKE_pbvh_vertex_iter_end;
}
}