Sculpt: New Layer Brush · 47f46637be
- ️blender
- ️Tue Apr 14 2020
@ -600,19 +600,10 @@ def brush_settings(layout, context, brush, popover=False):
|
||||
# use_persistent, set_persistent_base
|
||||
if capabilities.has_persistence:
|
||||
ob = context.sculpt_object
|
||||
do_persistent = True
|
||||
|
||||
# not supported yet for this case
|
||||
for md in ob.modifiers:
|
||||
if md.type == 'MULTIRES':
|
||||
do_persistent = False
|
||||
break
|
||||
|
||||
if do_persistent:
|
||||
layout.separator()
|
||||
layout.prop(brush, "use_persistent")
|
||||
layout.operator("sculpt.set_persistent_base")
|
||||
layout.separator()
|
||||
layout.separator()
|
||||
layout.prop(brush, "use_persistent")
|
||||
layout.operator("sculpt.set_persistent_base")
|
||||
layout.separator()
|
||||
|
||||
if brush.sculpt_tool == 'CLAY_STRIPS':
|
||||
row = layout.row()
|
||||
|
@ -279,6 +279,12 @@ typedef struct SculptClothSimulation {
|
||||
|
||||
} SculptClothSimulation;
|
||||
|
||||
typedef struct SculptLayerPersistentBase {
|
||||
float co[3];
|
||||
float no[3];
|
||||
float disp;
|
||||
} SculptLayerPersistentBase;
|
||||
|
||||
/* Session data (mode-specific) */
|
||||
|
||||
typedef struct SculptSession {
|
||||
@ -329,9 +335,6 @@ typedef struct SculptSession {
|
||||
unsigned int texcache_side, *texcache, texcache_actual;
|
||||
struct ImagePool *tex_pool;
|
||||
|
||||
/* Layer brush persistence between strokes */
|
||||
float (*layer_co)[3]; /* Copy of the mesh vertices' locations */
|
||||
|
||||
struct StrokeCache *cache;
|
||||
struct FilterCache *filter_cache;
|
||||
|
||||
@ -359,6 +362,10 @@ typedef struct SculptSession {
|
||||
float pose_origin[3];
|
||||
SculptPoseIKChain *pose_ik_chain_preview;
|
||||
|
||||
/* Layer brush persistence between strokes */
|
||||
/* This is freed with the PBVH, so it is always in sync with the mesh. */
|
||||
SculptLayerPersistentBase *layer_base;
|
||||
|
||||
/* Transform operator */
|
||||
float pivot_pos[3];
|
||||
float pivot_rot[4];
|
||||
|
@ -122,7 +122,6 @@ void BKE_pbvh_build_bmesh(PBVH *bvh,
|
||||
const int cd_vert_node_offset,
|
||||
const int cd_face_node_offset);
|
||||
void BKE_pbvh_free(PBVH *bvh);
|
||||
void BKE_pbvh_free_layer_disp(PBVH *bvh);
|
||||
|
||||
/* Hierarchical Search in the BVH, two methods:
|
||||
* - for each hit calling a callback
|
||||
@ -310,14 +309,6 @@ void BKE_pbvh_face_sets_set(PBVH *bvh, int *face_sets);
|
||||
|
||||
void BKE_pbvh_face_sets_color_set(PBVH *bvh, int seed, int color_default);
|
||||
|
||||
/* Layer displacement */
|
||||
|
||||
/* Get the node's displacement layer, creating it if necessary */
|
||||
float *BKE_pbvh_node_layer_disp_get(PBVH *pbvh, PBVHNode *node);
|
||||
|
||||
/* If the node has a displacement layer, free it and set to null */
|
||||
void BKE_pbvh_node_layer_disp_free(PBVHNode *node);
|
||||
|
||||
/* vertex deformer */
|
||||
float (*BKE_pbvh_vert_coords_alloc(struct PBVH *pbvh))[3];
|
||||
void BKE_pbvh_vert_coords_apply(struct PBVH *pbvh, const float (*vertCos)[3], const int totvert);
|
||||
|
@ -1422,6 +1422,12 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
br->cloth_deform_type = BRUSH_CLOTH_DEFORM_DRAG;
|
||||
br->flag &= ~(BRUSH_ALPHA_PRESSURE | BRUSH_SIZE_PRESSURE);
|
||||
break;
|
||||
case SCULPT_TOOL_LAYER:
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
br->hardness = 0.35f;
|
||||
br->alpha = 1.0f;
|
||||
br->height = 0.05f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1306,9 +1306,10 @@ static void sculptsession_free_pbvh(Object *object)
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(ss->pmap);
|
||||
|
||||
MEM_SAFE_FREE(ss->pmap_mem);
|
||||
|
||||
MEM_SAFE_FREE(ss->layer_base);
|
||||
|
||||
MEM_SAFE_FREE(ss->preview_vert_index_list);
|
||||
ss->preview_vert_index_count = 0;
|
||||
}
|
||||
@ -1353,31 +1354,17 @@ void BKE_sculptsession_free(Object *ob)
|
||||
BM_log_free(ss->bm_log);
|
||||
}
|
||||
|
||||
if (ss->texcache) {
|
||||
MEM_freeN(ss->texcache);
|
||||
}
|
||||
MEM_SAFE_FREE(ss->texcache);
|
||||
|
||||
if (ss->tex_pool) {
|
||||
BKE_image_pool_free(ss->tex_pool);
|
||||
}
|
||||
|
||||
if (ss->layer_co) {
|
||||
MEM_freeN(ss->layer_co);
|
||||
}
|
||||
MEM_SAFE_FREE(ss->orig_cos);
|
||||
MEM_SAFE_FREE(ss->deform_cos);
|
||||
MEM_SAFE_FREE(ss->deform_imats);
|
||||
|
||||
if (ss->orig_cos) {
|
||||
MEM_freeN(ss->orig_cos);
|
||||
}
|
||||
if (ss->deform_cos) {
|
||||
MEM_freeN(ss->deform_cos);
|
||||
}
|
||||
if (ss->deform_imats) {
|
||||
MEM_freeN(ss->deform_imats);
|
||||
}
|
||||
|
||||
if (ss->preview_vert_index_list) {
|
||||
MEM_freeN(ss->preview_vert_index_list);
|
||||
}
|
||||
MEM_SAFE_FREE(ss->preview_vert_index_list);
|
||||
|
||||
if (ss->pose_ik_chain_preview) {
|
||||
for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
|
||||
|
@ -685,8 +685,6 @@ void BKE_pbvh_free(PBVH *bvh)
|
||||
if (node->face_vert_indices) {
|
||||
MEM_freeN((void *)node->face_vert_indices);
|
||||
}
|
||||
BKE_pbvh_node_layer_disp_free(node);
|
||||
|
||||
if (node->bm_faces) {
|
||||
BLI_gset_free(node->bm_faces, NULL);
|
||||
}
|
||||
@ -722,13 +720,6 @@ void BKE_pbvh_free(PBVH *bvh)
|
||||
MEM_freeN(bvh);
|
||||
}
|
||||
|
||||
void BKE_pbvh_free_layer_disp(PBVH *bvh)
|
||||
{
|
||||
for (int i = 0; i < bvh->totnode; i++) {
|
||||
BKE_pbvh_node_layer_disp_free(&bvh->nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void pbvh_iter_begin(PBVHIter *iter,
|
||||
PBVH *bvh,
|
||||
BKE_pbvh_SearchCallback scb,
|
||||
@ -2768,26 +2759,6 @@ void BKE_pbvh_grids_update(
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the node's displacement layer, creating it if necessary */
|
||||
float *BKE_pbvh_node_layer_disp_get(PBVH *bvh, PBVHNode *node)
|
||||
{
|
||||
if (!node->layer_disp) {
|
||||
int totvert = 0;
|
||||
BKE_pbvh_node_num_verts(bvh, node, &totvert, NULL);
|
||||
node->layer_disp = MEM_callocN(sizeof(float) * totvert, "layer disp");
|
||||
}
|
||||
return node->layer_disp;
|
||||
}
|
||||
|
||||
/* If the node has a displacement layer, free it and set to null */
|
||||
void BKE_pbvh_node_layer_disp_free(PBVHNode *node)
|
||||
{
|
||||
if (node->layer_disp) {
|
||||
MEM_freeN(node->layer_disp);
|
||||
node->layer_disp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
float (*BKE_pbvh_vert_coords_alloc(PBVH *pbvh))[3]
|
||||
{
|
||||
float(*vertCos)[3] = NULL;
|
||||
|
@ -1216,6 +1216,34 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession
|
||||
}
|
||||
}
|
||||
|
||||
void SCULPT_layer_brush_height_preview_draw(const uint gpuattr,
|
||||
const Brush *brush,
|
||||
const float obmat[4][4],
|
||||
const float location[3],
|
||||
const float normal[3],
|
||||
const float rds,
|
||||
const float line_width,
|
||||
const float outline_col[3],
|
||||
const float alpha)
|
||||
{
|
||||
float cursor_trans[4][4], cursor_rot[4][4];
|
||||
float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
|
||||
float quat[4];
|
||||
float height_preview_trans[3];
|
||||
copy_m4_m4(cursor_trans, obmat);
|
||||
madd_v3_v3v3fl(height_preview_trans, location, normal, brush->height);
|
||||
translate_m4(
|
||||
cursor_trans, height_preview_trans[0], height_preview_trans[1], height_preview_trans[2]);
|
||||
rotation_between_vecs_to_quat(quat, z_axis, normal);
|
||||
quat_to_mat4(cursor_rot, quat);
|
||||
GPU_matrix_mul(cursor_trans);
|
||||
GPU_matrix_mul(cursor_rot);
|
||||
|
||||
GPU_line_width(line_width);
|
||||
immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
|
||||
imm_draw_circle_wire_3d(gpuattr, 0, 0, rds, 80);
|
||||
}
|
||||
|
||||
static bool paint_use_2d_cursor(ePaintMode mode)
|
||||
{
|
||||
if (mode >= PAINT_MODE_TEXTURE_3D) {
|
||||
@ -1476,6 +1504,21 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
|
||||
GPU_matrix_pop();
|
||||
}
|
||||
|
||||
/* Layer brush height. */
|
||||
if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
|
||||
GPU_matrix_push();
|
||||
SCULPT_layer_brush_height_preview_draw(pos,
|
||||
brush,
|
||||
vc.obact->obmat,
|
||||
gi.location,
|
||||
gi.normal,
|
||||
rds,
|
||||
1.0f,
|
||||
outline_col,
|
||||
outline_alpha);
|
||||
GPU_matrix_pop();
|
||||
}
|
||||
|
||||
/* Update and draw dynamic mesh preview lines. */
|
||||
GPU_matrix_push();
|
||||
GPU_matrix_mul(vc.obact->obmat);
|
||||
|
@ -1709,10 +1709,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
|
||||
/* Update the test radius to sample the normal using the normal radius of the brush. */
|
||||
if (data->brush->ob_mode == OB_MODE_SCULPT) {
|
||||
float test_radius = sqrtf(normal_test.radius_squared);
|
||||
/* Layer brush produces artifacts with normal and area radius. */
|
||||
if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) {
|
||||
test_radius *= data->brush->normal_radius_factor;
|
||||
}
|
||||
test_radius *= data->brush->normal_radius_factor;
|
||||
normal_test.radius = test_radius;
|
||||
normal_test.radius_squared = test_radius * test_radius;
|
||||
}
|
||||
@ -1724,15 +1721,13 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
|
||||
if (data->brush->ob_mode == OB_MODE_SCULPT) {
|
||||
float test_radius = sqrtf(area_test.radius_squared);
|
||||
/* Layer brush produces artifacts with normal and area radius */
|
||||
if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) {
|
||||
/* Enable area radius control only on Scrape for now */
|
||||
if (ELEM(data->brush->sculpt_tool, SCULPT_TOOL_SCRAPE, SCULPT_TOOL_FILL) &&
|
||||
data->brush->area_radius_factor > 0.0f) {
|
||||
test_radius *= data->brush->area_radius_factor;
|
||||
}
|
||||
else {
|
||||
test_radius *= data->brush->normal_radius_factor;
|
||||
}
|
||||
/* Enable area radius control only on Scrape for now */
|
||||
if (ELEM(data->brush->sculpt_tool, SCULPT_TOOL_SCRAPE, SCULPT_TOOL_FILL) &&
|
||||
data->brush->area_radius_factor > 0.0f) {
|
||||
test_radius *= data->brush->area_radius_factor;
|
||||
}
|
||||
else {
|
||||
test_radius *= data->brush->normal_radius_factor;
|
||||
}
|
||||
area_test.radius = test_radius;
|
||||
area_test.radius_squared = test_radius * test_radius;
|
||||
@ -4072,23 +4067,14 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
|
||||
SculptSession *ss = data->ob->sculpt;
|
||||
Sculpt *sd = data->sd;
|
||||
const Brush *brush = data->brush;
|
||||
const float *offset = data->offset;
|
||||
|
||||
const bool use_persistent_base = ss->layer_base && brush->flag & BRUSH_PERSISTENT;
|
||||
|
||||
PBVHVertexIter vd;
|
||||
SculptOrigVertData orig_data;
|
||||
float *layer_disp;
|
||||
const float bstrength = ss->cache->bstrength;
|
||||
const float lim = (bstrength < 0.0f) ? -data->brush->height : data->brush->height;
|
||||
/* XXX: layer brush needs conversion to proxy but its more complicated */
|
||||
/* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
|
||||
|
||||
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
|
||||
|
||||
/* Why does this have to be thread-protected? */
|
||||
BLI_mutex_lock(&data->mutex);
|
||||
layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, data->nodes[n]);
|
||||
BLI_mutex_unlock(&data->mutex);
|
||||
|
||||
SculptBrushTest test;
|
||||
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
|
||||
ss, &test, data->brush->falloff_shape);
|
||||
@ -4098,38 +4084,65 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
|
||||
SCULPT_orig_vert_data_update(&orig_data, &vd);
|
||||
|
||||
if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
|
||||
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
|
||||
brush,
|
||||
vd.co,
|
||||
sqrtf(test.dist),
|
||||
vd.no,
|
||||
vd.fno,
|
||||
vd.mask ? *vd.mask : 0.0f,
|
||||
vd.index,
|
||||
tls->thread_id);
|
||||
float *disp = &layer_disp[vd.i];
|
||||
float val[3];
|
||||
const float fade = SCULPT_brush_strength_factor(ss,
|
||||
brush,
|
||||
vd.co,
|
||||
sqrtf(test.dist),
|
||||
vd.no,
|
||||
vd.fno,
|
||||
vd.mask ? *vd.mask : 0.0f,
|
||||
vd.index,
|
||||
tls->thread_id);
|
||||
|
||||
*disp += fade;
|
||||
|
||||
/* Don't let the displacement go past the limit. */
|
||||
if ((lim < 0.0f && *disp < lim) || (lim >= 0.0f && *disp > lim)) {
|
||||
*disp = lim;
|
||||
}
|
||||
|
||||
mul_v3_v3fl(val, offset, *disp);
|
||||
|
||||
if (!ss->multires.active && !ss->bm && ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
|
||||
int index = vd.vert_indices[vd.i];
|
||||
|
||||
/* Persistent base. */
|
||||
add_v3_v3(val, ss->layer_co[index]);
|
||||
const int vi = vd.index;
|
||||
float *disp_factor;
|
||||
if (use_persistent_base) {
|
||||
disp_factor = &ss->layer_base[vi].disp;
|
||||
}
|
||||
else {
|
||||
add_v3_v3(val, orig_data.co);
|
||||
disp_factor = &ss->cache->layer_displacement_factor[vi];
|
||||
}
|
||||
|
||||
SCULPT_clip(sd, ss, vd.co, val);
|
||||
/* When using persistent base, the layer brush Ctrl invert mode resets the height of the
|
||||
* layer to 0. This makes possible to clean edges of previously added layers on top of the
|
||||
* base. */
|
||||
/* The main direction of the layers is inverted using the regular brush strength with the
|
||||
* brush direction property. */
|
||||
if (use_persistent_base && ss->cache->invert) {
|
||||
(*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
|
||||
((*disp_factor) > 0.0f ? -1.0f : 1.0f);
|
||||
}
|
||||
else {
|
||||
(*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
|
||||
}
|
||||
if (vd.mask) {
|
||||
const float clamp_mask = 1.0f - *vd.mask;
|
||||
CLAMP(*disp_factor, -clamp_mask, clamp_mask);
|
||||
}
|
||||
else {
|
||||
CLAMP(*disp_factor, -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
float final_co[3];
|
||||
float normal[3];
|
||||
|
||||
if (use_persistent_base) {
|
||||
copy_v3_v3(normal, ss->layer_base[vi].no);
|
||||
mul_v3_fl(normal, brush->height);
|
||||
madd_v3_v3v3fl(final_co, ss->layer_base[vi].co, normal, *disp_factor);
|
||||
}
|
||||
else {
|
||||
normal_short_to_float_v3(normal, orig_data.no);
|
||||
mul_v3_fl(normal, brush->height);
|
||||
madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
|
||||
}
|
||||
|
||||
float vdisp[3];
|
||||
sub_v3_v3v3(vdisp, final_co, vd.co);
|
||||
mul_v3_fl(vdisp, fabsf(fade));
|
||||
add_v3_v3v3(final_co, vd.co, vdisp);
|
||||
|
||||
SCULPT_clip(sd, ss, vd.co, final_co);
|
||||
|
||||
if (vd.mvert) {
|
||||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
@ -4143,24 +4156,23 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
float offset[3];
|
||||
|
||||
mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm);
|
||||
if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0 &&
|
||||
ss->cache->first_time) {
|
||||
ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
|
||||
"layer displacement factor");
|
||||
}
|
||||
|
||||
SculptThreadedTaskData data = {
|
||||
.sd = sd,
|
||||
.ob = ob,
|
||||
.brush = brush,
|
||||
.nodes = nodes,
|
||||
.offset = offset,
|
||||
};
|
||||
BLI_mutex_init(&data.mutex);
|
||||
|
||||
PBVHParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
|
||||
BKE_pbvh_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
|
||||
|
||||
BLI_mutex_end(&data.mutex);
|
||||
}
|
||||
|
||||
static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
|
||||
@ -5948,6 +5960,7 @@ void SCULPT_cache_free(StrokeCache *cache)
|
||||
{
|
||||
MEM_SAFE_FREE(cache->dial);
|
||||
MEM_SAFE_FREE(cache->surface_smooth_laplacian_disp);
|
||||
MEM_SAFE_FREE(cache->layer_displacement_factor);
|
||||
|
||||
if (cache->pose_ik_chain) {
|
||||
SCULPT_pose_ik_chain_free(cache->pose_ik_chain);
|
||||
@ -6006,14 +6019,9 @@ static void sculpt_update_cache_invariants(
|
||||
ss->cache = cache;
|
||||
|
||||
/* Set scaling adjustment. */
|
||||
if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
|
||||
max_scale = 1.0f;
|
||||
}
|
||||
else {
|
||||
max_scale = 0.0f;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
max_scale = max_ff(max_scale, fabsf(ob->scale[i]));
|
||||
}
|
||||
max_scale = 0.0f;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
max_scale = max_ff(max_scale, fabsf(ob->scale[i]));
|
||||
}
|
||||
cache->scale[0] = max_scale / ob->scale[0];
|
||||
cache->scale[1] = max_scale / ob->scale[1];
|
||||
@ -6129,32 +6137,6 @@ static void sculpt_update_cache_invariants(
|
||||
normalize_v3(cache->true_gravity_direction);
|
||||
}
|
||||
|
||||
/* Initialize layer brush displacements and persistent coords. */
|
||||
if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
|
||||
/* Not supported yet for multires or dynamic topology. */
|
||||
if (!ss->multires.active && !ss->bm && !ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
|
||||
if (!ss->layer_co) {
|
||||
ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert, "sculpt mesh vertices copy");
|
||||
}
|
||||
|
||||
if (ss->deform_cos) {
|
||||
memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < ss->totvert; i++) {
|
||||
copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ss->bm) {
|
||||
/* Free any remaining layer displacements from nodes. If not and topology changes
|
||||
* from using another tool, then next layer toolstroke
|
||||
* can access past disp array bounds. */
|
||||
BKE_pbvh_free_layer_disp(ss->pbvh);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make copies of the mesh vertex locations and normals for some tools. */
|
||||
if (brush->flag & BRUSH_ANCHORED) {
|
||||
cache->original = true;
|
||||
@ -7290,13 +7272,25 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
|
||||
|
||||
static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
SculptSession *ss = CTX_data_active_object(C)->sculpt;
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
if (ss) {
|
||||
if (ss->layer_co) {
|
||||
MEM_freeN(ss->layer_co);
|
||||
SCULPT_vertex_random_access_init(ss);
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
|
||||
|
||||
MEM_SAFE_FREE(ss->layer_base);
|
||||
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
ss->layer_base = MEM_mallocN(sizeof(SculptLayerPersistentBase) * totvert,
|
||||
"layer persistent base");
|
||||
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
copy_v3_v3(ss->layer_base[i].co, SCULPT_vertex_co_get(ss, i));
|
||||
SCULPT_vertex_normal_get(ss, i, ss->layer_base[i].no);
|
||||
ss->layer_base[i].disp = 0.0f;
|
||||
}
|
||||
ss->layer_co = NULL;
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
|
@ -781,6 +781,9 @@ typedef struct StrokeCache {
|
||||
/* Stores the displacement produced by the laplacian step of HC smooth. */
|
||||
float (*surface_smooth_laplacian_disp)[3];
|
||||
|
||||
/* Layer brush */
|
||||
float *layer_displacement_factor;
|
||||
|
||||
float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
|
||||
struct Dial *dial;
|
||||
|
||||
|
@ -1314,10 +1314,6 @@ void SCULPT_undo_push_end_ex(const bool use_nested_undo)
|
||||
MEM_freeN(unode->no);
|
||||
unode->no = NULL;
|
||||
}
|
||||
|
||||
if (unode->node) {
|
||||
BKE_pbvh_node_layer_disp_free(unode->node);
|
||||
}
|
||||
}
|
||||
|
||||
/* We could remove this and enforce all callers run in an operator using 'OPTYPE_UNDO'. */
|
||||
|
@ -689,7 +689,6 @@ typedef enum eBrushUVSculptTool {
|
||||
SCULPT_TOOL_SLIDE_RELAX, \
|
||||
SCULPT_TOOL_CREASE, \
|
||||
SCULPT_TOOL_BLOB, \
|
||||
SCULPT_TOOL_LAYER, \
|
||||
SCULPT_TOOL_INFLATE, \
|
||||
SCULPT_TOOL_CLAY, \
|
||||
SCULPT_TOOL_CLAY_STRIPS, \
|
||||
|
@ -2094,6 +2094,7 @@ static void rna_def_brush(BlenderRNA *brna)
|
||||
RNA_def_property_float_sdna(prop, NULL, "height");
|
||||
RNA_def_property_float_default(prop, 0.5f);
|
||||
RNA_def_property_range(prop, 0, 1.0f);
|
||||
RNA_def_property_ui_range(prop, 0, 0.2f, 1, 3);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Brush Height", "Affectable height of brush (layer height for layer tool, i.e.)");
|
||||
RNA_def_property_update(prop, 0, "rna_Brush_update");
|
||||
|