Sculpt-dev: More improvements to detail enhance

* Detail enhance is now it's own dedicated toolslot.
  This makes it possible to use autosmooth with
  detail enhance.

  Note the behavior of the smooth brush (which
  invokes enhance when pressing control)
  is unchanged.

* Fixed a bug with temporary attribute layers being constantly
  cleared and reallocated with multires.

* Cleaned up velocity smooth code a bit.
* Pruned various dead #if blocks.
* generate_from_enum_ex in space_toolsystem.py
  now takes a special argument to combine enum
  items.  This is used to make enhance a subtool
  of smooth.
This commit is contained in:
Joseph Eagar 2021-12-12 05:03:24 -08:00
parent 0b9e40cc0c
commit 268e18e9a3
18 changed files with 518 additions and 309 deletions

View File

@ -132,7 +132,8 @@ def mesh_data_lists_from_mesh(me, material_colors):
tris_data = []
white = [1, 1, 1, 1]
class white:
color = [1, 1, 1, 1]
for p in me_polys:
# Note, all faces are handled, backfacing/zero area is checked just before writing.
@ -162,7 +163,7 @@ def mesh_data_lists_from_mesh(me, material_colors):
c1 = color_poly[i1]
c2 = color_poly[i2]
else:
c1 = c2 = c3 = white
c0 = c1 = c2 = white
v0 = me_verts[l0.vertex_index]
v1 = me_verts[l1.vertex_index]

View File

