Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPablo Dobarro <pablodp606@gmail.com>2020-01-22 04:23:51 +0300
committerPablo Dobarro <pablodp606@gmail.com>2020-02-11 20:57:07 +0300
commit015d5eda884dfb10f8982f9b0f8d69c9ea540349 (patch)
treed48f2ef3aea20b1ff69e54b7990f32b22104791e /source/blender/editors/sculpt_paint
parentf1f2d9fe745e37d7e7c286002ec3fa6243b499e3 (diff)
Sculpt: Clay Thumb Brush
This brush simulates deforming clay with your fingers, accumulating material during the stroke. It has a plane that tilts during the stroke in the front part of the brush to achieve this effect. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D6238
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c214
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h12
2 files changed, 226 insertions, 0 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index d1509e10886..f4c94b6e5de 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1754,6 +1754,9 @@ static float brush_strength(const Sculpt *sd,
/* Clay Strips needs less strength to compensate the curve. */
final_pressure = pressure * pressure * pressure;
return alpha * flip * final_pressure * overlap * feather * 0.3f;
+ case SCULPT_TOOL_CLAY_THUMB:
+ final_pressure = pressure * pressure;
+ return alpha * flip * final_pressure * overlap * feather * 1.3f;
case SCULPT_TOOL_MASK:
overlap = (1.0f + overlap) / 2.0f;
@@ -5753,6 +5756,188 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
BKE_pbvh_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
}
+/* -------------------------------------------------------------------- */
+
+/** \name Sculpt Clay Thumb Brush
+ * \{ */
+
+static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
+ const float hardness = 0.50f;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = data->clay_strength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ float plane_tilt[4];
+ float normal_tilt[3];
+ float imat[4][4];
+
+ invert_m4_m4(imat, mat);
+ rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle));
+
+ /* Plane aligned to the geometry normal (back part of the brush). */
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ /* Tilted plane (front part of the brush). */
+ plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ float local_co[3];
+ mul_v3_m4v3(local_co, mat, vd.co);
+ float intr[3], intr_tilt[3];
+ float val[3];
+
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co);
+
+ /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex
+ * coordinates. */
+ /* We can also control the mix with a curve if it produces noticeable artifacts in the center
+ * of the brush. */
+ const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f;
+ interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
+ sub_v3_v3v3(val, intr_tilt, vd.co);
+
+ /* Deform the real vertex test distance with a hardness factor. This moves the falloff
+ * towards the edges of the brush, producing a more defined falloff and a flat center. */
+ 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);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static float sculpt_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
+{
+ float final_pressure = 0.0f;
+ for (int i = 0; i < CLAY_STABILIZER_LEN; i++) {
+ final_pressure += cache->clay_pressure_stabilizer[i];
+ }
+ return final_pressure / (float)CLAY_STABILIZER_LEN;
+}
+
+static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+ const float offset = get_offset(sd, ss);
+ const float displace = radius * (0.25f + offset);
+
+ /* Sampled geometry normal and area center. */
+ float area_no_sp[3];
+ float area_no[3];
+ float area_co[3];
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ calc_area_normal(sd, ob, nodes, totnode, area_no);
+ }
+ else {
+ copy_v3_v3(area_no, area_no_sp);
+ }
+
+ /* Delay the first daub because grab delta is not setup. */
+ if (ss->cache->first_time) {
+ ss->cache->clay_thumb_front_angle = 0.0f;
+ return;
+ }
+
+ /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
+ * stroke. */
+ if (ss->cache->mirror_symmetry_pass == 0) {
+ ss->cache->clay_thumb_front_angle += 0.8f;
+ CLAMP(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f);
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ /* Displace the brush planes. */
+ copy_v3_v3(area_co, ss->cache->location);
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ /* Init brush local space matrix. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], ss->cache->location);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ /* Scale brush local space matrix. */
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
+ invert_m4_m4(mat, tmat);
+
+ float clay_strength = ss->cache->bstrength *
+ sculpt_clay_thumb_get_stabilized_pressure(ss->cache);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no_sp = area_no_sp,
+ .area_co = ss->cache->location,
+ .mat = mat,
+ .clay_strength = clay_strength,
+ };
+
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
static void do_gravity_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -6061,6 +6246,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
case SCULPT_TOOL_MULTIPLANE_SCRAPE:
do_multiplane_scrape_brush(sd, ob, nodes, totnode);
break;
+ case SCULPT_TOOL_CLAY_THUMB:
+ do_clay_thumb_brush(sd, ob, nodes, totnode);
+ break;
case SCULPT_TOOL_FILL:
if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
do_scrape_brush(sd, ob, nodes, totnode);
@@ -6586,6 +6774,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Clay Brush";
case SCULPT_TOOL_CLAY_STRIPS:
return "Clay Strips Brush";
+ case SCULPT_TOOL_CLAY_THUMB:
+ return "Clay Thumb Brush";
case SCULPT_TOOL_FILL:
return "Fill Brush";
case SCULPT_TOOL_SCRAPE:
@@ -6854,6 +7044,11 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
return max_ff(initial_size * 0.20f, initial_size * pow3f(cache->pressure));
case SCULPT_TOOL_CLAY_STRIPS:
return max_ff(initial_size * 0.35f, initial_size * pow2f(cache->pressure));
+ case SCULPT_TOOL_CLAY_THUMB: {
+ float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache);
+ return initial_size * clay_stabilized_pressure;
+ }
+
default:
return initial_size * cache->pressure;
}
@@ -6875,6 +7070,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
SCULPT_TOOL_NUDGE,
SCULPT_TOOL_CLAY_STRIPS,
SCULPT_TOOL_MULTIPLANE_SCRAPE,
+ SCULPT_TOOL_CLAY_THUMB,
SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_POSE,
SCULPT_TOOL_THUMB) ||
@@ -6911,6 +7107,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
break;
case SCULPT_TOOL_CLAY_STRIPS:
case SCULPT_TOOL_MULTIPLANE_SCRAPE:
+ case SCULPT_TOOL_CLAY_THUMB:
case SCULPT_TOOL_NUDGE:
case SCULPT_TOOL_SNAKE_HOOK:
if (brush->flag & BRUSH_ANCHORED) {
@@ -7054,6 +7251,23 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
}
}
+ /* Clay stabilized pressure. */
+ if (brush->sculpt_tool == SCULPT_TOOL_CLAY_THUMB) {
+ if (ss->cache->first_time) {
+ for (int i = 0; i < CLAY_STABILIZER_LEN; i++) {
+ ss->cache->clay_pressure_stabilizer[i] = 0.0f;
+ }
+ ss->cache->clay_pressure_stabilizer_index = 0;
+ }
+ else {
+ cache->clay_pressure_stabilizer[cache->clay_pressure_stabilizer_index] = cache->pressure;
+ cache->clay_pressure_stabilizer_index += 1;
+ if (cache->clay_pressure_stabilizer_index >= CLAY_STABILIZER_LEN) {
+ cache->clay_pressure_stabilizer_index = 0;
+ }
+ }
+ }
+
if (BKE_brush_use_size_pressure(brush) &&
paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT)) {
cache->radius = sculpt_brush_dynamic_size_get(brush, cache, cache->initial_radius);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index b29bbfd1fb0..0b5bb942032 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -221,6 +221,9 @@ typedef struct SculptThreadedTaskData {
float max_distance_squared;
float nearest_vertex_search_co[3];
+ /* Stabilized strength for the Clay Thumb brush. */
+ float clay_strength;
+
int mask_expand_update_it;
bool mask_expand_invert_mask;
bool mask_expand_use_normals;
@@ -312,6 +315,8 @@ bool sculpt_pbvh_calc_area_normal(const struct Brush *brush,
* For descriptions of these settings, check the operator properties.
*/
+#define CLAY_STABILIZER_LEN 10
+
typedef struct StrokeCache {
/* Invariants */
float initial_radius;
@@ -390,6 +395,13 @@ typedef struct StrokeCache {
/* Pose brush */
struct SculptPoseIKChain *pose_ik_chain;
+ /* Clay Thumb brush */
+ /* Angle of the front tilting plane of the brush to simulate clay accumulation. */
+ float clay_thumb_front_angle;
+ /* Stores pressure samples to get an stabilized strength and radius variation. */
+ float clay_pressure_stabilizer[CLAY_STABILIZER_LEN];
+ int clay_pressure_stabilizer_index;
+
float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
struct Dial *dial;