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:
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py7
-rw-r--r--source/blender/blenkernel/intern/brush.c1
-rw-r--r--source/blender/blenloader/intern/versioning_280.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c297
-rw-r--r--source/blender/makesdna/DNA_brush_types.h13
-rw-r--r--source/blender/makesrna/intern/rna_brush.c27
7 files changed, 349 insertions, 11 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 89d771b7026..5bc4883d1ea 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -369,6 +369,13 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
row = col.row()
row.prop(brush, "normal_radius_factor", slider=True)
+ if brush.sculpt_tool == 'ELASTIC_DEFORM':
+ col.separator()
+ row = col.row()
+ row.prop(brush, "elastic_deform_type")
+ row = col.row()
+ row.prop(brush, "elastic_deform_compressibility", slider=True)
+
# topology_rake_factor
if (
capabilities.has_topology_rake and
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index cb408d25a01..f5f7fb71a64 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -901,6 +901,7 @@ void BKE_brush_sculpt_reset(Brush *br)
br->add_col[2] = 0.750000;
break;
case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_ELASTIC_DEFORM:
case SCULPT_TOOL_SNAKE_HOOK:
case SCULPT_TOOL_THUMB:
br->size = 75;
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index c6f0f16927f..cd51ee7c4b2 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -3860,5 +3860,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ /* Elatic deform brush */
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ if (br->ob_mode & OB_MODE_SCULPT && br->elastic_deform_compressibility == 0.0f) {
+ br->elastic_deform_compressibility = 0.5f;
+ }
+ }
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 18f087e8c7b..0072888cb8d 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -221,6 +221,7 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
case PAINT_MODE_SCULPT:
if (ELEM(brush->sculpt_tool,
SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_THUMB)) {
@@ -251,7 +252,11 @@ static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode m
{
switch (mode) {
case PAINT_MODE_SCULPT:
- if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB)) {
+ if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM)) {
return false;
}
else {
@@ -949,6 +954,7 @@ static bool sculpt_is_grab_tool(Brush *br)
{
return ELEM(br->sculpt_tool,
SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 4ad69e5de2a..dce8ea105e4 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -358,7 +358,8 @@ static bool sculpt_tool_needs_original(const char sculpt_tool)
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_LAYER,
- SCULPT_TOOL_DRAW_SHARP);
+ SCULPT_TOOL_DRAW_SHARP,
+ SCULPT_TOOL_ELASTIC_DEFORM);
}
static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
@@ -388,6 +389,7 @@ static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush
SCULPT_TOOL_LAYER,
SCULPT_TOOL_NUDGE,
SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_THUMB) ||
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) ||
@@ -1445,6 +1447,9 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_ROTATE:
return alpha * pressure * feather;
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ return root_alpha * feather;
+
default:
return 0;
}
@@ -2918,6 +2923,252 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
}
+/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
+ * Pixar Technical Memo #17-03 */
+
+typedef struct KelvinletParams {
+ float f;
+ float a;
+ float b;
+ float c;
+ float radius_scaled;
+} KelvinletParams;
+
+static int sculpt_kelvinlet_get_scale_iteration_count(eBrushElasticDeformType type)
+{
+ if (type == BRUSH_ELASTIC_DEFORM_GRAB) {
+ return 1;
+ }
+ if (type == BRUSH_ELASTIC_DEFORM_GRAB_BISCALE) {
+ return 2;
+ }
+ if (type == BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE) {
+ return 3;
+ }
+ return 0;
+}
+
+static void sculpt_kelvinet_integrate(void (*kelvinlet)(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float normal[3],
+ KelvinletParams *p),
+ float r_disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float normal[3],
+ KelvinletParams *p)
+{
+ float k[4][3], k_it[4][3];
+ kelvinlet(k[0], vertex_co, location, normal, p);
+ copy_v3_v3(k_it[0], k[0]);
+ mul_v3_fl(k_it[0], 0.5f);
+ add_v3_v3v3(k_it[0], vertex_co, k_it[0]);
+ kelvinlet(k[1], k_it[0], location, normal, p);
+ copy_v3_v3(k_it[1], k[1]);
+ mul_v3_fl(k_it[1], 0.5f);
+ add_v3_v3v3(k_it[1], vertex_co, k_it[1]);
+ kelvinlet(k[2], k_it[1], location, normal, p);
+ copy_v3_v3(k_it[2], k[2]);
+ add_v3_v3v3(k_it[2], vertex_co, k_it[2]);
+ sub_v3_v3v3(k_it[2], k_it[2], location);
+ kelvinlet(k[3], k_it[2], location, normal, p);
+ copy_v3_v3(r_disp, k[0]);
+ madd_v3_v3fl(r_disp, k[1], 2);
+ madd_v3_v3fl(r_disp, k[2], 2);
+ add_v3_v3(r_disp, k[3]);
+ mul_v3_fl(r_disp, 1.0f / 6.0f);
+}
+
+/* Regularized Kelvinlets: Formula (16) */
+static void sculpt_kelvinlet_scale(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float UNUSED(normal[3]),
+ KelvinletParams *p)
+{
+ float r_v[3];
+ sub_v3_v3v3(r_v, vertex_co, location);
+ float r = len_v3(r_v);
+ float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled);
+ float u = (2.0f * p->b - p->a) * ((1.0f / (r_e * r_e * r_e))) +
+ ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e));
+ float fade = u * p->c;
+ mul_v3_v3fl(disp, r_v, fade * p->f);
+}
+
+/* Regularized Kelvinlets: Formula (15) */
+static void sculpt_kelvinlet_twist(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float normal[3],
+ KelvinletParams *p)
+{
+ float r_v[3], q_r[3];
+ sub_v3_v3v3(r_v, vertex_co, location);
+ float r = len_v3(r_v);
+ float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled);
+ float u = -p->a * ((1.0f / (r_e * r_e * r_e))) +
+ ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e));
+ float fade = u * p->c;
+ cross_v3_v3v3(q_r, normal, r_v);
+ mul_v3_v3fl(disp, q_r, fade * p->f);
+}
+
+static void do_elastic_deform_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;
+ const float *grab_delta = data->grab_delta;
+ const float *location = ss->cache->location;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ const float bstrength = ss->cache->bstrength;
+
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ /* Maybe this can be exposed to the user */
+ float radius_e[3] = {1.0f, 2.0f, 2.0f};
+ float r_e[3];
+ float kvl[3];
+ float radius_scaled[3];
+
+ radius_scaled[0] = ss->cache->radius * radius_e[0];
+ radius_scaled[1] = radius_scaled[0] * radius_e[1];
+ radius_scaled[2] = radius_scaled[1] * radius_e[2];
+
+ float shear_modulus = 1.0f;
+ float poisson_ratio = brush->elastic_deform_compressibility;
+
+ float a = 1.0f / (4.0f * (float)M_PI * shear_modulus);
+ float b = a / (4.0f * (1.0f - poisson_ratio));
+ float c = 2 * (3.0f * a - 2.0f * b);
+
+ float dir;
+ if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
+ dir = 1.0f;
+ }
+ else {
+ dir = -1.0f;
+ }
+
+ if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
+ int symm = ss->cache->mirror_symmetry_pass;
+ if (symm == 1 || symm == 2 || symm == 4 || symm == 7) {
+ dir = -dir;
+ }
+ }
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+ float fade, u, final_disp[3], weights[3];
+ float r = len_v3v3(location, orig_data.co);
+ KelvinletParams params;
+ params.a = a;
+ params.b = b;
+ params.c = c;
+ params.radius_scaled = radius_scaled[0];
+
+ int multi_scale_it = sculpt_kelvinlet_get_scale_iteration_count(brush->elastic_deform_type);
+ for (int it = 0; it < max_ii(1, multi_scale_it); it++) {
+ r_e[it] = sqrtf(r * r + radius_scaled[it] * radius_scaled[it]);
+ }
+
+ /* Regularized Kelvinlets: Formula (6) */
+ for (int s_it = 0; s_it < multi_scale_it; s_it++) {
+ kvl[s_it] = ((a - b) / r_e[s_it]) + ((b * r * r) / (r_e[s_it] * r_e[s_it] * r_e[s_it])) +
+ ((a * radius_scaled[s_it] * radius_scaled[s_it]) /
+ (2.0f * r_e[s_it] * r_e[s_it] * r_e[s_it]));
+ }
+
+ switch (brush->elastic_deform_type) {
+ /* Regularized Kelvinlets: Multi-scale extrapolation. Formula (11) */
+ case BRUSH_ELASTIC_DEFORM_GRAB:
+ fade = kvl[0] * c;
+ mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.f);
+ break;
+ case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE:
+ u = kvl[0] - kvl[1];
+ fade = u * c / ((1.0f / radius_scaled[0]) - (1.0f / radius_scaled[1]));
+ mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.0f);
+ break;
+ case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE:
+ weights[0] = 1.0f;
+ weights[1] = -(
+ (radius_scaled[2] * radius_scaled[2] - radius_scaled[0] * radius_scaled[0]) /
+ (radius_scaled[2] * radius_scaled[2] - radius_scaled[1] * radius_scaled[1]));
+ weights[2] = ((radius_scaled[1] * radius_scaled[1] - radius_scaled[0] * radius_scaled[0]) /
+ (radius_scaled[2] * radius_scaled[2] - radius_scaled[1] * radius_scaled[1]));
+
+ float u = weights[0] * kvl[0] + weights[1] * kvl[1] + weights[2] * kvl[2];
+ fade = u * c /
+ (weights[0] / radius_scaled[0] + weights[1] / radius_scaled[1] +
+ weights[2] / radius_scaled[2]);
+ mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.0f);
+ break;
+ case BRUSH_ELASTIC_DEFORM_SCALE:
+ params.f = len_v3(grab_delta) * dir * bstrength;
+ sculpt_kelvinet_integrate(sculpt_kelvinlet_scale,
+ final_disp,
+ orig_data.co,
+ location,
+ ss->cache->sculpt_normal_symm,
+ &params);
+ break;
+ case BRUSH_ELASTIC_DEFORM_TWIST:
+ params.f = len_v3(grab_delta) * dir * bstrength;
+ sculpt_kelvinet_integrate(sculpt_kelvinlet_twist,
+ final_disp,
+ orig_data.co,
+ location,
+ ss->cache->sculpt_normal_symm,
+ &params);
+ break;
+ }
+
+ if (vd.mask) {
+ mul_v3_fl(final_disp, 1.0f - *vd.mask);
+ }
+
+ copy_v3_v3(proxy[vd.i], final_disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+}
+
static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -4219,13 +4470,26 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
{
SculptSession *ss = ob->sculpt;
int totnode;
+ PBVHNode **nodes;
/* Build a list of all nodes that are potentially within the brush's area of influence */
- const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
- ss->cache->original;
- const float radius_scale = 1.0f;
- PBVHNode **nodes = sculpt_pbvh_gather_generic(
- ob, sd, brush, use_original, radius_scale, &totnode);
+
+ /* These brushes need to update all nodes as they are not constrained by the brush radius */
+ if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = FLT_MAX,
+ .original = true,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, NULL, &data, &nodes, &totnode);
+ }
+ else {
+ const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
+ ss->cache->original;
+ const float radius_scale = 1.0f;
+ nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
+ }
/* Only act if some verts are inside the brush area */
if (totnode) {
@@ -4309,6 +4573,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
break;
case SCULPT_TOOL_DRAW_SHARP:
do_draw_sharp_brush(sd, ob, nodes, totnode);
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ do_elastic_deform_brush(sd, ob, nodes, totnode);
break;
}
@@ -4374,8 +4640,11 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
Object *ob = data->ob;
/* these brushes start from original coordinates */
- const bool use_orco = ELEM(
- data->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
+ const bool use_orco = ELEM(data->brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM);
PBVHVertexIter vd;
PBVHProxyNode *proxies;
@@ -4817,6 +5086,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Simplify Brush";
case SCULPT_TOOL_DRAW_SHARP:
return "Draw Sharp Brush";
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ return "Elastic Deform Brush";
}
return "Sculpting";
@@ -5055,6 +5326,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
if (ELEM(tool,
SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_NUDGE,
SCULPT_TOOL_CLAY_STRIPS,
SCULPT_TOOL_SNAKE_HOOK,
@@ -5078,6 +5350,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
switch (tool) {
case SCULPT_TOOL_GRAB:
case SCULPT_TOOL_THUMB:
+ case SCULPT_TOOL_ELASTIC_DEFORM:
sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
invert_m4_m4(imat, ob->obmat);
mul_mat3_m4_v3(imat, delta);
@@ -5116,11 +5389,14 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
if (tool == SCULPT_TOOL_GRAB) {
copy_v3_v3(cache->anchored_location, cache->true_location);
}
+ else if (tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ copy_v3_v3(cache->anchored_location, cache->true_location);
+ }
else if (tool == SCULPT_TOOL_THUMB) {
copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
}
- if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
+ if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ELASTIC_DEFORM)) {
/* location stays the same for finding vertices in brush radius */
copy_v3_v3(cache->true_location, cache->orig_grab_location);
@@ -5636,7 +5912,8 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
/* Restore the mesh before continuing with anchored stroke */
if ((brush->flag & BRUSH_ANCHORED) ||
- (brush->sculpt_tool == SCULPT_TOOL_GRAB &&
+ ((brush->sculpt_tool == SCULPT_TOOL_GRAB ||
+ brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) &&
BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) ||
(brush->flag & BRUSH_DRAG_DOT)) {
paint_mesh_restore_co(sd, ob);
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 747c7cfb842..c5d741fd25a 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -198,6 +198,14 @@ typedef enum eBrushCurvePreset {
BRUSH_CURVE_CONSTANT = 8,
} eBrushCurvePreset;
+typedef enum eBrushElasticDeformType {
+ BRUSH_ELASTIC_DEFORM_GRAB = 0,
+ BRUSH_ELASTIC_DEFORM_GRAB_BISCALE = 1,
+ BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE = 2,
+ BRUSH_ELASTIC_DEFORM_SCALE = 3,
+ BRUSH_ELASTIC_DEFORM_TWIST = 4,
+} eBrushElasticDeformType;
+
typedef struct Brush {
ID id;
@@ -305,6 +313,9 @@ typedef struct Brush {
int curve_preset;
+ int elastic_deform_type;
+ float elastic_deform_compressibility;
+
/* overlay */
int texture_overlay_alpha;
int mask_overlay_alpha;
@@ -454,6 +465,7 @@ typedef enum eBrushSculptTool {
SCULPT_TOOL_CLAY_STRIPS = 18,
SCULPT_TOOL_MASK = 19,
SCULPT_TOOL_DRAW_SHARP = 20,
+ SCULPT_TOOL_ELASTIC_DEFORM = 21,
} eBrushSculptTool;
/* Brush.uv_sculpt_tool */
@@ -488,6 +500,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_THUMB, \
SCULPT_TOOL_LAYER, \
SCULPT_TOOL_DRAW_SHARP, \
+ SCULPT_TOOL_ELASTIC_DEFORM, \
\
/* These brushes could handle dynamic topology, \
* but user feedback indicates it's better not to */ \
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 58771023aab..5f574cc0f8e 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -92,6 +92,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""},
{SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""},
{SCULPT_TOOL_DRAW_SHARP, "DRAW_SHARP", ICON_BRUSH_SCULPT_DRAW, "Draw Sharp", ""},
+ {SCULPT_TOOL_ELASTIC_DEFORM, "ELASTIC_DEFORM", ICON_BRUSH_GRAB, "Elastic Deform", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -1595,6 +1596,19 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem brush_elastic_deform_type_items[] = {
+ {BRUSH_ELASTIC_DEFORM_GRAB, "ELASTIC_DEFORM_GRAB", 0, "Grab", ""},
+ {BRUSH_ELASTIC_DEFORM_GRAB_BISCALE, "ELASTIC_DEFORM_GRAB_BISCALE", 0, "Bi-scale Grab", ""},
+ {BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE,
+ "ELASTIC_DEFORM_GRAB_TRISCALE",
+ 0,
+ "Tri-scale Grab",
+ ""},
+ {BRUSH_ELASTIC_DEFORM_SCALE, "ELASTIC_DEFORM_SCALE", 0, "Scale", ""},
+ {BRUSH_ELASTIC_DEFORM_TWIST, "ELASTIC_DEFORM_TWIST", 0, "Twist", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "Brush", "ID");
RNA_def_struct_ui_text(
srna, "Brush", "Brush data-block for storing brush settings for painting and sculpting");
@@ -1675,6 +1689,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Curve Preset", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "elastic_deform_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_elastic_deform_type_items);
+ RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
/* number values */
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_funcs(prop, NULL, "rna_Brush_set_size", NULL);
@@ -1810,6 +1829,14 @@ static void rna_def_brush(BlenderRNA *brna)
prop, "Normal Weight", "How much grab will pull vertexes out of surface during a grab");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "elastic_deform_compressibility", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "elastic_deform_compressibility");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01f, 3);
+ RNA_def_property_ui_text(
+ prop, "Compressibility", "Material compressibility when simulating the elasticity");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "rake_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "rake_factor");
RNA_def_property_float_default(prop, 0);