Sculpt: fix symmetry bug and mesh filter

smooth improvements

* Fixed symmetry bug
* Exposed a few hard edge options to the mesh filter tool
* Updated default brushes inside of startup.blend.
This commit is contained in:
Joseph Eagar 2021-10-11 04:25:47 -07:00
parent 6c16801001
commit 318bc8ea42
13 changed files with 249 additions and 58 deletions

Binary file not shown.

View File

@ -1346,6 +1346,15 @@ class _defs_sculpt:
elif props.type == 'SPHERE':
layout.prop(props, "sphere_center", expand=False)
if props.type in ["SMOOTH", "SPHERE", "SURFACE_SMOOTH", "SHARPEN"]:
layout.prop(props, "weighted")
if props.type == "SMOOTH":
#layout.prop(props, "hard_edge_fac")
layout.prop(props, "hard_edge_mode")
layout.prop(props, "preserve_fset_boundaries")
layout.prop(props, "bound_smooth_radius")
return dict(idname="builtin.mesh_filter",
label="Mesh Filter",
icon="ops.sculpt.mesh_filter",

View File

@ -162,9 +162,13 @@ void BKE_brush_default_input_curves_set(struct Brush *brush);
#define BKE_brush_tool_set(brush, p, tool) \
{ \
CHECK_TYPE_ANY(brush, struct Brush *); \
char _old = *(char *)POINTER_OFFSET(brush, (p)->runtime.tool_offset); \
*(char *)POINTER_OFFSET(brush, (p)->runtime.tool_offset) = tool; \
if ((p)->runtime.ob_mode == OB_MODE_SCULPT) { \
BKE_brush_builtin_patch(brush, tool); \
if (_old != tool) { \
BKE_brush_sculpt_reset(brush, tool); \
} \
} \
} \
((void)0)

View File

@ -537,7 +537,7 @@ BrushFlagMap brush_flags_map[] = {
DEF(flag, accumulate, BRUSH_ACCUMULATE)
DEF(flag2, use_weighted_smooth, BRUSH_SMOOTH_USE_AREA_WEIGHT)
DEF(flag2, preserve_faceset_boundary, BRUSH_SMOOTH_PRESERVE_FACE_SETS)
DEF(flag2, hard_edge_mode, BRUSH_HARD_EDGE_MODE)
//DEF(flag2, hard_edge_mode, BRUSH_HARD_EDGE_MODE) don't convert, this only existed on temp_bmesh_multires
DEF(flag2, grab_silhouette, BRUSH_GRAB_SILHOUETTE)
DEF(flag, invert_to_scrape_fill, BRUSH_INVERT_TO_SCRAPE_FILL)
DEF(flag2, use_multiplane_scrape_dynamic, BRUSH_MULTIPLANE_SCRAPE_DYNAMIC)
@ -1703,13 +1703,14 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
break;
case SCULPT_TOOL_CREASE:
GETCH(direction)->ivalue = true;
GETCH(strength)->fvalue = 0.25;
GETCH(strength)->fvalue = 0.25f;
GETCH(crease_pinch_factor)->fvalue = 0.5f;
break;
case SCULPT_TOOL_SCRAPE:
case SCULPT_TOOL_FILL:
GETCH(strength)->fvalue = 0.7f;
GETCH(area_radius_factor)->fvalue = 0.5f;
GETCH(spacing)->fvalue = 7;
GETCH(spacing)->fvalue = 7.0f;
ADDCH(invert_to_scrape_fill);
GETCH(invert_to_scrape_fill)->ivalue = true;
GETCH(accumulate)->ivalue = true;
@ -1805,6 +1806,11 @@ void BKE_brush_channelset_check_radius(BrushChannelSet *chset)
return;
}
if (ch1->fvalue == 0.0 || ch2->fvalue == 0.0) {
ch1->fvalue = 100.0f;
ch2->fvalue = 0.1f;
}
int mask = BRUSH_CHANNEL_INHERIT | BRUSH_CHANNEL_INHERIT_IF_UNSET |
/*BRUSH_CHANNEL_SHOW_IN_HEADER | BRUSH_CHANNEL_SHOW_IN_WORKSPACE |*/
BRUSH_CHANNEL_UI_EXPANDED;

View File

@ -1510,8 +1510,9 @@ static void layerDynTopoVert_copy(const void *source, void *dest, int count)
static void layerDynTopoVert_interp(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
float co[3], no[3], origmask, color[4];
float co[3], no[3], origmask, color[4], curv;
MSculptVert *mv = (MSculptVert *)dest;
// float totweight = 0.0f;
if (count == 0) {
@ -1522,6 +1523,7 @@ static void layerDynTopoVert_interp(
zero_v3(co);
zero_v3(no);
origmask = 0.0f;
curv = 0.0f;
zero_v4(color);
for (int i = 0; i < count; i++) {
@ -1538,7 +1540,8 @@ static void layerDynTopoVert_interp(
madd_v3_v3fl(co, mv2->origco, w);
madd_v3_v3fl(no, mv2->origno, w);
madd_v4_v4fl(color, mv2->origcolor, w);
origmask += mv2->origmask * w;
origmask += (float)mv2->origmask * w;
curv += (float)mv2->curv * w;
// totweight += w;
}
@ -1561,7 +1564,8 @@ static void layerDynTopoVert_interp(
copy_v3_v3(mv->origno, no);
copy_v4_v4(mv->origcolor, color);
mv->origmask = origmask;
mv->curv = (short)curv;
mv->origmask = (short)origmask;
}
static void layerInterp_noop(const void **UNUSED(sources),

View File

@ -35,6 +35,7 @@
#include <stdio.h>
//#define DYNTOPO_REPORT
//#define WITH_ADAPTIVE_CURVATURE
#define SCULPTVERT_VALENCE_TEMP SCULPTVERT_SPLIT_TEMP
@ -1422,8 +1423,10 @@ static void edge_queue_insert_val34_vert(EdgeQueueContext *eq_ctx, BMVert *v)
eq_ctx->val34_verts[eq_ctx->val34_verts_tot - 1] = v;
}
BLI_INLINE float maskcb_get(EdgeQueueContext *eq_ctx, BMEdge *e)
ATTR_NO_OPT static float maskcb_get(EdgeQueueContext *eq_ctx, BMEdge *e)
{
float ret = 0.0f;
if (eq_ctx->mask_cb) {
SculptVertRef sv1 = {(intptr_t)e->v1};
SculptVertRef sv2 = {(intptr_t)e->v2};
@ -1431,13 +1434,16 @@ BLI_INLINE float maskcb_get(EdgeQueueContext *eq_ctx, BMEdge *e)
float w1 = eq_ctx->mask_cb(sv1, eq_ctx->mask_cb_data);
float w2 = eq_ctx->mask_cb(sv2, eq_ctx->mask_cb_data);
return (w1 + w2) * 0.5f;
ret = (w1 + w2) * 0.5f;
}
else {
ret = 1.0f;
}
return 1.0f;
return ret;
}
BLI_INLINE float calc_weighted_edge_split(EdgeQueueContext *eq_ctx, BMVert *v1, BMVert *v2)
ATTR_NO_OPT 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);
@ -1461,12 +1467,27 @@ BLI_INLINE float calc_weighted_edge_split(EdgeQueueContext *eq_ctx, BMVert *v1,
return l;
#else
# 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);
float c1 = (float)mv1->curv / 65535.0f;
float c2 = (float)mv2->curv / 65535.0f;
float fac = 1.0f + powf((c1 + c2) * 100.0, 4.0f);
fac = min_ff(fac, 4.0f);
return fac * len_squared_v3v3(v1->co, v2->co);
# 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);
#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);
@ -1812,7 +1833,7 @@ static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx, BMEdge *e)
#endif
{
const float w = maskcb_get(eq_ctx, e);
const float len_sq = BM_edge_calc_length_squared(e) * w * w;
const float len_sq = calc_weighted_edge_split(eq_ctx, e->v1, e->v2) * w * w;
if (len_sq > eq_ctx->q->limit_len_squared) {
edge_queue_insert(eq_ctx, e, -len_sq, eq_ctx->q->limit_len);
@ -1855,7 +1876,8 @@ static void long_edge_queue_edge_add_recursive(EdgeQueueContext *eq_ctx,
do {
BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
for (int i = 0; i < (int)ARRAY_SIZE(l_adjacent); i++) {
float len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e);
float len_sq_other = calc_weighted_edge_split(
eq_ctx, l_adjacent[i]->e->v1, l_adjacent[i]->e->v2);
float w = maskcb_get(eq_ctx, l_adjacent[i]->e);
len_sq_other *= w * w;
@ -1906,7 +1928,7 @@ static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f, bool i
BMLoop *l_iter = l_first;
do {
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
float len_sq = BM_edge_calc_length_squared(l_iter->e);
float len_sq = calc_weighted_edge_split(eq_ctx, l_iter->e->v1, l_iter->e->v2);
float w = maskcb_get(eq_ctx, l_iter->e);
len_sq *= w * w;
@ -2187,8 +2209,7 @@ static void long_edge_queue_task_cb(void *__restrict userdata,
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
float w = maskcb_get(eq_ctx, l_iter->e);
float len_sq = BM_edge_calc_length_squared(l_iter->e);
float len_sq = calc_weighted_edge_split(eq_ctx, l_iter->e->v1, l_iter->e->v2);
len_sq *= w * w;
if (len_sq > eq_ctx->q->limit_len_squared) {

View File

@ -817,6 +817,10 @@ void BKE_pbvh_bmesh_update_origvert(
BM_log_vert_before_modified(pbvh->bm_log, v, pbvh->cd_vert_mask_offset, r_color != NULL);
}
if (pbvh->cd_vert_mask_offset) {
mv->origmask = (short)(BM_ELEM_CD_GET_FLOAT(v, pbvh->cd_vert_mask_offset) * 65535.0f);
}
if (r_co || r_no) {
copy_v3_v3(mv->origco, v->co);
@ -1489,16 +1493,20 @@ static int color_boundary_key(float col[4])
}
#endif
void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
int cd_faceset_offset,
int cd_vert_node_offset,
int cd_face_node_offset,
int cd_vcol,
BMVert *v,
int bound_symmetry)
ATTR_NO_OPT void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
int cd_faceset_offset,
int cd_vert_node_offset,
int cd_face_node_offset,
int cd_vcol,
BMVert *v,
int bound_symmetry)
{
MSculptVert *mv = BKE_PBVH_SCULPTVERT(cd_sculpt_vert, v);
float avg[3] = {0.0f, 0.0f, 0.0f};
float avg_len = 0.0f;
float curv = 0.0f, totcurv = 0.0f;
BMEdge *e = v->e;
mv->flag &= ~(SCULPTVERT_BOUNDARY | SCULPTVERT_FSET_BOUNDARY | SCULPTVERT_NEED_BOUNDARY |
SCULPTVERT_NEED_TRIANGULATE | SCULPTVERT_FSET_CORNER | SCULPTVERT_CORNER |
@ -1536,6 +1544,17 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
do {
BMVert *v2 = v == e->v1 ? e->v2 : e->v1;
#if 0
float tmp[3];
sub_v3_v3v3(tmp, v2->co, v->co);
madd_v3_v3fl(avg, v->no, -dot_v3v3(v->no, tmp));
// madd_v3_v3fl(tmp, v->no, -dot_v3v3(v->no, tmp));
add_v3_v3(avg, tmp);
avg_len += len_squared_v3(tmp);
totcurv += 1.0f;
#endif
if (BM_ELEM_CD_GET_INT(v2, cd_vert_node_offset) != ni) {
mv->flag |= SCULPTVERT_PBVH_BOUNDARY;
}
@ -1612,6 +1631,11 @@ 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;
// th = th * 0.5 + 0.5;
curv += th;
totcurv += 1.0f;
// fset = abs(BM_ELEM_CD_GET_INT(e->l->radial_next->f, cd_faceset_offset));
int fset2 = BKE_pbvh_do_fset_symmetry(
BM_ELEM_CD_GET_INT(e->l->radial_next->f, cd_faceset_offset), bound_symmetry, v2->co);
@ -1661,6 +1685,27 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
mv->flag |= SCULPTVERT_CORNER;
}
#if 0
if (totcurv > 0.0f) {
mul_v3_fl(avg, 1.0f / totcurv);
avg_len /= totcurv;
}
if (avg_len > 0.0f) {
curv = len_squared_v3(avg) / avg_len;
}
else {
curv = 0.0f;
}
#else
if (totcurv > 0.0f) {
curv /= totcurv;
}
#endif
// mv->curv = (short)(fabsf(min_ff(curv * 50.0f, 1.0f)) * 32767.0f);
mv->curv = (short)(min_ff(fabsf(curv), 1.0f) * 65535.0f);
BLI_array_free(fsets);
}

View File

@ -2985,7 +2985,7 @@ bool SCULPT_vertex_check_origdata(SculptSession *ss, SculptVertRef vertex)
copy_v4_v4(mv->origcolor, color);
}
mv->origmask = SCULPT_vertex_mask_get(ss, vertex);
mv->origmask = (short)(SCULPT_vertex_mask_get(ss, vertex) * 65535.0f);
return false;
}
@ -3014,7 +3014,7 @@ void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, SculptVertRef v
orig_data->col = mv->origcolor;
}
else if (orig_data->datatype == SCULPT_UNDO_MASK) {
orig_data->mask = mv->origmask;
orig_data->mask = (float)mv->origmask / 65535.0f;
}
}
@ -9690,12 +9690,6 @@ static void SCULPT_run_command(
/*create final, input mapped parameter list*/
BKE_brush_channelset_free(cmd->params_mapped);
cmd->params_mapped = BKE_brush_channelset_copy(cmd->params_final);
BKE_brush_channelset_apply_mapping(cmd->params_mapped, &ss->cache->input_mapping);
BKE_brush_channelset_clear_inherit(cmd->params_mapped);
radius_scale = 1.0f;
*brush2 = *brush;
@ -10071,6 +10065,14 @@ static void SCULPT_run_commandlist(
.totnode = 0,
.radius_max = radius_max}; //, .nodes = nodes, .totnode = totnode};
if (cmd->params_mapped) {
BKE_brush_channelset_free(cmd->params_mapped);
}
cmd->params_mapped = BKE_brush_channelset_copy(cmd->params_final);
BKE_brush_channelset_apply_mapping(cmd->params_mapped, &ss->cache->input_mapping);
BKE_brush_channelset_clear_inherit(cmd->params_mapped);
do_symmetrical_brush_actions(sd, ob, SCULPT_run_command, ups, &data);
sculpt_combine_proxies(sd, ob);

View File

@ -963,7 +963,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
use_persistent);
}
else if (mp1->totloop == 4) {
ml1 = (ml1 + 1) % mp1->loopstart;
ml1 = (ml1 + 1) % mp1->loopstart;
cloth_brush_add_bend_constraint(ss,
data->cloth_sim,

View File

@ -331,7 +331,20 @@ static void mesh_filter_task_cb(void *__restrict userdata,
/* This produces better results as the relax operation is no completely focused on the
* boundaries. */
const bool relax_face_sets = !(ss->filter_cache->iteration_count % 3 == 0);
const bool weighted = false;
const bool weighted = ss->filter_cache->weighted_smooth;
const bool preserve_fset_boundaries = ss->filter_cache->preserve_fset_boundaries;
// const float hard_edge_fac = ss->filter_cache->hard_edge_fac;
const bool hard_edge_mode = ss->filter_cache->hard_edge_mode;
const float bound_smooth_radius = ss->filter_cache->bound_smooth_radius;
if (ELEM(filter_type,
MESH_FILTER_SMOOTH,
MESH_FILTER_SURFACE_SMOOTH,
MESH_FILTER_SHARPEN,
MESH_FILTER_RELAX,
MESH_FILTER_RELAX_FACE_SETS)) {
BKE_pbvh_check_tri_areas(ss->pbvh, node);
}
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
@ -365,20 +378,24 @@ static void mesh_filter_task_cb(void *__restrict userdata,
switch (filter_type) {
case MESH_FILTER_SMOOTH: {
// float bound_smooth = SCULPT_get_float(ss, boundary_smooth, ss->, ss->cache->brush);
// float projection = SCULPT_get_float(ss, autosmooth_projection, NULL, ss->cache->brush);
// float slide_fset = SCULPT_get_float(ss, fset_slide, NULL, ss->cache->brush);
fade = clamp_f(fade, -1.0f, 1.0f);
float bsmooth = bound_smooth_radius > 0.0f ? 0.5f : 0.0f;
float slide_fset = bound_smooth_radius > 0.0f ?
bsmooth :
1.0f - (float)hard_edge_mode; // powf(1.0 - hard_edge_fac, 0.5f);
SCULPT_neighbor_coords_average_interior(
ss,
avg,
vd.vertex,
&((SculptSmoothArgs){.projection = 0.0f,
.slide_fset = 0.0f,
.bound_smooth = 0.0f,
.preserve_fset_boundaries = false,
.do_weighted_smooth = false}));
.slide_fset = slide_fset, // 1.0f - hard_edge_fac,
.bound_smooth = bsmooth,
.preserve_fset_boundaries = preserve_fset_boundaries,
.do_weighted_smooth = weighted,
.bound_smooth_radius = bound_smooth_radius,
.bound_scl = bsmooth > 0.0f ? &ss->filter_cache->bound_scl :
NULL}));
sub_v3_v3v3(val, avg, orig_co);
madd_v3_v3v3fl(val, orig_co, val, fade);
@ -535,6 +552,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
}
BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_update_tri_area(node);
BKE_pbvh_node_mark_update(node);
}
@ -868,6 +886,17 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
SculptFilterOrientation orientation = RNA_enum_get(op->ptr, "orientation");
ss->filter_cache->orientation = orientation;
ss->filter_cache->weighted_smooth = RNA_boolean_get(op->ptr, "weighted");
ss->filter_cache->preserve_fset_boundaries = RNA_boolean_get(op->ptr,
"preserve_fset_boundaries");
// ss->filter_cache->hard_edge_fac = RNA_float_get(op->ptr, "hard_edge_fac");
ss->filter_cache->hard_edge_mode = RNA_boolean_get(op->ptr, "hard_edge_mode");
ss->filter_cache->bound_smooth_radius = RNA_float_get(op->ptr, "bound_smooth_radius");
if (filter_type == MESH_FILTER_SMOOTH && ss->filter_cache->bound_smooth_radius != 0.0f) {
SCULPT_bound_smooth_init(ss, &ss->filter_cache->bound_scl);
}
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
@ -963,4 +992,28 @@ void SCULPT_OT_mesh_filter(struct wmOperatorType *ot)
MESH_FILTER_SPHERE_CENTER_AVERAGE,
"Sphere Center",
"Position of the center of the sphere created by the filter");
RNA_def_boolean(ot->srna, "weighted", true, "Weighted", "Weight smoothing by face areas");
RNA_def_boolean(ot->srna,
"preserve_fset_boundaries",
true,
"Preserve Face Sets",
"Preserve face set boundaries");
// RNA_def_float(ot->srna, "hard_edge_fac", 0.0f, 0.0f, 1.0f, "Hard Edge Factor", "",
// 0.0f, 1.0f);
RNA_def_boolean(ot->srna,
"hard_edge_mode",
false,
"Hard Edge Mode",
"Treat face set boundaries as hard edges");
RNA_def_float(ot->srna,
"bound_smooth_radius",
0.0,
0.0,
1000.0f,
"Bevel Radius",
"Radius to bevel hard edges, 0 disables",
0.0f,
5.0f);
}

View File

@ -412,6 +412,7 @@ typedef struct SculptSmoothArgs {
bool do_origco : 1;
bool do_weighted_smooth : 1;
bool preserve_fset_boundaries : 1;
float bound_smooth_radius; // if 0, ss->cache->radius will be used
} SculptSmoothArgs;
/* Utils. */
@ -1690,6 +1691,13 @@ typedef struct FilterCache {
GHash *mask_delta_step;
bool preserve_fset_boundaries;
bool weighted_smooth;
float hard_edge_fac;
bool hard_edge_mode;
float bound_smooth_radius;
struct SculptCustomLayer bound_scl;
} FilterCache;
void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
@ -1997,6 +2005,10 @@ void SCULPT_replay_test(void);
struct BMesh *SCULPT_dyntopo_empty_bmesh();
/* initializes customdata layer used by SCULPT_neighbor_coords_average_interior when bound_smooth >
* 0.0f*/
void SCULPT_bound_smooth_init(SculptSession *ss, SculptCustomLayer *r_bound_scl);
#define SCULPT_stroke_needs_original(brush) \
ELEM(brush->sculpt_tool, \
SCULPT_TOOL_DRAW_SHARP, \

View File

@ -74,10 +74,10 @@
#include <math.h>
#include <stdlib.h>
void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float result[3],
SculptVertRef vertex,
SculptSmoothArgs *args)
ATTR_NO_OPT void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float result[3],
SculptVertRef vertex,
SculptSmoothArgs *args)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
@ -155,7 +155,10 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
if (bound_scl) {
b1 = SCULPT_temp_cdata_get(vertex, bound_scl);
b1_orig = *b1;
*b1 = 0.0f;
if (1 || is_boundary) {
*b1 = 0.0f;
}
}
SculptVertexNeighborIter ni;
@ -276,12 +279,22 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
copy_v3_v3(no2, mv2->origno);
}
float radius = ss->cache->radius * 10.0f;
float radius;
if (!args->bound_smooth_radius && ss->cache) {
radius = ss->cache->radius * 1.0f;
}
else {
radius = args->bound_smooth_radius * 1.0f;
}
radius = radius == 0.0f ? 0.0001f : radius;
float th = radius - b1_orig;
th = MAX2(th, 0.0f);
th /= radius;
// th = 1.0 - th;
#if 0
float *color = (float *)SCULPT_vertex_color_get(ss, ni.vertex);
color[0] = color[1] = color[2] = th;
@ -291,10 +304,24 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float fac = bound_smooth;
fac = MIN2(fac * 4.0f, 1.0f);
fac = powf(fac, 0.2);
th *= fac;
// th *= fac;
// th *= shell_angle_to_dist(shellth * 1.0) * 0.5;
sub_v3_v3(tmp, co);
madd_v3_v3fl(tmp, no2, th * dot_v3v3(no2, tmp));
/* jump above the v,no2 plane, using distance from plane (which doubles after this)*/
// sub_v3_v3(tmp, co);
// madd_v3_v3fl(tmp, no2, th * dot_v3v3(no2, tmp));
// add_v3_v3(tmp, co);
th = min_ff(b1_orig / radius, 1.0f);
/*ok this bit smoothes the bevel edges. why? hit on it
by accident.*/
float shellth = saacos(dot_v3v3(no, no2));
shellth = shell_angle_to_dist(shellth * 2.0);
th /= 0.00001 + shellth;
sub_v3_v3v3(tmp, co2, co);
madd_v3_v3fl(tmp, no, -dot_v3v3(no, tmp) * th);
add_v3_v3(tmp, co);
}
@ -353,7 +380,7 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
corner_smooth = MAX2(slide_fset, bound_smooth);
}
else {
corner_smooth = bound_smooth;
corner_smooth = 2.0f * bound_smooth;
}
interp_v3_v3v3(result, result, co, 1.0f - corner_smooth);
@ -1139,6 +1166,13 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
}
#endif
void SCULPT_bound_smooth_init(SculptSession *ss, SculptCustomLayer *r_bound_scl)
{
SculptLayerParams params = {.permanent = true, .simple_array = false};
SCULPT_temp_customlayer_get(
ss, ATTR_DOMAIN_POINT, CD_PROP_COLOR, "t__smooth_bdist", r_bound_scl, &params);
}
void SCULPT_smooth(Sculpt *sd,
Object *ob,
PBVHNode **nodes,
@ -1213,12 +1247,7 @@ void SCULPT_smooth(Sculpt *sd,
bound_smooth = powf(ss->cache->brush->boundary_smooth_factor, BOUNDARY_SMOOTH_EXP);
bound_scl = &_scl;
SculptLayerParams params = {.permanent = false, .simple_array = false};
SCULPT_temp_customlayer_ensure(
ss, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, "__smooth_bdist", &params);
SCULPT_temp_customlayer_get(
ss, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, "__smooth_bdist", bound_scl, &params);
SCULPT_bound_smooth_init(ss, bound_scl);
if (do_vel_smooth) {
SCULPT_temp_customlayer_get(

View File

@ -526,7 +526,7 @@ typedef struct MRecast {
/** \} */
typedef struct MSculptVert {
short flag, valence;
unsigned short flag, valence;
/**original coordinates*/
float origco[3], origno[3];
@ -534,7 +534,13 @@ typedef struct MSculptVert {
/**original color*/
float origcolor[4];
float origmask;
unsigned short origmask;
/* curv is a fast curvature approximation used by dyntopo
adaptive curvature. */
unsigned short curv;
/* curvature_dir parallels a principle curvature direction */
float curvature_dir[3];
/* id of current stroke, used to detect