diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_paint_common.py | 4 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 32 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_boundary.c | 24 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_cloth.c | 31 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 15 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_pose.c | 5 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_brush_types.h | 9 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_brush.c | 20 |
8 files changed, 118 insertions, 22 deletions
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 5f15fa00562..a20de3e29db 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -641,6 +641,8 @@ def brush_settings(layout, context, brush, popover=False): elif sculpt_tool == 'POSE': layout.separator() + layout.prop(brush, "deform_target") + layout.separator() layout.prop(brush, "pose_deform_type") layout.prop(brush, "pose_origin_type") layout.prop(brush, "pose_offset") @@ -721,6 +723,8 @@ def brush_settings(layout, context, brush, popover=False): col.prop(brush, "smear_deform_type") elif sculpt_tool == 'BOUNDARY': + layout.prop(brush, "deform_target") + layout.separator() col = layout.column() col.prop(brush, "boundary_deform_type") col.prop(brush, "boundary_falloff_type") diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 5d09109c506..e1c1b8ee5fb 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -275,6 +275,19 @@ void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]) SCULPT_vertex_normal_get(ss, SCULPT_active_vertex_get(ss), normal); } +float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss, + const int deform_target, + PBVHVertexIter *iter) +{ + switch (deform_target) { + case BRUSH_DEFORM_TARGET_GEOMETRY: + return iter->co; + case BRUSH_DEFORM_TARGET_CLOTH_SIM: + return ss->cache->cloth_sim->deformation_pos[iter->index]; + } + return iter->co; +} + /* Sculpt Face Sets and Visibility. */ int SCULPT_active_face_set_get(SculptSession *ss) @@ -5690,6 +5703,16 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe SCULPT_pose_brush_init(sd, ob, ss, brush); } + if (brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM) { + if (!ss->cache->cloth_sim) { + ss->cache->cloth_sim = SCULPT_cloth_brush_simulation_create(ss, brush, 1.0f, 0.0f, false); + SCULPT_cloth_brush_simulation_init(ss, ss->cache->cloth_sim); + SCULPT_cloth_brush_build_nodes_constraints( + sd, ob, nodes, totnode, ss->cache->cloth_sim, ss->cache->location, FLT_MAX); + } + SCULPT_cloth_brush_store_simulation_state(ss, ss->cache->cloth_sim); + } + bool invert = ss->cache->pen_flip || ss->cache->invert || brush->flag & BRUSH_DIR_IN; /* Apply one type of brush action. */ @@ -5828,6 +5851,12 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe do_gravity(sd, ob, nodes, totnode, sd->gravity_factor); } + if (brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM) { + if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) { + SCULPT_cloth_brush_do_simulation_step(sd, ob, ss->cache->cloth_sim, nodes, totnode); + } + } + MEM_SAFE_FREE(nodes); /* Update average stroke position. */ @@ -7308,7 +7337,8 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op) need_mask = true; } - if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) { + if (brush->sculpt_tool == SCULPT_TOOL_CLOTH || + brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM) { need_mask = true; } diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c index a188d6a678c..5e01e034715 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -633,6 +633,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, const int symm_area = ss->cache->mirror_symmetry_pass; SculptBoundary *boundary = ss->cache->boundaries[symm_area]; const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + const Brush *brush = data->brush; const float strength = ss->cache->bstrength; @@ -657,12 +658,13 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, orig_data.co, boundary->initial_vertex_position, symm)) { const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; float t_orig_co[3]; + float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]); - rotate_v3_v3v3fl(vd.co, + rotate_v3_v3v3fl(target_co, t_orig_co, boundary->bend.pivot_rotation_axis[vd.index], angle * boundary->edit_info[vd.index].strength_factor * mask); - add_v3_v3(vd.co, boundary->bend.pivot_positions[vd.index]); + add_v3_v3(target_co, boundary->bend.pivot_positions[vd.index]); } } @@ -682,6 +684,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, const int symm_area = ss->cache->mirror_symmetry_pass; SculptBoundary *boundary = ss->cache->boundaries[symm_area]; const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + const Brush *brush = data->brush; const float strength = ss->cache->bstrength; @@ -699,7 +702,8 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, if (SCULPT_check_vertex_pivot_symmetry( orig_data.co, boundary->initial_vertex_position, symm)) { const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - madd_v3_v3v3fl(vd.co, + float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); + madd_v3_v3v3fl(target_co, orig_data.co, boundary->slide.directions[vd.index], boundary->edit_info[vd.index].strength_factor * disp * mask * strength); @@ -722,6 +726,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, const int symm_area = ss->cache->mirror_symmetry_pass; SculptBoundary *boundary = ss->cache->boundaries[symm_area]; const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + const Brush *brush = data->brush; const float strength = ss->cache->bstrength; @@ -741,7 +746,8 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; float normal[3]; normal_short_to_float_v3(normal, orig_data.no); - madd_v3_v3v3fl(vd.co, + float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); + madd_v3_v3v3fl(target_co, orig_data.co, normal, boundary->edit_info[vd.index].strength_factor * disp * mask * strength); @@ -764,6 +770,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, const int symm_area = ss->cache->mirror_symmetry_pass; SculptBoundary *boundary = ss->cache->boundaries[symm_area]; const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + const Brush *brush = data->brush; const float strength = ss->cache->bstrength; @@ -779,7 +786,8 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, if (SCULPT_check_vertex_pivot_symmetry( orig_data.co, boundary->initial_vertex_position, symm)) { const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - madd_v3_v3v3fl(vd.co, + float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); + madd_v3_v3v3fl(target_co, orig_data.co, ss->cache->grab_delta_symmetry, boundary->edit_info[vd.index].strength_factor * mask * strength); @@ -802,6 +810,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, const int symm_area = ss->cache->mirror_symmetry_pass; SculptBoundary *boundary = ss->cache->boundaries[symm_area]; const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + const Brush *brush = data->brush; const float strength = ss->cache->bstrength; @@ -826,12 +835,13 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, orig_data.co, boundary->initial_vertex_position, symm)) { const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; float t_orig_co[3]; + float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); sub_v3_v3v3(t_orig_co, orig_data.co, boundary->twist.pivot_position); - rotate_v3_v3v3fl(vd.co, + rotate_v3_v3v3fl(target_co, t_orig_co, boundary->twist.rotation_axis, angle * mask * boundary->edit_info[vd.index].strength_factor); - add_v3_v3(vd.co, boundary->twist.pivot_position); + add_v3_v3(target_co, boundary->twist.pivot_position); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index acfa04022cb..ea94398ee5d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -134,6 +134,7 @@ static float cloth_brush_simulation_falloff_get(const Brush *brush, #define CLOTH_SIMULATION_ITERATIONS 5 #define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024 #define CLOTH_SIMULATION_TIME_STEP 0.01f +#define CLOTH_DEFORMATION_TARGET_STRENGTH 0.35f static bool cloth_brush_sim_has_length_constraint(SculptClothSimulation *cloth_sim, const int v1, @@ -297,9 +298,22 @@ static void do_cloth_brush_build_constraints_task_cb_ex( } } - if (cloth_is_deform_brush && len_squared < radius_squared) { - const float fade = BKE_brush_curve_strength(brush, sqrtf(len_squared), ss->cache->radius); - cloth_brush_add_deformation_constraint(data->cloth_sim, vd.index, fade); + if (brush && brush->sculpt_tool == SCULPT_TOOL_CLOTH) { + /* The cloth brush works by applying forces in most of its modes, but some of them require + * deformation coordinates to make the simulation stable. */ + if (cloth_is_deform_brush && len_squared < radius_squared) { + /* When a deform brush is used as part of the cloth brush, deformation constraints are + * created with different strengths and only inside the radius of the brush. */ + const float fade = BKE_brush_curve_strength(brush, sqrtf(len_squared), ss->cache->radius); + cloth_brush_add_deformation_constraint(data->cloth_sim, vd.index, fade); + } + } + else if (data->cloth_sim->deformation_pos) { + /* Any other tool that target the cloth simulation handle the falloff in + * their own code when modifying the deformation coordinates of the simulation, so + * deformation constraints are created with a fixed strength for all vercies. */ + cloth_brush_add_deformation_constraint( + data->cloth_sim, vd.index, CLOTH_DEFORMATION_TARGET_STRENGTH); } if (pin_simulation_boundary) { @@ -716,7 +730,7 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss, } } -static void cloth_brush_do_simulation_step( +void SCULPT_cloth_brush_do_simulation_step( Sculpt *sd, Object *ob, SculptClothSimulation *cloth_sim, PBVHNode **nodes, int totnode) { SculptSession *ss = ob->sculpt; @@ -924,7 +938,6 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode { SculptSession *ss = ob->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); - const int totverts = SCULPT_vertex_count_get(ss); /* In the first brush step of each symmetry pass, build the constraints for the vertices in all * nodes inside the simulation's limits. */ @@ -954,15 +967,13 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode } /* Store the initial state in the simulation. */ - for (int i = 0; i < totverts; i++) { - copy_v3_v3(ss->cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i)); - } + SCULPT_cloth_brush_store_simulation_state(ss, ss->cache->cloth_sim); /* Apply forces to the vertices. */ cloth_brush_apply_brush_foces(sd, ob, nodes, totnode); /* Update and write the simulation to the nodes. */ - cloth_brush_do_simulation_step(sd, ob, ss->cache->cloth_sim, nodes, totnode); + SCULPT_cloth_brush_do_simulation_step(sd, ob, ss->cache->cloth_sim, nodes, totnode); } void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim) @@ -1189,7 +1200,7 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent 0, ss->filter_cache->totnode, &data, cloth_filter_apply_forces_task_cb, &settings); /* Update and write the simulation to the nodes. */ - cloth_brush_do_simulation_step( + SCULPT_cloth_brush_do_simulation_step( sd, ob, ss->filter_cache->cloth_sim, ss->filter_cache->nodes, ss->filter_cache->totnode); if (ss->deform_modifiers_active || ss->shapekey_active) { diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index df81deeb9d4..548ef00ad87 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -104,6 +104,12 @@ void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[ * current coordinate of the vertex. */ void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]); +/* Returns the pointer to the coordinates that should be edited from a brush tool iterator + * depending on the given deformation target. */ +float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss, + const int deform_target, + PBVHVertexIter *iter); + #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 typedef struct SculptVertexNeighborIter { /* Storage */ @@ -350,6 +356,7 @@ void SCULPT_do_cloth_brush(struct Sculpt *sd, struct Object *ob, struct PBVHNode **nodes, int totnode); + void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim); struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(struct SculptSession *ss, @@ -391,8 +398,12 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr, BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) { - return brush->sculpt_tool == SCULPT_TOOL_CLOTH && - brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB; + return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && + brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) || + /* All brushes that are not the cloth brush deform the simulation using softbody + constriants instead of applying forces. */ + (brush->sculpt_tool != SCULPT_TOOL_CLOTH && + brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM); } /* Pose Brush. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index 4d41d069155..e53e33c1186 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -165,6 +165,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata, SculptSession *ss = data->ob->sculpt; SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; SculptPoseIKChainSegment *segments = ik_chain->segments; + const Brush *brush = data->brush; PBVHVertexIter vd; float disp[3], new_co[3]; @@ -206,7 +207,9 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata, /* Apply the accumulated displacement to the vertex. */ add_v3_v3v3(final_pos, orig_data.co, total_disp); - copy_v3_v3(vd.co, final_pos); + + float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); + copy_v3_v3(target_co, final_pos); if (vd.mvert) { vd.mvert->flag |= ME_VERT_PBVH_UPDATE; diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 6c4d2856526..3873763e3e0 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -322,6 +322,11 @@ typedef enum eBrushCurvePreset { BRUSH_CURVE_SMOOTHER = 9, } eBrushCurvePreset; +typedef enum eBrushDeformTarget { + BRUSH_DEFORM_TARGET_GEOMETRY = 0, + BRUSH_DEFORM_TARGET_CLOTH_SIM = 1, +} eBrushDeformTarget; + typedef enum eBrushElasticDeformType { BRUSH_ELASTIC_DEFORM_GRAB = 0, BRUSH_ELASTIC_DEFORM_GRAB_BISCALE = 1, @@ -539,7 +544,7 @@ typedef struct Brush { /** Source for fill tool color gradient application. */ char gradient_fill_mode; - char _pad0[1]; + char _pad0[5]; /** Projection shape (sphere, circle). */ char falloff_shape; @@ -587,6 +592,8 @@ typedef struct Brush { /* Maximun distance to search fake neighbors from a vertex. */ float disconnected_distance_max; + int deform_target; + /* automasking */ int automasking_flags; int automasking_boundary_edges_propagation_steps; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index cc39a5dbe8d..fa48cf2f399 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1979,6 +1979,20 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem brush_deformation_target_items[] = { + {BRUSH_DEFORM_TARGET_GEOMETRY, + "GEOMETRY", + 0, + "Geometry", + "Brush deformation displaces the vertices of the mesh"}, + {BRUSH_DEFORM_TARGET_CLOTH_SIM, + "CLOTH_SIM", + 0, + "Cloth Simulation", + "Brush deforms the mesh by deforming the constraints of a cloth simulation"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem brush_elastic_deform_type_items[] = { {BRUSH_ELASTIC_DEFORM_GRAB, "GRAB", 0, "Grab", ""}, {BRUSH_ELASTIC_DEFORM_GRAB_BISCALE, "GRAB_BISCALE", 0, "Bi-scale Grab", ""}, @@ -2207,6 +2221,12 @@ 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, "deform_target", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_deformation_target_items); + RNA_def_property_ui_text( + prop, "Deformation Target", "How the deformation of the brush will affect the object"); + 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"); |