diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d_toolbar.py | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/brush.c | 1 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_280.c | 7 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_stroke.c | 8 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 297 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_brush_types.h | 13 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_brush.c | 27 |
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, + ¶ms); + 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, + ¶ms); + 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); |