Sculpt: various bugfixes
* BMLog now saves face material indices * Fixed id corruption in join mesh edge case. * The mesh->bmesh conversion function now checks if IDs are corrupted in a bit smarter way: + Any id that's greater then 5 times the sum of total elements with ids is assumed to be corrupt. Avoids very large allocations for the fast element->id map, which is a simple lookup table. + Alternative is to automatically switch to the slower GHash id->element map. + Sculpt code would have to detect this case and regenerate IDs? * The slide relax brush is now internally split into two seperate commands. * Basic smoothing now uses fewer iterations, velocity smooth is used to speed up convergence.
This commit is contained in:
parent
6aa14c3433
commit
b701cd63ad
|
@ -1699,11 +1699,11 @@ void BKE_builtin_apply_hard_edge_mode(BrushChannelSet *chset, bool do_apply)
|
|||
}
|
||||
}
|
||||
|
||||
void BKE_builtin_commandlist_create(Brush *brush,
|
||||
BrushChannelSet *chset,
|
||||
BrushCommandList *cl,
|
||||
int tool,
|
||||
BrushMappingData *mapdata)
|
||||
ATTR_NO_OPT void BKE_builtin_commandlist_create(Brush *brush,
|
||||
BrushChannelSet *chset,
|
||||
BrushCommandList *cl,
|
||||
int tool,
|
||||
BrushMappingData *mapdata)
|
||||
{
|
||||
BrushCommand *cmd;
|
||||
BrushChannel *ch;
|
||||
|
@ -1736,7 +1736,7 @@ void BKE_builtin_commandlist_create(Brush *brush,
|
|||
float autosmooth_projection = BKE_brush_channelset_get_float(
|
||||
chset, "autosmooth_projection", NULL);
|
||||
|
||||
bool is_cloth = tool = SCULPT_TOOL_CLOTH;
|
||||
bool is_cloth = tool == SCULPT_TOOL_CLOTH;
|
||||
is_cloth = is_cloth ||
|
||||
(ELEM(tool, SCULPT_TOOL_BOUNDARY, SCULPT_TOOL_POSE) &&
|
||||
BRUSHSET_GET_INT(chset, deform_target, NULL) == BRUSH_DEFORM_TARGET_CLOTH_SIM);
|
||||
|
@ -1761,7 +1761,9 @@ void BKE_builtin_commandlist_create(Brush *brush,
|
|||
|
||||
float autosmooth = BKE_brush_channelset_get_float(chset, "autosmooth", NULL);
|
||||
if (!no_autosmooth && autosmooth > 0.0f) {
|
||||
cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl, chset, true), SCULPT_TOOL_SMOOTH);
|
||||
int smooth_tool = tool != SCULPT_TOOL_SLIDE_RELAX ? SCULPT_TOOL_SMOOTH : SCULPT_TOOL_RELAX;
|
||||
|
||||
cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl, chset, true), smooth_tool);
|
||||
BKE_builtin_apply_hard_edge_mode(cmd->params, hard_edge_mode);
|
||||
BKE_brush_commandset_inherit_all_mappings(cmd->params);
|
||||
|
||||
|
|
|
@ -464,7 +464,8 @@ typedef struct {
|
|||
void *customdata_f;
|
||||
char hflag;
|
||||
|
||||
size_t len;
|
||||
uint len;
|
||||
short mat_nr;
|
||||
|
||||
void *customdata_res[MAX_FACE_RESERVED];
|
||||
uint v_ids_res[MAX_FACE_RESERVED];
|
||||
|
@ -844,6 +845,7 @@ static BMLogFace *bm_log_face_alloc(BMLog *log, BMFace *f)
|
|||
|
||||
lf->len = (size_t)f->len;
|
||||
lf->id = (uint)BM_ELEM_GET_ID(log->bm, f);
|
||||
lf->mat_nr = f->mat_nr;
|
||||
|
||||
SET_TRACE(lf);
|
||||
|
||||
|
@ -1379,7 +1381,9 @@ static void bm_log_faces_restore(
|
|||
|
||||
BMFace *f = BM_face_create_verts(
|
||||
bm, vs_tmp, (int)BLI_array_len(vs_tmp), NULL, BM_CREATE_SKIP_ID, true);
|
||||
|
||||
f->head.hflag = lf->hflag;
|
||||
f->mat_nr = lf->mat_nr;
|
||||
|
||||
copy_v3_v3(f->no, lf->no);
|
||||
|
||||
|
@ -1515,6 +1519,7 @@ static void bm_log_face_values_swap(BMLog *log,
|
|||
|
||||
swap_v3_v3(f->no, lf->no);
|
||||
SWAP(char, f->head.hflag, lf->hflag);
|
||||
SWAP(short, f->mat_nr, lf->mat_nr);
|
||||
|
||||
void *old_cdata = NULL;
|
||||
|
||||
|
|
|
@ -280,9 +280,9 @@ void BM_enter_multires_space(Object *ob, BMesh *bm, int space)
|
|||
*/
|
||||
|
||||
void BM_mesh_bm_from_me(Object *ob,
|
||||
BMesh *bm,
|
||||
const Mesh *me,
|
||||
const struct BMeshFromMeshParams *params)
|
||||
BMesh *bm,
|
||||
const Mesh *me,
|
||||
const struct BMeshFromMeshParams *params)
|
||||
{
|
||||
const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
|
||||
bm->pdata.totlayer || bm->ldata.totlayer));
|
||||
|
@ -500,18 +500,30 @@ void BM_mesh_bm_from_me(Object *ob,
|
|||
BM_mesh_cd_flag_apply(bm, me->cd_flag);
|
||||
}
|
||||
|
||||
#define IS_GARBAGE_ID(id) ((id) < 0 || (id) > id_garbage_threshold)
|
||||
|
||||
int *existing_id_layers[4] = {NULL, NULL, NULL, NULL};
|
||||
|
||||
/* threshold to detect garbage IDs, number of elements with ids multiplied by 5 */
|
||||
int id_garbage_threshold = 0;
|
||||
|
||||
int use_exist_ids = 0;
|
||||
int has_ids = bm->idmap.flag & BM_HAS_IDS ?
|
||||
(bm->idmap.flag & (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)) :
|
||||
0;
|
||||
|
||||
if (bm->idmap.flag & BM_HAS_IDS) {
|
||||
int tots[4] = {me->totvert + bm->totvert,
|
||||
me->totedge + bm->totedge,
|
||||
me->totloop + bm->totloop,
|
||||
me->totpoly + bm->totface};
|
||||
|
||||
if (!params->ignore_id_layers) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
existing_id_layers[i] = (int *)CustomData_get_layer(cdatas[i], CD_MESH_ID);
|
||||
|
||||
if (existing_id_layers[i]) {
|
||||
id_garbage_threshold += tots[i];
|
||||
|
||||
use_exist_ids |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
@ -522,6 +534,8 @@ void BM_mesh_bm_from_me(Object *ob,
|
|||
bm_init_idmap_cdlayers(bm);
|
||||
}
|
||||
|
||||
id_garbage_threshold *= 5;
|
||||
|
||||
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
|
||||
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
|
||||
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
|
||||
|
@ -560,7 +574,7 @@ void BM_mesh_bm_from_me(Object *ob,
|
|||
bm_elem_check_toolflags(bm, (BMElem *)v);
|
||||
|
||||
if (has_ids & BM_VERT) {
|
||||
if (use_exist_ids & BM_VERT) {
|
||||
if ((use_exist_ids & BM_VERT) && !IS_GARBAGE_ID(existing_id_layers[0][i])) {
|
||||
bm_assign_id(bm, (BMElem *)v, existing_id_layers[0][i], false);
|
||||
}
|
||||
else {
|
||||
|
@ -611,7 +625,7 @@ void BM_mesh_bm_from_me(Object *ob,
|
|||
bm_elem_check_toolflags(bm, (BMElem *)e);
|
||||
|
||||
if (has_ids & BM_EDGE) {
|
||||
if (use_exist_ids & BM_EDGE) {
|
||||
if ((use_exist_ids & BM_EDGE) && !IS_GARBAGE_ID(existing_id_layers[1][i])) {
|
||||
bm_assign_id(bm, (BMElem *)e, existing_id_layers[1][i], false);
|
||||
}
|
||||
else {
|
||||
|
@ -682,7 +696,7 @@ void BM_mesh_bm_from_me(Object *ob,
|
|||
CustomData_to_bmesh_block(&me->ldata, &bm->ldata, j++, &l_iter->head.data, true);
|
||||
|
||||
if (has_ids & BM_LOOP) {
|
||||
if (use_exist_ids & BM_LOOP) {
|
||||
if ((use_exist_ids & BM_LOOP) && !IS_GARBAGE_ID(existing_id_layers[2][j - 1])) {
|
||||
bm_assign_id(bm, (BMElem *)l_iter, existing_id_layers[2][j - 1], false);
|
||||
}
|
||||
else {
|
||||
|
@ -697,7 +711,7 @@ void BM_mesh_bm_from_me(Object *ob,
|
|||
bm_elem_check_toolflags(bm, (BMElem *)f);
|
||||
|
||||
if (has_ids & BM_FACE) {
|
||||
if (use_exist_ids & BM_FACE) {
|
||||
if ((use_exist_ids & BM_FACE) && !IS_GARBAGE_ID(existing_id_layers[3][i])) {
|
||||
bm_assign_id(bm, (BMElem *)f, existing_id_layers[3][i], false);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -77,6 +77,134 @@
|
|||
/* join selected meshes into the active mesh, context sensitive
|
||||
* return 0 if no join is made (error) and 1 if the join is done */
|
||||
|
||||
static void get_id_range(Mesh *mesh,
|
||||
CustomData *vdata,
|
||||
CustomData *edata,
|
||||
CustomData *ldata,
|
||||
CustomData *pdata,
|
||||
int totvert,
|
||||
int totedge,
|
||||
int totloop,
|
||||
int totpoly,
|
||||
int *r_min,
|
||||
int *r_max)
|
||||
{
|
||||
const CustomData *datas[4] = {vdata, edata, ldata, pdata};
|
||||
int tots[4] = {totvert, totedge, totloop, totpoly};
|
||||
int min_id = 0, max_id = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int *ids = CustomData_get_layer(datas[i], CD_MESH_ID);
|
||||
if (!ids) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tots[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
min_id = max_id = *ids;
|
||||
}
|
||||
else {
|
||||
min_id = MIN2(min_id, *ids);
|
||||
max_id = MAX2(max_id, *ids);
|
||||
}
|
||||
|
||||
ids++;
|
||||
|
||||
for (int j = 1; j < tots[i]; j++, ids++) {
|
||||
min_id = MIN2(min_id, *ids);
|
||||
max_id = MAX2(max_id, *ids);
|
||||
}
|
||||
}
|
||||
|
||||
*r_min = min_id;
|
||||
*r_max = max_id;
|
||||
}
|
||||
|
||||
static void handle_missing_id_layers(Mesh *src,
|
||||
Mesh *dst,
|
||||
CustomData *vdata,
|
||||
CustomData *edata,
|
||||
CustomData *ldata,
|
||||
CustomData *pdata,
|
||||
int totvert,
|
||||
int totedge,
|
||||
int totloop,
|
||||
int totpoly)
|
||||
{
|
||||
const CustomData *src_datas[4] = {&src->vdata, &src->edata, &src->ldata, &src->pdata};
|
||||
const CustomData *dst_datas[4] = {vdata, edata, ldata, pdata};
|
||||
int srctots[4] = {src->totvert, src->totedge, src->totloop, src->totpoly};
|
||||
int dsttots[4] = {totvert, totedge, totloop, totpoly};
|
||||
|
||||
// find starting max id in dst
|
||||
int dst_range[2], src_range[2];
|
||||
|
||||
get_id_range(src,
|
||||
&src->vdata,
|
||||
&src->edata,
|
||||
&src->ldata,
|
||||
&src->pdata,
|
||||
src->totvert,
|
||||
src->totedge,
|
||||
src->totloop,
|
||||
src->totpoly,
|
||||
src_range,
|
||||
src_range + 1);
|
||||
|
||||
get_id_range(dst,
|
||||
vdata,
|
||||
edata,
|
||||
ldata,
|
||||
pdata,
|
||||
totvert,
|
||||
totedge,
|
||||
totloop,
|
||||
totpoly,
|
||||
dst_range,
|
||||
dst_range + 1);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
const CustomData *srcdata = src_datas[i];
|
||||
const CustomData *dstdata = dst_datas[i];
|
||||
|
||||
const bool haveid_src = CustomData_has_layer(srcdata, CD_MESH_ID);
|
||||
const bool haveid_dst = CustomData_has_layer(dstdata, CD_MESH_ID);
|
||||
|
||||
if (haveid_dst && haveid_src) {
|
||||
// assign ids
|
||||
int offset = dst_range[1] - src_range[0] + 1;
|
||||
|
||||
int *srcids = CustomData_get_layer(srcdata, CD_MESH_ID);
|
||||
int *dstids = CustomData_get_layer(dstdata, CD_MESH_ID);
|
||||
|
||||
int start = dsttots[i];
|
||||
int end = start + srctots[i];
|
||||
|
||||
// offset ids
|
||||
dstids += start;
|
||||
for (int i = start; i < end; i++, dstids++, srcids++) {
|
||||
*dstids = (*srcids) + offset;
|
||||
}
|
||||
}
|
||||
else if (haveid_dst) {
|
||||
int curid = dst_range[1] + 1;
|
||||
int *dstids = CustomData_get_layer(dstdata, CD_MESH_ID);
|
||||
|
||||
int start = dsttots[i];
|
||||
int end = start + srctots[i];
|
||||
dstids += start;
|
||||
|
||||
// assign new ids
|
||||
for (int i = start; i < end; i++, dstids++) {
|
||||
*dstids = curid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void join_mesh_single(Depsgraph *depsgraph,
|
||||
Main *bmain,
|
||||
Scene *scene,
|
||||
|
@ -286,6 +414,17 @@ static void join_mesh_single(Depsgraph *depsgraph,
|
|||
}
|
||||
}
|
||||
|
||||
handle_missing_id_layers(me,
|
||||
(Mesh *)ob_dst->data,
|
||||
vdata,
|
||||
edata,
|
||||
ldata,
|
||||
pdata,
|
||||
*vertofs,
|
||||
*edgeofs,
|
||||
*loopofs,
|
||||
*polyofs);
|
||||
|
||||
/* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
|
||||
*vertofs += me->totvert;
|
||||
*mvert_pp += me->totvert;
|
||||
|
|
|
@ -1045,6 +1045,10 @@ char SCULPT_mesh_symmetry_xyz_get(Object *object)
|
|||
|
||||
int SCULPT_active_face_set_get(SculptSession *ss)
|
||||
{
|
||||
if (ss->active_face_index.i == SCULPT_REF_NONE) {
|
||||
return SCULPT_FACE_SET_NONE;
|
||||
}
|
||||
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES:
|
||||
return ss->face_sets[ss->active_face_index.i];
|
||||
|
@ -4072,6 +4076,7 @@ static float brush_strength(const Sculpt *sd,
|
|||
}
|
||||
case SCULPT_TOOL_DRAW_FACE_SETS:
|
||||
return alpha * pressure * overlap * feather;
|
||||
case SCULPT_TOOL_RELAX:
|
||||
case SCULPT_TOOL_SLIDE_RELAX:
|
||||
return alpha * pressure * overlap * feather * 2.0f;
|
||||
case SCULPT_TOOL_PAINT:
|
||||
|
@ -5186,6 +5191,8 @@ bool brush_uses_commandlist(Brush *brush)
|
|||
case SCULPT_TOOL_PINCH:
|
||||
case SCULPT_TOOL_SIMPLIFY:
|
||||
case SCULPT_TOOL_SNAKE_HOOK:
|
||||
case SCULPT_TOOL_SLIDE_RELAX:
|
||||
case SCULPT_TOOL_RELAX:
|
||||
case SCULPT_TOOL_INFLATE:
|
||||
case SCULPT_TOOL_PAINT:
|
||||
case SCULPT_TOOL_SMEAR:
|
||||
|
@ -5485,7 +5492,10 @@ void do_brush_action(
|
|||
SCULPT_do_elastic_deform_brush(sd, ob, nodes, totnode);
|
||||
break;
|
||||
case SCULPT_TOOL_SLIDE_RELAX:
|
||||
SCULPT_do_slide_relax_brush(sd, ob, nodes, totnode);
|
||||
SCULPT_do_slide_brush(sd, ob, nodes, totnode);
|
||||
break;
|
||||
case SCULPT_TOOL_RELAX:
|
||||
SCULPT_do_relax_brush(sd, ob, nodes, totnode);
|
||||
break;
|
||||
case SCULPT_TOOL_BOUNDARY:
|
||||
SCULPT_do_boundary_brush(sd, ob, nodes, totnode);
|
||||
|
@ -5988,7 +5998,10 @@ static void SCULPT_run_command(
|
|||
SCULPT_do_elastic_deform_brush(sd, ob, nodes, totnode);
|
||||
break;
|
||||
case SCULPT_TOOL_SLIDE_RELAX:
|
||||
SCULPT_do_slide_relax_brush(sd, ob, nodes, totnode);
|
||||
SCULPT_do_slide_brush(sd, ob, nodes, totnode);
|
||||
break;
|
||||
case SCULPT_TOOL_RELAX:
|
||||
SCULPT_do_relax_brush(sd, ob, nodes, totnode);
|
||||
break;
|
||||
case SCULPT_TOOL_BOUNDARY:
|
||||
SCULPT_do_boundary_brush(sd, ob, nodes, totnode);
|
||||
|
@ -6834,6 +6847,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
|
|||
return "DynTopo";
|
||||
case SCULPT_TOOL_AUTO_FSET:
|
||||
return "Auto Face Set";
|
||||
case SCULPT_TOOL_RELAX:
|
||||
return "Relax";
|
||||
}
|
||||
|
||||
return "Sculpting";
|
||||
|
@ -7057,6 +7072,7 @@ static void sculpt_update_cache_invariants(
|
|||
}
|
||||
else if (ELEM(brush->sculpt_tool,
|
||||
SCULPT_TOOL_SLIDE_RELAX,
|
||||
SCULPT_TOOL_RELAX,
|
||||
SCULPT_TOOL_DRAW_FACE_SETS,
|
||||
SCULPT_TOOL_PAINT,
|
||||
SCULPT_TOOL_SMEAR)) {
|
||||
|
@ -8536,9 +8552,14 @@ void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerR
|
|||
}
|
||||
|
||||
BrushCommandList *list = ss->cache->commandlist = BKE_brush_commandlist_create();
|
||||
int tool = brush->sculpt_tool;
|
||||
|
||||
if (tool == SCULPT_TOOL_SLIDE_RELAX && ss->cache->alt_smooth) {
|
||||
tool = SCULPT_TOOL_RELAX;
|
||||
}
|
||||
|
||||
BKE_builtin_commandlist_create(
|
||||
brush, ss->cache->channels_final, list, brush->sculpt_tool, &ss->cache->input_mapping);
|
||||
brush, ss->cache->channels_final, list, tool, &ss->cache->input_mapping);
|
||||
}
|
||||
|
||||
SCULPT_run_commandlist(sd, ob, brush, ss->cache->commandlist, ups);
|
||||
|
@ -8657,6 +8678,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
|
|||
}
|
||||
else if (ELEM(brush->sculpt_tool,
|
||||
SCULPT_TOOL_SLIDE_RELAX,
|
||||
SCULPT_TOOL_RELAX,
|
||||
SCULPT_TOOL_DRAW_FACE_SETS,
|
||||
SCULPT_TOOL_PAINT,
|
||||
SCULPT_TOOL_SMEAR)) {
|
||||
|
|
|
@ -3218,6 +3218,8 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
|
|||
|
||||
const bool do_reproject = SCULPT_need_reproject;
|
||||
|
||||
const int boundflag = SCULPT_BOUNDARY_ALL;
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
|
||||
|
||||
|
@ -3239,7 +3241,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
|
|||
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);
|
||||
SCULPT_relax_vertex(ss, &vd, fade * bstrength, boundflag, vd.co);
|
||||
|
||||
if (do_reproject) {
|
||||
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
|
||||
|
@ -3252,7 +3254,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
|
|||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
void SCULPT_do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
|
||||
void SCULPT_do_slide_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
|
@ -3272,14 +3274,32 @@ void SCULPT_do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
|
|||
|
||||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
|
||||
if (ss->cache->alt_smooth) {
|
||||
SCULPT_boundary_info_ensure(ob);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
|
||||
}
|
||||
BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
|
||||
}
|
||||
|
||||
void SCULPT_do_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
|
||||
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
|
||||
|
||||
BKE_curvemapping_init(brush->curve);
|
||||
|
||||
SculptThreadedTaskData data = {
|
||||
.sd = sd,
|
||||
.ob = ob,
|
||||
.brush = brush,
|
||||
.nodes = nodes,
|
||||
};
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
|
||||
SCULPT_boundary_info_ensure(ob);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -422,6 +422,8 @@ typedef struct SculptSmoothArgs {
|
|||
bool do_weighted_smooth : 1;
|
||||
bool preserve_fset_boundaries : 1;
|
||||
float bound_smooth_radius; // if 0, ss->cache->radius will be used
|
||||
float vel_smooth_fac;
|
||||
SculptCustomLayer *vel_scl;
|
||||
} SculptSmoothArgs;
|
||||
|
||||
/* Utils. */
|
||||
|
@ -1095,6 +1097,7 @@ typedef struct SculptThreadedTaskData {
|
|||
float crease_pinch_factor;
|
||||
bool use_curvature;
|
||||
float vel_smooth_fac;
|
||||
int iterations;
|
||||
} SculptThreadedTaskData;
|
||||
|
||||
/*************** Brush testing declarations ****************/
|
||||
|
@ -2140,10 +2143,11 @@ void SCULPT_do_scene_project_brush(struct Sculpt *sd,
|
|||
struct Object *ob,
|
||||
struct PBVHNode **nodes,
|
||||
int totnode);
|
||||
void SCULPT_do_slide_relax_brush(struct Sculpt *sd,
|
||||
struct Object *ob,
|
||||
struct PBVHNode **nodes,
|
||||
int totnode);
|
||||
void SCULPT_do_slide_brush(struct Sculpt *sd,
|
||||
struct Object *ob,
|
||||
struct PBVHNode **nodes,
|
||||
int totnode);
|
||||
void SCULPT_do_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
|
||||
void SCULPT_do_fairing_brush(struct Sculpt *sd,
|
||||
struct Object *ob,
|
||||
struct PBVHNode **nodes,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -508,7 +508,8 @@ typedef enum eBrushSculptTool {
|
|||
|
||||
SCULPT_TOOL_TOPOLOGY_RAKE = 40,
|
||||
SCULPT_TOOL_DYNTOPO = 41,
|
||||
SCULPT_TOOL_AUTO_FSET = 42
|
||||
SCULPT_TOOL_AUTO_FSET = 42,
|
||||
SCULPT_TOOL_RELAX = 43
|
||||
} eBrushSculptTool;
|
||||
|
||||
/* Brush.uv_sculpt_tool */
|
||||
|
@ -547,7 +548,6 @@ typedef enum eBrushUVSculptTool {
|
|||
SCULPT_TOOL_CLOTH, \
|
||||
SCULPT_TOOL_DISPLACEMENT_ERASER, \
|
||||
SCULPT_TOOL_FAIRING, \
|
||||
SCULPT_TOOL_SLIDE_RELAX, \
|
||||
SCULPT_TOOL_ELASTIC_DEFORM, \
|
||||
SCULPT_TOOL_BOUNDARY, \
|
||||
SCULPT_TOOL_POSE, \
|
||||
|
|
Loading…
Reference in New Issue