diff options
author | Pablo Dobarro <pablodp606@gmail.com> | 2020-12-10 00:19:34 +0300 |
---|---|---|
committer | Pablo Dobarro <pablodp606@gmail.com> | 2020-12-10 00:25:16 +0300 |
commit | d870a60dd9270764d5f61457224252200376dd2d (patch) | |
tree | e8a68244c0195b8fb103497bd0284cd25bd50ef3 | |
parent | 19560eef1aedd64fc604c1f6151fa62c5c3c3957 (diff) |
Sculpt: Elastic deform type for Snake Hook
This adds deformation types to snake hook and the elastic deformation
type. This mode deforms the mesh using a kelvinlet instead of applying
the displacement directly inside the brush radius, which is great for
stylized shapes sketching.
Changes in rake rotation when using elastic are too strong when set
to 1, so I'll add a nicer way to support rake rotations with smoother
transitions in the future.
Reviewed By: sergey, JulienKaspar
Differential Revision: https://developer.blender.org/D9560
-rw-r--r-- | release/scripts/startup/bl_ui/properties_paint_common.py | 5 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 55 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 32 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_brush_types.h | 10 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_brush.c | 19 |
5 files changed, 100 insertions, 21 deletions
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 3075d76d6fa..1ae1826b609 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -643,6 +643,11 @@ def brush_settings(layout, context, brush, popover=False): layout.prop(brush, "elastic_deform_volume_preservation", slider=True) layout.separator() + elif sculpt_tool == 'SNAKE_HOOK': + layout.separator() + layout.prop(brush, "snake_hook_deform_type") + layout.separator() + elif sculpt_tool == 'POSE': layout.separator() layout.prop(brush, "deform_target") diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index b9427677745..fd7ec1da497 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4232,6 +4232,8 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, (len_v3(grab_delta) / ss->cache->radius)) : 0.0f; + const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; SculptBrushTest test; @@ -4239,18 +4241,28 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + KelvinletParams params; + BKE_kelvinlet_init_params(¶ms, ss->cache->radius, bstrength, 1.0f, 0.4f); + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sq_fn(&test, vd.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, - thread_id); + if (do_elastic || sculpt_brush_test_sq_fn(&test, vd.co)) { + + float fade; + if (do_elastic) { + fade = 1.0f; + } + else { + 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, + thread_id); + } mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -4289,6 +4301,17 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, add_v3_v3(proxy[vd.i], delta_rotate); } + if (do_elastic) { + float disp[3]; + BKE_kelvinlet_grab_triscale(disp, ¶ms, vd.co, ss->cache->location, proxy[vd.i]); + mul_v3_fl(disp, bstrength * 20.0f); + if (vd.mask) { + mul_v3_fl(disp, 1.0f - *vd.mask); + } + mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); + copy_v3_v3(proxy[vd.i], disp); + } + if (vd.mvert) { vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } @@ -5714,16 +5737,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe /* Build a list of all nodes that are potentially within the brush's area of influence */ - /* These brushes need to update all nodes as they are not constrained by the brush radius */ - /* Elastic deform needs all nodes to avoid artifacts as the effect of the brush is not - * constrained by the radius. */ - /* Pose needs all nodes because it applies all symmetry iterations at the same time and the IK - * chain can grow to any area of the model. */ - /* This can be optimized by filtering the nodes after calculating the chain. */ - if (ELEM(brush->sculpt_tool, - SCULPT_TOOL_ELASTIC_DEFORM, - SCULPT_TOOL_POSE, - SCULPT_TOOL_BOUNDARY)) { + if (SCULPT_tool_needs_all_pbvh_nodes(brush)) { + /* These brushes need to update all nodes as they are not constrained by the brush radius */ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); } else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) { diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 99ee22328ea..3b48207f461 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -434,6 +434,38 @@ BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM); } +BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush) +{ + if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) { + /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect + * of the Kelvinlet is not constrained by the radius. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_POSE) { + /* Pose needs all nodes because it applies all symmetry iterations at the same time + * and the IK chain can grow to any area of the model. */ + /* TODO: This can be optimized by filtering the nodes after calculating the chain. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) { + /* Boundary needs all nodes because it is not possible to know where the boundary + * deformation is going to be propagated before calculating it. */ + /* TODO: after calculating the boudnary info in the first iteration, it should be + * possible to get the nodes that have vertices included in any boundary deformation + * and cache them. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK && + brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) { + /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */ + return true; + } + return false; +} + /* Pose Brush. */ void SCULPT_do_pose_brush(struct Sculpt *sd, struct Object *ob, diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 50aac69da19..7bd3c7d0117 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -402,6 +402,11 @@ typedef enum eBrushBoundaryFalloffType { BRUSH_BOUNDARY_FALLOFF_LOOP_INVERT = 3, } eBrushBoundaryFalloffType; +typedef enum eBrushSnakeHookDeformType { + BRUSH_SNAKE_HOOK_DEFORM_FALLOFF = 0, + BRUSH_SNAKE_HOOK_DEFORM_ELASTIC = 1, +} eBrushSnakeHookDeformType; + /* Gpencilsettings.Vertex_mode */ typedef enum eGp_Vertex_Mode { /* Affect to Stroke only. */ @@ -573,7 +578,7 @@ typedef struct Brush { char gpencil_sculpt_tool; /** Active grease pencil weight tool. */ char gpencil_weight_tool; - char _pad1[2]; + char _pad1[6]; float autosmooth_factor; @@ -607,6 +612,9 @@ typedef struct Brush { int elastic_deform_type; float elastic_deform_volume_preservation; + /* snake hook */ + int snake_hook_deform_type; + /* pose */ int pose_deform_type; float pose_offset; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index cf36c1a3742..b5ce7976fd8 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -2072,6 +2072,20 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem brush_snake_hook_deform_type_items[] = { + {BRUSH_SNAKE_HOOK_DEFORM_FALLOFF, + "FALLOFF", + 0, + "Radius Falloff", + "Applies the brush falloff in the tip of the brush"}, + {BRUSH_SNAKE_HOOK_DEFORM_ELASTIC, + "ELASTIC", + 0, + "Elastic", + "Modifies the entire mesh using elastic deform"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem brush_cloth_deform_type_items[] = { {BRUSH_CLOTH_DEFORM_DRAG, "DRAG", 0, "Drag", ""}, {BRUSH_CLOTH_DEFORM_PUSH, "PUSH", 0, "Push", ""}, @@ -2309,6 +2323,11 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "snake_hook_deform_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_snake_hook_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"); + prop = RNA_def_property(srna, "cloth_deform_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, brush_cloth_deform_type_items); RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); |