Sculpt: New Clay Brush

The previous Clay brush was similar to flatten. Now it has a different plane calculation and falloff, based on the position of the vertices before deforming them, so it feels more like adding clay to the model.

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D6228
This commit is contained in:
Pablo Dobarro 2019-11-18 22:40:46 +01:00
parent c7ade50dee
commit 316107d4cd
2 changed files with 128 additions and 30 deletions

View File

@ -927,7 +927,8 @@ void BKE_brush_sculpt_reset(Brush *br)
br->spacing = 5;
break;
case SCULPT_TOOL_CLAY:
br->flag |= BRUSH_FRONTFACE;
br->spacing = 6;
br->normal_radius_factor = 0.75f;
break;
case SCULPT_TOOL_CLAY_STRIPS:
br->flag |= BRUSH_ACCUMULATE | BRUSH_SIZE_PRESSURE;

View File

@ -1736,6 +1736,8 @@ static float brush_strength(const Sculpt *sd,
switch (brush->sculpt_tool) {
case SCULPT_TOOL_CLAY:
overlap = (1.0f + overlap) / 2.0f;
return 0.25f * alpha * flip * pressure * overlap * feather;
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_DRAW_SHARP:
case SCULPT_TOOL_LAYER:
@ -4649,6 +4651,66 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
BKE_pbvh_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
}
/* -------------------------------------------------------------------- */
/** \name Sculpt Clay Brush
* \{ */
typedef struct ClaySampleData {
float plane_dist[2];
} ClaySampleData;
static void calc_clay_surface_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
const Brush *brush = data->brush;
ClaySampleData *csd = tls->userdata_chunk;
const float *area_no = data->area_no;
const float *area_co = data->area_co;
float plane[4];
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
ss, &test, brush->falloff_shape);
/* Apply the brush normal radius to the test before sampling */
float test_radius = sqrtf(test.radius_squared);
test_radius *= brush->normal_radius_factor;
test.radius_squared = test_radius * test_radius;
plane_from_point_normal_v3(plane, area_co, area_no);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
float plane_dist = dist_signed_to_plane_v3(vd.co, plane);
float plane_dist_abs = fabsf(plane_dist);
if (plane_dist > 0.0f) {
csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs);
}
else {
csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs);
}
}
BKE_pbvh_vertex_iter_end;
}
}
static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata),
void *__restrict chunk_join,
void *__restrict chunk)
{
ClaySampleData *join = chunk_join;
ClaySampleData *csd = chunk;
join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]);
join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]);
}
static void do_clay_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@ -4658,11 +4720,11 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
const Brush *brush = data->brush;
const float *area_no = data->area_no;
const float *area_co = data->area_co;
const float hardness = 0.65f;
PBVHVertexIter vd;
float(*proxy)[3];
const bool flip = (ss->cache->bstrength < 0);
const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
const float bstrength = fabsf(ss->cache->bstrength);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@ -4675,33 +4737,32 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
if (plane_point_side_flip(vd.co, test.plane_tool, flip)) {
float intr[3];
float val[3];
float intr[3];
float val[3];
closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
sub_v3_v3v3(val, intr, vd.co);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
/* note, the normal from the vertices is ignored,
* causes glitch with planes, see: T44390 */
const float fade = bstrength * tex_strength(ss,
brush,
vd.co,
sqrtf(test.dist),
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
tls->thread_id);
float dist = sqrtf(test.dist);
float p = dist / ss->cache->radius;
p = (p - hardness) / (1.0f - hardness);
CLAMP(p, 0.0f, 1.0f);
dist *= p;
const float fade = bstrength * tex_strength(ss,
brush,
vd.co,
dist,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
@ -4713,8 +4774,8 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
const bool flip = (ss->cache->bstrength < 0);
const float radius = flip ? -ss->cache->radius : ss->cache->radius;
const float radius = fabsf(ss->cache->radius);
bool flip = ss->cache->bstrength < 0.0f;
float offset = get_offset(sd, ss);
float displace;
@ -4725,14 +4786,48 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = radius * (0.25f + offset);
SculptThreadedTaskData sample_data = {
.sd = NULL,
.ob = ob,
.brush = brush,
.nodes = nodes,
.totnode = totnode,
.area_no = area_no,
.area_co = ss->cache->location,
};
ClaySampleData csd = {{{0}}};
PBVHParallelSettings sample_settings;
BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
sample_settings.func_reduce = calc_clay_surface_reduce;
sample_settings.userdata_chunk = &csd;
sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
BKE_pbvh_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
float d_bstrength;
if (flip) {
d_bstrength = -csd.plane_dist[1];
}
else {
d_bstrength = csd.plane_dist[0];
}
float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
d_offset = min_ff(radius, d_offset);
d_offset = d_offset / radius;
d_offset = 1.0f - d_offset;
displace = fabsf(radius * (0.25f + offset + (d_offset * 0.15f)));
if (flip) {
displace = -displace;
}
mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
copy_v3_v3(area_co, ss->cache->location);
add_v3_v3(area_co, temp);
/* add_v3_v3v3(p, ss->cache->location, area_no); */
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
@ -4747,6 +4842,8 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BKE_pbvh_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
}
/** \} */
static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)