@ -1266,6 +1266,13 @@ def brush_settings(layout, context, brush, popover=False):
capabilities = brush.sculpt_capabilities
sculpt_tool = brush.sculpt_tool
if sculpt_tool in ["SMOOTH", "ENHANCE_DETAILS"]:
UnifiedPaintPanel.channel_unified(layout,
context,
brush,
"enhance_detail_presteps",
slider=False)
if advanced:
# normal_radius_factor
UnifiedPaintPanel.prop_unified(layout,

View File

@ -49,19 +49,74 @@ def generate_from_enum_ex(_context, *,
attr,
cursor='DEFAULT',
tooldef_keywords={},
exclude_filter={}):
exclude_filter={},
combine_map={}):
"""
combine_map combines items, takes the form of a dict:
combine_map = {
"PARENT KEY" : (
"CHILD KEY"
)
}
"""
combinekeys = {}
parentmap = {}
for k, v in combine_map.items():
combinekeys[k] = []
for child in v:
parentmap[child] = k
tool_defs = []
#build combine key owners first
for enum in type.bl_rna.properties[attr].enum_items_static:
name = enum.name
idname = enum.identifier
if idname in exclude_filter:
continue
tool_defs.append(ToolDef.from_dict(dict(idname=idname_prefix + name,
if idname in combinekeys:
combinekeys[idname].append(ToolDef.from_dict(dict(idname=idname_prefix + name,
label=name,
icon=icon_prefix + idname.lower(),
cursor=cursor,
data_block=idname,
**tooldef_keywords,)))
for enum in type.bl_rna.properties[attr].enum_items_static:
name = enum.name
idname = enum.identifier
if idname in exclude_filter:
continue
if idname in combinekeys:
tool_defs.append(combinekeys[idname])
elif idname in parentmap:
parentkey = parentmap[idname]
combinekeys[parentkey].append(ToolDef.from_dict(dict(idname=idname_prefix + name,
label=name,
icon=icon_prefix + idname.lower(),
cursor=cursor,
data_block=idname,
**tooldef_keywords,)))
else:
tool_defs.append(ToolDef.from_dict(dict(idname=idname_prefix + name,
label=name,
icon=icon_prefix + idname.lower(),
cursor=cursor,
data_block=idname,
**tooldef_keywords,)))
# finalize combined keys
for k, v in combinekeys.items():
tool_defs[tool_defs.index(v)] = tuple(v)
return tuple(tool_defs)
@ -1170,12 +1225,17 @@ class _defs_sculpt:
#if not prefs.experimental.use_sculpt_uvsmooth:
# exclude_filter["UV_SMOOTH"] = True
combine_map = {
"SMOOTH" : ("ENHANCE_DETAILS",)
}
return generate_from_enum_ex(context,
idname_prefix="builtin_brush.",
icon_prefix="brush.sculpt.",
type=bpy.types.Brush,
attr="sculpt_tool",
exclude_filter=exclude_filter,)
exclude_filter=exclude_filter,
combine_map=combine_map)
@ToolDef.from_fn
def hide_border():

View File

@ -713,6 +713,7 @@ typedef struct SculptSession {
// for grids
CustomData temp_vdata, temp_pdata;
int temp_vdata_elems, temp_pdata_elems;
/* These contain the vertex and poly counts of the final mesh. */
int totvert, totpoly;

View File

@ -630,6 +630,7 @@ MAKE_ENUM(blend,"Blending Mode","Brush blending mode",IMB_BLEND_MIX,{\
MAKE_INT_EX(autofset_start,"Face Set Start","",2,1,1024,1,1024)
MAKE_FLOAT_EX_FLAG(autofset_spacing,"Spacing","Spacing for auto face set",4,1,1000,1,300,false,0)
MAKE_BOOL_EX(autofset_use_spacing,"Use Spacing","Use spacing for auto face set",false,0)
MAKE_INT_EX(enhance_detail_presteps, "Detail Filter", "", 1, 0, 50, 0, 50)
//MAKE_FLOAT3_EX
/* clang-format on */

View File

@ -301,6 +301,7 @@ static bool check_builtin_init()
mdef->blendmode = MA_RAMP_ADD;
}
//SETCAT(enhance_detail_presteps, "Enhancement");
SETCAT(concave_mask_factor, "Automasking");
SETCAT(automasking, "Automasking");
SETCAT(automasking_boundary_edges_propagation_steps, "Automasking");
@ -1203,7 +1204,7 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH(cloth_use_collision);
ADDCH(cloth_solve_bending);
ADDCH(cloth_bending_stiffness);
switch (tool) {
case SCULPT_TOOL_CLAY:
if (set_mappings) {
@ -1280,6 +1281,10 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
case SCULPT_TOOL_CREASE:
ADDCH(crease_pinch_factor);
break;
case SCULPT_TOOL_SMOOTH:
case SCULPT_TOOL_ENHANCE_DETAILS:
ADDCH(enhance_detail_presteps);
break;
case SCULPT_TOOL_POSE:
ADDCH(deform_target);
ADDCH(disconnected_distance_max);
@ -1379,6 +1384,7 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
SCULPT_TOOL_FAIRING,
SCULPT_TOOL_DRAW_FACE_SETS,
SCULPT_TOOL_SMOOTH,
SCULPT_TOOL_ENHANCE_DETAILS,
SCULPT_TOOL_SIMPLIFY)) {
SHOWALL(accumulate);
@ -1434,7 +1440,13 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
SHOWCTX(autosmooth);
SHOWALL(crease_pinch_factor);
SHOWWRK(autosmooth);
break;
case SCULPT_TOOL_ENHANCE_DETAILS:
SHOWCTX(dyntopo_disabled);
SHOWALL(enhance_detail_presteps);
break;
case SCULPT_TOOL_SMOOTH:
SHOWALL(enhance_detail_presteps);
SHOWWRK(surface_smooth_shape_preservation);
SHOWWRK(surface_smooth_current_vertex);
SHOWWRK(surface_smooth_iterations);
@ -1836,6 +1848,12 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
break;
}
case SCULPT_TOOL_ENHANCE_DETAILS:
BRUSHSET_SET_BOOL(chset, use_space_attenuation, false);
BRUSHSET_SET_BOOL(chset, dyntopo_disabled, true);
BRUSHSET_SET_FLOAT(chset, spacing, 5.0f);
BRUSHSET_SET_FLOAT(chset, strength, 0.3f);
break;
case SCULPT_TOOL_SMOOTH:
BRUSHSET_SET_BOOL(chset, use_space_attenuation, false);
BRUSHSET_SET_FLOAT(chset, spacing, 5.0f);

View File

@ -1510,6 +1510,9 @@ void BKE_sculptsession_free(Object *ob)
BM_mesh_free(ss->bm);
}
CustomData_free(&ss->temp_vdata, ss->temp_vdata_elems);
CustomData_free(&ss->temp_pdata, ss->temp_pdata_elems);
sculptsession_free_pbvh(ob);
for (int i = 0; i < SCULPT_SCL_LAYER_MAX; i++) {
@ -2470,6 +2473,9 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
MEM_SAFE_FREE(ss->face_areas);
ss->face_areas = MEM_calloc_arrayN(totgridfaces, sizeof(float) * 2, "ss->face_areas");
CustomData_reset(&ob->sculpt->temp_vdata);
CustomData_reset(&ob->sculpt->temp_pdata);
BKE_pbvh_build_grids(pbvh,
subdiv_ccg->grids,
subdiv_ccg->num_grids,
@ -2480,10 +2486,14 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
ob->sculpt->fast_draw,
ss->face_areas);
ss->temp_vdata_elems = BKE_pbvh_get_grid_num_vertices(pbvh);
ss->temp_pdata_elems = ss->totfaces;
BKE_sculptsession_check_mdyntopo(ob->sculpt, pbvh, 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;
}
@ -2672,6 +2682,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
ob->sculpt->pbvh = pbvh;
BKE_sculptsession_update_attr_refs(ob);
if (pbvh) {
SCULPT_update_flat_vcol_shading(ob, scene);
}
@ -2995,10 +3007,6 @@ static bool sculpt_temp_customlayer_get(SculptSession *ss,
__func__);
permanent = false;
}
// customdata attribute layers not supported for grids
simple_array = true;
out->params.simple_array = true;
}
BLI_assert(!(simple_array && permanent));
@ -3194,6 +3202,7 @@ static bool sculpt_temp_customlayer_get(SculptSession *ss,
out->cd_offset = -1;
out->data = out->layer->data;
out->elemsize = CustomData_get_elem_size(out->layer);
break;
}
case PBVH_GRIDS: {
@ -3208,8 +3217,8 @@ static bool sculpt_temp_customlayer_get(SculptSession *ss,
cdata = &ss->temp_vdata;
break;
case ATTR_DOMAIN_FACE:
// not supported
return false;
totelem = ss->totfaces;
cdata = &ss->temp_pdata;
default:
return false;
}
@ -3224,9 +3233,9 @@ static bool sculpt_temp_customlayer_get(SculptSession *ss,
CustomData_add_layer_named(cdata, proptype, CD_CALLOC, NULL, totelem, name);
idx = CustomData_get_named_layer_index(cdata, proptype, name);
if (!permanent) {
//if (!permanent) {
cdata->layers[idx].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY;
}
//}
}
if (nocopy) {

View File

@ -4553,13 +4553,56 @@ void BKE_pbvh_get_vert_face_areas(PBVH *pbvh, SculptVertRef vertex, float *r_are
break;
}
default:
// not supported
for (int i = 0; i < valence; i++) {
case PBVH_GRIDS: { /* estimate from edge lengths */
int index = (int)vertex.i;
const CCGKey *key = BKE_pbvh_get_grid_key(pbvh);
const int grid_index = index / key->grid_area;
const int vertex_index = index - grid_index * key->grid_area;
SubdivCCGCoord coord = {.grid_index = grid_index,
.x = vertex_index % key->grid_size,
.y = vertex_index / key->grid_size};
SubdivCCGNeighbors neighbors;
BKE_subdiv_ccg_neighbor_coords_get(pbvh->subdiv_ccg, &coord, false, &neighbors);
float *co1 = CCG_elem_co(key, CCG_elem_offset(key, pbvh->grids[grid_index], vertex_index));
float totw = 0.0f;
int i = 0;
for (i = 0; i < neighbors.size; i++) {
SubdivCCGCoord *coord2 = neighbors.coords + i;
int vertex_index2 = coord2->y * key->grid_size + coord2->x;
int index2 = coord2->grid_index * key->grid_area + vertex_index2;
float *co2 = CCG_elem_co(
key, CCG_elem_offset(key, pbvh->grids[coord2->grid_index], vertex_index2));
float w = len_v3v3(co1, co2);
// w = sqrtf(w);
// w *= w;
r_areas[i] = w;
totw += w;
}
if (neighbors.size != valence) {
printf("%s: error!\n", __func__);
}
if (totw < 0.000001f) {
for (int i = 0; i < neighbors.size; i++) {
r_areas[i] = 1.0f;
}
}
for (; i < valence; i++) {
r_areas[i] = 1.0f;
}
break;
}
}
}

View File

@ -1799,7 +1799,7 @@ static float fast_ray_nearest_hit(const BVHRayCastData *data, const BVHNode *nod
return max_fff(t1x, t1y, t1z);
}
ATTR_NO_OPT static void dfs_raycast(BVHRayCastData *data, BVHNode *node)
static void dfs_raycast(BVHRayCastData *data, BVHNode *node)
{
int i;

View File

@ -757,6 +757,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.draw_face_sets
brush.sculpt.draw_sharp
brush.sculpt.elastic_deform
brush.sculpt.enhance_details
brush.sculpt.fairing
brush.sculpt.fill
brush.sculpt.flatten

View File

@ -925,6 +925,7 @@ DEF_ICON_COLOR(BRUSH_SCULPT_SMEAR)
DEF_ICON_COLOR(BRUSH_SCENE_PROJECT)
DEF_ICON_COLOR(BRUSH_SCENE_FAIRING)
DEF_ICON_COLOR(BRUSH_ARRAY)
DEF_ICON_COLOR(BRUSH_ENHANCE_DETAILS)
/* grease pencil sculpt */
DEF_ICON_COLOR(GPBRUSH_SMOOTH)

View File

@ -4068,6 +4068,7 @@ static float brush_strength(const Sculpt *sd,
return 0.5f * alpha * flip * pressure * overlap * feather;
}
case SCULPT_TOOL_ENHANCE_DETAILS:
case SCULPT_TOOL_SMOOTH: {
const float smooth_strength_base = flip * pressure * feather;
// if (cache->alt_smooth) {
@ -5479,6 +5480,9 @@ void do_brush_action(
case SCULPT_TOOL_UV_SMOOTH:
SCULPT_uv_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ENHANCE_DETAILS:
SCULPT_enhance_details_brush(sd, ob, nodes, totnode, SCULPT_get_int(ss, enhance_detail_presteps, sd, brush));
break;
}
bool apply_autosmooth = !ELEM(SCULPT_get_tool(ss, brush),
@ -6042,6 +6046,10 @@ static void SCULPT_run_command(
case SCULPT_TOOL_AUTO_FSET:
SCULPT_do_auto_face_set(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ENHANCE_DETAILS:
SCULPT_enhance_details_brush(
sd, ob, nodes, totnode, SCULPT_get_int(ss, enhance_detail_presteps, sd, brush));
break;
}
if (ss->needs_pbvh_rebuild) {
@ -7947,7 +7955,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
/* Update the active vertex of the SculptSession. */
ss->active_vertex_index = srd.active_vertex_index;
//SCULPT_vertex_random_access_ensure(ss);
// SCULPT_vertex_random_access_ensure(ss);
copy_v3_v3(out->active_vertex_co, SCULPT_active_vertex_co_get(ss));
switch (BKE_pbvh_type(ss->pbvh)) {
@ -8924,6 +8932,9 @@ static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene,
ob->sculpt->active_face_index.i = SCULPT_REF_NONE;
ob->sculpt->active_vertex_index.i = SCULPT_REF_NONE;
CustomData_reset(&ob->sculpt->temp_vdata);
CustomData_reset(&ob->sculpt->temp_pdata);
BKE_sculpt_ensure_orig_mesh_data(scene, ob);
BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
@ -9868,36 +9879,13 @@ static void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
int SCULPT_vertex_valence_get(const struct SculptSession *ss, SculptVertRef vertex)
{
SculptVertexNeighborIter ni;
int tot = 0;
#if 0
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BMVert *v = (BMVert *)vertex.i;
MSculptVert *mv = BKE_PBVH_SCULPTVERT(ss->cd_sculpt_vert, v);
if (mv->flag & SCULPTVERT_NEED_VALENCE) {
BKE_pbvh_bmesh_update_valence(ss->cd_sculpt_vert, vertex);
}
mval = mv->valence;
# ifdef NDEBUG
return mval;
# endif
}
#else
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BMVert *v = (BMVert *)vertex.i;
return BM_vert_edge_count(v);
}
#endif
MSculptVert *mv = ss->mdyntopo_verts + vertex.i;
MSculptVert *mv = SCULPT_vertex_get_sculptvert(ss, vertex);
if (mv->flag & SCULPTVERT_NEED_VALENCE) {
mv->flag &= ~SCULPTVERT_NEED_VALENCE;
int tot = 0;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
tot++;
}

View File

@ -178,7 +178,7 @@ struct _SculptNeighborRef {
SculptEdgeRef edge;
};
# define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 12
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 12
typedef struct SculptVertexNeighborIter {
/* Storage */
@ -209,47 +209,46 @@ void SCULPT_vertex_neighbors_get(const struct SculptSession *ss,
SculptVertexNeighborIter *iter);
/* Iterator over neighboring vertices. */
# define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
neighbor_iterator.i++) { \
neighbor_iterator.has_edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge.i != \
SCULPT_REF_NONE; \
neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i].vertex; \
neighbor_iterator.edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge; \
neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i];
#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
neighbor_iterator.i++) { \
neighbor_iterator.has_edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge.i != \
SCULPT_REF_NONE; \
neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i].vertex; \
neighbor_iterator.edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge; \
neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i];
/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
* first since they are nearest for floodfill. */
# define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
neighbor_iterator.i--) { \
neighbor_iterator.has_edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge.i != \
SCULPT_REF_NONE; \
neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i].vertex; \
neighbor_iterator.edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge; \
neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i]; \
neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
neighbor_iterator.size - \
neighbor_iterator.num_duplicates);
#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
neighbor_iterator.i--) { \
neighbor_iterator.has_edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge.i != \
SCULPT_REF_NONE; \
neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i].vertex; \
neighbor_iterator.edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge; \
neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i]; \
neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
neighbor_iterator.size - neighbor_iterator.num_duplicates);
# define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
} \
if (!neighbor_iterator.no_free && \
neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
MEM_freeN(neighbor_iterator.neighbors); \
MEM_freeN(neighbor_iterator.neighbor_indices); \
} \
((void)0)
#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
} \
if (!neighbor_iterator.no_free && \
neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
MEM_freeN(neighbor_iterator.neighbors); \
MEM_freeN(neighbor_iterator.neighbor_indices); \
} \
((void)0)
# define SCULPT_VERTEX_NEIGHBORS_ITER_FREE(neighbor_iterator) \
if (neighbor_iterator.neighbors && !neighbor_iterator.no_free && \
neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
MEM_freeN(neighbor_iterator.neighbors); \
MEM_freeN(neighbor_iterator.neighbor_indices); \
} \
((void)0)
#define SCULPT_VERTEX_NEIGHBORS_ITER_FREE(neighbor_iterator) \
if (neighbor_iterator.neighbors && !neighbor_iterator.no_free && \
neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
MEM_freeN(neighbor_iterator.neighbors); \
MEM_freeN(neighbor_iterator.neighbor_indices); \
} \
((void)0)
SculptVertRef SCULPT_active_vertex_get(SculptSession *ss);
const float *SCULPT_active_vertex_co_get(SculptSession *ss);
@ -265,7 +264,7 @@ struct MVert *SCULPT_mesh_deformed_mverts_get(SculptSession *ss);
/* Fake Neighbors */
# define FAKE_NEIGHBOR_NONE -1
#define FAKE_NEIGHBOR_NONE -1
void SCULPT_fake_neighbors_ensure(struct Sculpt *sd, Object *ob, const float max_dist);
void SCULPT_fake_neighbors_enable(Object *ob);
@ -298,28 +297,28 @@ float SCULPT_get_float_intern(const SculptSession *ss,
const char *idname,
const Sculpt *sd,
const Brush *br);
# define SCULPT_get_float(ss, idname, sd, br) \
SCULPT_get_float_intern(ss, BRUSH_BUILTIN_##idname, sd, br)
#define SCULPT_get_float(ss, idname, sd, br) \
SCULPT_get_float_intern(ss, BRUSH_BUILTIN_##idname, sd, br)
int SCULPT_get_int_intern(const SculptSession *ss,
const char *idname,
const Sculpt *sd,
const Brush *br);
# define SCULPT_get_int(ss, idname, sd, br) \
SCULPT_get_int_intern(ss, BRUSH_BUILTIN_##idname, sd, br)
# define SCULPT_get_bool(ss, idname, sd, br) SCULPT_get_int(ss, idname, sd, br)
#define SCULPT_get_int(ss, idname, sd, br) \
SCULPT_get_int_intern(ss, BRUSH_BUILTIN_##idname, sd, br)
#define SCULPT_get_bool(ss, idname, sd, br) SCULPT_get_int(ss, idname, sd, br)
int SCULPT_get_vector_intern(
const SculptSession *ss, const char *idname, float out[4], const Sculpt *sd, const Brush *br);
# define SCULPT_get_vector(ss, idname, out, sd, br) \
SCULPT_get_vector_intern(ss, BRUSH_BUILTIN_##idname, out, sd, br)
#define SCULPT_get_vector(ss, idname, out, sd, br) \
SCULPT_get_vector_intern(ss, BRUSH_BUILTIN_##idname, out, sd, br)
BrushChannel *SCULPT_get_final_channel_intern(const SculptSession *ss,
const char *idname,
const Sculpt *sd,
const Brush *br);
# define SCULPT_get_final_channel(ss, idname, sd, br) \
SCULPT_get_final_channel_intern(ss, BRUSH_BUILTIN_##idname, sd, br)
#define SCULPT_get_final_channel(ss, idname, sd, br) \
SCULPT_get_final_channel_intern(ss, BRUSH_BUILTIN_##idname, sd, br)
SculptCornerType SCULPT_vertex_is_corner(const SculptSession *ss,
const SculptVertRef index,
@ -1029,7 +1028,7 @@ typedef struct SculptUndoNode {
/* Factor of brush to have rake point following behind
* (could be configurable but this is reasonable default). */
# define SCULPT_RAKE_BRUSH_FACTOR 0.25f
#define SCULPT_RAKE_BRUSH_FACTOR 0.25f
struct SculptRakeData {
float follow_dist;
@ -1288,9 +1287,9 @@ bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
* For descriptions of these settings, check the operator properties.
*/
# define SCULPT_CLAY_STABILIZER_LEN 10
# define SCULPT_SPEED_MA_SIZE 4
# define GRAB_DELTA_MA_SIZE 3
#define SCULPT_CLAY_STABILIZER_LEN 10
#define SCULPT_SPEED_MA_SIZE 4
#define GRAB_DELTA_MA_SIZE 3
typedef struct AutomaskingSettings {
/* Flags from eAutomasking_flag. */
@ -1562,7 +1561,7 @@ typedef enum eSculptExpandRecursionType {
SCULPT_EXPAND_RECURSION_GEODESICS,
} eSculptExpandRecursionType;
# define EXPAND_SYMM_AREAS 8
#define EXPAND_SYMM_AREAS 8
typedef struct ExpandCache {
/* Target data elements that the expand operation will affect. */
@ -1987,14 +1986,14 @@ int SCULPT_dyntopo_get_templayer(SculptSession *ss, int type, const char *name);
void SCULPT_ensure_persistent_layers(SculptSession *ss, struct Object *ob);
# define SCULPT_LAYER_PERS_CO "Persistent Base Co"
# define SCULPT_LAYER_PERS_NO "Persistent Base No"
# define SCULPT_LAYER_PERS_DISP "Persistent Base Height"
# define SCULPT_LAYER_DISP "__temp_layer_disp"
# define SCULPT_LAYER_STROKE_ID "__temp_layer_strokeid"
#define SCULPT_LAYER_PERS_CO "Persistent Base Co"
#define SCULPT_LAYER_PERS_NO "Persistent Base No"
#define SCULPT_LAYER_PERS_DISP "Persistent Base Height"
#define SCULPT_LAYER_DISP "__temp_layer_disp"
#define SCULPT_LAYER_STROKE_ID "__temp_layer_strokeid"
// these tools don't support dynamic pbvh splitting during the stroke
# define DYNTOPO_HAS_DYNAMIC_SPLIT(tool) true
#define DYNTOPO_HAS_DYNAMIC_SPLIT(tool) true
/*get current symmetry pass index inclusive of both
mirror and radial symmetry*/
@ -2116,7 +2115,7 @@ void SCULPT_cotangents_begin(struct Object *ob, SculptSession *ss);
char SCULPT_mesh_fset_boundary_symmetry_get(struct Object *object);
// exponent to make boundary_smooth_factor more user-friendly
# define BOUNDARY_SMOOTH_EXP 2.0
#define BOUNDARY_SMOOTH_EXP 2.0
// edges
@ -2131,16 +2130,16 @@ SculptVertRef SCULPT_edge_other_vertex(const SculptSession *ss,
const SculptEdgeRef edge,
const SculptVertRef vertex);
# define SCULPT_REPLAY
# ifdef SCULPT_REPLAY
#define SCULPT_REPLAY
#ifdef SCULPT_REPLAY
struct SculptReplayLog;
struct SculptBrushSample;
# ifdef WIN32
# define REPLAY_EXPORT __declspec(dllexport)
# else
# define REPLAY_EXPORT
# endif
# ifdef WIN32
# define REPLAY_EXPORT __declspec(dllexport)
# else
# define REPLAY_EXPORT
# endif
void SCULPT_replay_log_free(struct SculptReplayLog *log);
struct SculptReplayLog *SCULPT_replay_log_create();
@ -2150,7 +2149,7 @@ char *SCULPT_replay_serialize();
void SCULPT_replay_log_append(struct Sculpt *sd, struct SculptSession *ss, struct Object *ob);
void SCULPT_replay_test(void);
# endif
#endif
struct BMesh *SCULPT_dyntopo_empty_bmesh();
@ -2158,15 +2157,15 @@ struct BMesh *SCULPT_dyntopo_empty_bmesh();
* 0.0f*/
void SCULPT_bound_smooth_ensure(SculptSession *ss, struct Object *ob);
# 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)
#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)
void SCULPT_undo_ensure_bmlog(struct Object *ob);
@ -2328,3 +2327,9 @@ typedef struct SculptFaceSetDrawData {
void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
const int n,
const struct TaskParallelTLS *__restrict tls);
void SCULPT_enhance_details_brush(struct Sculpt *sd,
struct Object *ob,
struct PBVHNode **nodes,
const int totnode,
int presteps);

View File

@ -424,7 +424,7 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SCULPT_temp_customlayer_ensure(
ss, ob, ATTR_DOMAIN_POINT, CD_PROP_COLOR, "_sculpt_smear_previous", &params);
SCULPT_temp_customlayer_ensure(
ss, ob, ATTR_DOMAIN_POINT, CD_PROP_INT32, "_paint_buffer_stroke_id", &params_id);
ss, ob, ATTR_DOMAIN_POINT, CD_PROP_INT32, SCULPT_LAYER_STROKE_ID, &params_id);
SCULPT_temp_customlayer_get(
ss, ob, ATTR_DOMAIN_POINT, CD_PROP_COLOR, "_sculpt_smear_previous", &buffer_scl, &params);
@ -432,7 +432,7 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
ob,
ATTR_DOMAIN_POINT,
CD_PROP_INT32,
"_paint_buffer_stroke_id",
SCULPT_LAYER_STROKE_ID,
&stroke_id_scl,
&params_id);

View File

@ -43,6 +43,7 @@
#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
@ -68,12 +69,7 @@
#include "atomic_ops.h"
#include "bmesh.h"
#ifdef PROXY_ADVANCED
/* clang-format off */
#include "BKE_DerivedMesh.h"
#include "../../blenkernel/intern/pbvh_intern.h"
/* clang-format on */
#endif
#include <math.h>
#include <stdlib.h>
@ -477,7 +473,7 @@ static void SCULPT_neighbor_coords_average_interior_boundary(SculptSession *ss,
totarea = totarea != 0.0f ? 1.0f / totarea : 0.0f;
float df = 0.25f / (float)val;
float df = 0.05f / (float)val;
for (int i = 0; i < val; i++) {
areas[i] = (areas[i] * totarea) + df;
@ -815,12 +811,11 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
/* normalize areas, then apply a 0.25/val floor */
float totarea = 0.0f;
for (int i = 0; i < val; i++) {
totarea += areas[i];
}
totarea = totarea != 0.0f ? 1.0f / totarea : 0.0f;
totarea = totarea > 0.0f ? 1.0f / totarea : 0.0f;
float df = 0.25f / (float)val;
@ -830,18 +825,26 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
}
float vel[3] = {0.0f, 0.0f, 0.0f};
int totvel = 0;
float totvel = 0.0f;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
MSculptVert *mv2 = SCULPT_vertex_get_sculptvert(ss, ni.vertex);
const float *co2;
float w;
if (weighted) {
w = areas[ni.i];
}
else {
w = 1.0f;
}
if (args->vel_scl) {
/* propagate velocities */
float *vel2 = SCULPT_temp_cdata_get(ni.vertex, args->vel_scl);
add_v3_v3(vel, vel2);
totvel++;
madd_v3_v3fl(vel, vel2, w);
totvel += w;
}
if (!do_origco || mv2->stroke_id != ss->stroke_id) {
@ -853,16 +856,9 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
neighbor_count++;
float tmp[3], w;
float tmp[3];
bool ok = false;
if (weighted) {
w = areas[ni.i];
}
else {
w = 1.0f;
}
/* use the new edge api if edges are available, if not estimate boundary
from verts
*/
@ -967,9 +963,9 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
madd_v3_v3fl(avg, tan, dot_v3v3(bound2, tan) * 0.75);
}
if (args->vel_scl && totvel > 1) {
if (args->vel_scl && totvel != 0.0f) {
float *final_vel = SCULPT_temp_cdata_get(vertex, args->vel_scl);
mul_v3_fl(vel, 1.0f / (float)totvel);
mul_v3_fl(vel, 1.0f / totvel);
interp_v3_v3v3(final_vel, final_vel, vel, args->vel_smooth_fac);
}
@ -1537,16 +1533,155 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
static void SCULPT_enhance_details_brush(Sculpt *sd,
Object *ob,
PBVHNode **nodes,
const int totnode)
static void do_enhance_details_brush_dir_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
SculptCustomLayer *strokeid_scl = data->scl2;
SculptCustomLayer *scl = data->scl;
const uint current_stroke_id = (uint)ss->stroke_id;
bool modified = false;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
uint *strokeid = SCULPT_temp_cdata_get(vd.vertex, strokeid_scl);
if ((*strokeid) >> 1UL != current_stroke_id) {
*strokeid = current_stroke_id << 1UL;
modified = true;
float avg[3];
float *dir = SCULPT_temp_cdata_get(vd.vertex, scl);
float no[3];
SCULPT_vertex_normal_get(ss, vd.vertex, no);
SCULPT_neighbor_coords_average(ss, avg, vd.vertex, 0.0f, false, data->use_area_cos);
sub_v3_v3v3(dir, avg, SCULPT_vertex_co_get(ss, vd.vertex));
/* get rid of tangential displacement */
float fac = dot_v3v3(dir, no);
copy_v3_v3(dir, no);
mul_v3_fl(dir, -fac);
}
}
BKE_pbvh_vertex_iter_end;
/* tell main thread we modified something */
if (modified) {
atomic_add_and_fetch_uint32((uint32_t *)(&data->cd_temp), 1UL);
}
}
/* Diffuses detail directions */
static void do_enhance_details_brush_dir2_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
// SculptCustomLayer *strokeid_scl = data->scl2;
SculptCustomLayer *scl = data->scl;
bool use_area_weights = data->use_area_cos;
// const uint current_stroke_id = (uint)ss->stroke_id;
int lastvalence = 8;
float *areas = MEM_malloc_arrayN(lastvalence, sizeof(float), __func__);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
int valence;
if (use_area_weights) {
valence = SCULPT_vertex_valence_get(ss, vd.vertex);
if (valence > lastvalence) {
areas = MEM_reallocN(areas, sizeof(float) * valence);
}
BKE_pbvh_get_vert_face_areas(ss->pbvh, vd.vertex, areas, valence);
}
// uint *strokeid = SCULPT_temp_cdata_get(vd.vertex, strokeid_scl);
/* this check here is overly restrictive,
we already get filtered by whether stage
1 did anything */
if (1) { //*strokeid == current_stroke_id << 1UL) {
// if (data->cd_temp2) {
//(*strokeid)++;
//}
float avg[3] = {0.0f, 0.0f, 0.0f};
float tot = 0.0f;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float *dir2 = SCULPT_temp_cdata_get(ni.vertex, scl);
float w = 1.0f;
if (use_area_weights) {
w = areas[ni.i];
}
madd_v3_v3fl(avg, dir2, w);
tot += w;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (tot == 0.0f) {
continue;
}
mul_v3_fl(avg, 1.0f / (float)tot);
float *dir = SCULPT_temp_cdata_get(vd.vertex, scl);
interp_v3_v3v3(dir, dir, avg, 0.5f); // valence == 1 ? 0.5f : 0.75f);
}
}
BKE_pbvh_vertex_iter_end;
MEM_freeN(areas);
}
void SCULPT_enhance_details_brush(
Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, int presteps)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
SculptCustomLayer strokeid_scl;
bool use_area_weights = (ss->cache->brush->flag2 & BRUSH_SMOOTH_USE_AREA_WEIGHT);
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
SCULPT_vertex_random_access_ensure(ss);
}
if (use_area_weights) {
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
BKE_pbvh_update_all_tri_areas(ss->pbvh);
@ -1563,7 +1698,6 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
}
}
SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_info_ensure(ob);
SculptCustomLayer scl;
@ -1572,12 +1706,18 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
SCULPT_temp_customlayer_ensure(
ss, ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, "__dyntopo_detail_dir", &params);
SCULPT_temp_customlayer_ensure(
ss, ob, ATTR_DOMAIN_POINT, CD_PROP_INT32, SCULPT_LAYER_STROKE_ID, &params);
SCULPT_temp_customlayer_get(
ss, ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, "__dyntopo_detail_dir", &scl, &params);
SCULPT_temp_customlayer_get(
ss, ob, ATTR_DOMAIN_POINT, CD_PROP_INT32, SCULPT_LAYER_STROKE_ID, &strokeid_scl, &params);
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
SCULPT_vertex_random_access_ensure(ss);
#if 0
const int totvert = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totvert; i++) {
@ -1594,146 +1734,88 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
/* get rid of tangential displacement */
float fac = dot_v3v3(dir, no);
copy_v3_v3(dir, no);
mul_v3_fl(dir, fac);
mul_v3_fl(dir, -fac);
}
int lastvalence = 5;
float *areas = MEM_malloc_arrayN(lastvalence, sizeof(float), __func__);
/* smooth offsets */
for (int i = 0; i < totvert; i++) {
float avg[3] = {0.0f, 0.0f, 0.0f};
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
float *dir = SCULPT_temp_cdata_get(vertex, &scl);
float tot = 0.0f;
float *areas = NULL;
int valence;
for (int step = 0; step < presteps; step++) {
for (int i = 0; i < totvert; i++) {
float avg[3] = {0.0f, 0.0f, 0.0f};
if (use_area_weights) {
valence = SCULPT_vertex_valence_get(ss, vertex);
if (valence > lastvalence) {
areas = MEM_reallocN(areas, sizeof(float) * valence);
}
areas = MEM_callocN(sizeof(float) * valence * 4, "sdaf");
// BLI_array_alloca(areas, valence * 4);
BKE_pbvh_get_vert_face_areas(ss->pbvh, vertex, areas, valence);
}
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
float *dir2 = SCULPT_temp_cdata_get(ni.vertex, &scl);
float w = 1.0f;
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
float *dir = SCULPT_temp_cdata_get(vertex, &scl);
float tot = 0.0f;
float *areas = NULL;
int valence;
if (use_area_weights) {
w = areas[ni.i];
valence = SCULPT_vertex_valence_get(ss, vertex);
if (valence > lastvalence) {
areas = MEM_reallocN(areas, sizeof(float) * valence);
}
areas = MEM_callocN(sizeof(float) * valence * 4, "sdaf");
// BLI_array_alloca(areas, valence * 4);
BKE_pbvh_get_vert_face_areas(ss->pbvh, vertex, areas, valence);
}
madd_v3_v3fl(avg, dir2, w);
tot += w;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
float *dir2 = SCULPT_temp_cdata_get(ni.vertex, &scl);
if (tot > 0.0f) {
mul_v3_fl(avg, 1.0f / tot);
interp_v3_v3v3(dir, dir, avg, 0.5f);
float w = 1.0f;
if (use_area_weights) {
w = areas[ni.i];
}
madd_v3_v3fl(avg, dir2, w);
tot += w;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (tot > 0.0f) {
mul_v3_fl(avg, 1.0f / tot);
interp_v3_v3v3(dir, dir, avg, 0.75f);
}
}
}
MEM_freeN(areas);
#endif
}
SculptThreadedTaskData data = {.sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .scl = &scl};
SculptThreadedTaskData data = {.sd = sd,
.ob = ob,
.brush = brush,
.use_area_cos = weighted,
.cd_temp = 0,
.cd_temp2 = 0,
.nodes = nodes,
.scl = &scl,
.scl2 = &strokeid_scl};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, do_enhance_details_brush_task_cb_ex, &settings);
}
#ifdef PROXY_ADVANCED
static void do_smooth_brush_task_cb_ex(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;
const bool smooth_mask = data->smooth_mask;
float bstrength = data->strength;
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);
PBVHNode **nodes = data->nodes;
ProxyVertArray *p = &nodes[n]->proxyverts;
for (int i = 0; i < p->size; i++) {
float co[3] = {0.0f, 0.0f, 0.0f};
int ni = 0;
# if 1
if (sculpt_brush_test_sq_fn(&test, p->co[i])) {
const float fade = bstrength * SCULPT_brush_strength_factor(
ss,
brush,
p->co[i],
sqrtf(test.dist),
p->no[i],
p->fno[i],
smooth_mask ? 0.0f : (p->mask ? p->mask[i] : 0.0f),
p->index[i],
thread_id);
# else
if (1) {
const float fade = 1.0;
# endif
while (ni < MAX_PROXY_NEIGHBORS && p->neighbors[i][ni].node >= 0) {
ProxyKey *key = p->neighbors[i] + ni;
PBVHNode *n2 = ss->pbvh->nodes + key->node;
// printf("%d %d %d %p\n", key->node, key->pindex, ss->pbvh->totnode, n2);
if (key->pindex < 0 || key->pindex >= n2->proxyverts.size) {
printf("corruption!\n");
fflush(stdout);
ni++;
continue;
}
if (n2->proxyverts.co) {
add_v3_v3(co, n2->proxyverts.co[key->pindex]);
ni++;
}
BLI_task_parallel_range(0, totnode, &data, do_enhance_details_brush_dir_task_cb_ex, &settings);
if (data.cd_temp) { /* did something change? if so run diffuse task*/
for (int i = 0; i < presteps; i++) {
if (i == presteps - 1) {
data.cd_temp2 = 1; // flag tasks to update to final stroke id
}
// printf("ni %d\n", ni);
if (ni > 2) {
mul_v3_fl(co, 1.0f / (float)ni);
}
else {
copy_v3_v3(co, p->co[i]);
}
// printf("%f %f %f ", co[0], co[1], co[2]);
interp_v3_v3v3(p->co[i], p->co[i], co, fade);
BLI_task_parallel_range(
0, totnode, &data, do_enhance_details_brush_dir2_task_cb_ex, &settings);
}
}
}
#else
BLI_task_parallel_range(0, totnode, &data, do_enhance_details_brush_task_cb_ex, &settings);
}
//# define SMOOTH_ITER_IN_THREADS
static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
@ -1782,7 +1864,7 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
SculptCustomLayer *bound_scl = data->scl2;
SculptCustomLayer *vel_scl = data->scl;
# ifdef SMOOTH_ITER_IN_THREADS
#ifdef SMOOTH_ITER_IN_THREADS
for (int iteration = 0; iteration < data->iterations; iteration++) {
if (!data->nodes[n]) {
break;
@ -1794,7 +1876,7 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
else {
bstrength = 1.0f;
}
# endif
#endif
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
@ -1823,7 +1905,7 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
CLAMP(*vd.mask, 0.0f, 1.0f);
}
else {
float avg[3], val[3];
float avg[3], off[3];
// if (SCULPT_vertex_is_corner(ss, vd.vertex, ctype) & ~SCULPT_CORNER_FACE_SET) {
// continue;
@ -1843,12 +1925,12 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
if (vel_scl) {
float *vel = SCULPT_temp_cdata_get(vd.vertex, vel_scl);
# if 0
#if 1
if (isnan(dot_v3v3(vel, vel)) || !isfinite(dot_v3v3(vel, vel))) {
printf("NaN!");
zero_v3(vel);
}
# endif
#endif
copy_v3_v3(startvel, vel);
}
@ -1869,27 +1951,31 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
.preserve_fset_boundaries = ss->cache->brush->flag2 &
BRUSH_SMOOTH_PRESERVE_FACE_SETS}));
sub_v3_v3v3(val, avg, co);
sub_v3_v3v3(off, avg, co);
/* Apply velocity smooth. The point of this is to
improve convergence for very high levels of smoothing*/
if (vel_scl) {
float *vel = SCULPT_temp_cdata_get(vd.vertex, vel_scl);
float blend_vel[3];
sub_v3_v3v3(blend_vel, vel, startvel);
float veltmp[3];
copy_v3_v3(veltmp, vel);
float oldval[3];
copy_v3_v3(oldval, val);
/* remove tangental component */
float fac = dot_v3v3(vel, startno);
mul_v3_v3fl(vel, startno, fac);
madd_v3_v3fl(val, vel, data->vel_smooth_fac);
/* note that "off" is interpreted here
as a force to update vel */
madd_v3_v3fl(vel, off, 0.2f);
mul_v3_fl(vel, 0.8f);
interp_v3_v3v3(vel, startvel, oldval, 0.9);
add_v3_v3(vel, blend_vel);
mul_v3_fl(vel, 0.9);
/* apply velocity */
add_v3_v3(off, veltmp);
}
madd_v3_v3v3fl(val, co, val, fade);
SCULPT_clip(sd, ss, co, val);
madd_v3_v3v3fl(off, co, off, fade);
SCULPT_clip(sd, ss, co, off);
if (step == 0) {
SCULPT_reproject_cdata(ss, vd.vertex, startco, startno);
@ -1913,11 +1999,10 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
// not modified? remove from future iterations
data->nodes[n] = NULL;
}
# ifdef SMOOTH_ITER_IN_THREADS
#ifdef SMOOTH_ITER_IN_THREADS
}
# endif
}
#endif
}
void SCULPT_bound_smooth_ensure(SculptSession *ss, Object *ob)
{
@ -1950,7 +2035,7 @@ void SCULPT_smooth(Sculpt *sd,
Brush *brush = ss->cache && ss->cache->brush ? ss->cache->brush : BKE_paint_brush(&sd->paint);
const float vel_smooth_cutoff = 0.5;
const bool do_vel_smooth = bstrength > vel_smooth_cutoff;
const bool do_vel_smooth = bstrength > vel_smooth_cutoff && G.debug_value != 895;
const int max_iterations = MAX2((int)(2.5f * ceilf(bstrength)), 1);
const float fract = 1.0f / max_iterations;
@ -2033,13 +2118,6 @@ void SCULPT_smooth(Sculpt *sd,
SCULPT_bound_smooth_ensure(ss, ob);
}
#ifdef PROXY_ADVANCED
int datamask = PV_CO | PV_NEIGHBORS | PV_NO | PV_INDEX | PV_MASK;
BKE_pbvh_ensure_proxyarrays(ss, ss->pbvh, nodes, totnode, datamask);
BKE_pbvh_load_proxyarrays(ss->pbvh, nodes, totnode, PV_CO | PV_NO | PV_MASK);
#endif
#ifndef SMOOTH_ITER_IN_THREADS
for (iteration = 0; iteration <= count; iteration++) {
const float strength = (iteration != count) ? 1.0f : last;
@ -2081,9 +2159,6 @@ void SCULPT_smooth(Sculpt *sd,
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
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);
#endif
#ifndef SMOOTH_ITER_IN_THREADS
}
#endif
@ -2106,7 +2181,14 @@ void SCULPT_do_smooth_brush(
* the middle of the stroke. */
if (ss->cache->bstrength < 0.0f) {
/* Invert mode, intensify details. */
SCULPT_enhance_details_brush(sd, ob, nodes, totnode);
ss->cache->bstrength = -ss->cache->bstrength;
SCULPT_enhance_details_brush(
sd,
ob,
nodes,
totnode,
SCULPT_get_int(ss, enhance_detail_presteps, sd, BKE_paint_brush(&sd->paint)));
ss->cache->bstrength = -ss->cache->bstrength;
}
else {
/* Regular mode, smooth. */
@ -2699,12 +2781,6 @@ void SCULPT_smooth_vcol_boundary(
SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_info_ensure(ob);
#ifdef PROXY_ADVANCED
int datamask = PV_CO | PV_NEIGHBORS | PV_NO | PV_INDEX | PV_MASK;
BKE_pbvh_ensure_proxyarrays(ss, ss->pbvh, nodes, totnode, datamask);
BKE_pbvh_load_proxyarrays(ss->pbvh, nodes, totnode, PV_CO | PV_NO | PV_MASK);
#endif
for (iteration = 0; iteration <= count; iteration++) {
const float strength = (iteration != count) ? 1.0f : last;
@ -2721,9 +2797,5 @@ void SCULPT_smooth_vcol_boundary(
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(
0, totnode, &data, do_smooth_vcol_boundary_brush_task_cb_ex, &settings);
#ifdef PROXY_ADVANCED
BKE_pbvh_gather_proxyarray(ss->pbvh, nodes, totnode);
#endif
}
}

View File

@ -509,7 +509,8 @@ typedef enum eBrushSculptTool {
SCULPT_TOOL_TOPOLOGY_RAKE = 40,
SCULPT_TOOL_DYNTOPO = 41,
SCULPT_TOOL_AUTO_FSET = 42,
SCULPT_TOOL_RELAX = 43
SCULPT_TOOL_RELAX = 43,
SCULPT_TOOL_ENHANCE_DETAILS = 44
} eBrushSculptTool;
/* Brush.uv_sculpt_tool */

View File

@ -114,6 +114,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_CREASE, "CREASE", ICON_BRUSH_CREASE, "Crease", ""},
{0, "", 0, NULL, NULL},
{SCULPT_TOOL_SMOOTH, "SMOOTH", ICON_BRUSH_SMOOTH, "Smooth", ""},
{SCULPT_TOOL_ENHANCE_DETAILS, "ENHANCE_DETAILS", ICON_BRUSH_ENHANCE_DETAILS, "Enhance Details", ""},
{SCULPT_TOOL_FLATTEN, "FLATTEN", ICON_BRUSH_FLATTEN, "Flatten", ""},
{SCULPT_TOOL_FILL, "FILL", ICON_BRUSH_FILL, "Fill", ""},
{SCULPT_TOOL_SCRAPE, "SCRAPE", ICON_BRUSH_SCRAPE, "Scrape", ""},
@ -146,7 +147,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_ARRAY, "ARRAY", ICON_BRUSH_SCULPT_DRAW, "Array", ""},
{SCULPT_TOOL_VCOL_BOUNDARY, "VCOL_BOUNDARY", ICON_BRUSH_VCOL_BOUNDARY, "Sharpen Color Boundary", ""},
{SCULPT_TOOL_UV_SMOOTH, "UV_SMOOTH", ICON_BRUSH_GRAB, "UV Smooth", ""},
{0, NULL, 0, NULL, NULL},
{0, NULL, 0, NULL, NULL},
};
/* clang-format on */
@ -724,7 +725,7 @@ static void rna_Brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
static void rna_Brush_dyntopo_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
//Brush *br = (Brush *)ptr->data;
// Brush *br = (Brush *)ptr->data;
}
static void rna_Brush_material_update(bContext *UNUSED(C), PointerRNA *UNUSED(ptr))