diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_transform.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_transform.c | 182 |
1 files changed, 169 insertions, 13 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index b3616254b26..8856e3bf3db 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -16,6 +16,7 @@ #include "BKE_brush.h" #include "BKE_context.h" +#include "BKE_kelvinlet.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_object.h" @@ -33,6 +34,7 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_sculpt.h" +#include "ED_view3d.h" #include "paint_intern.h" #include "sculpt_intern.h" @@ -54,6 +56,10 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob) copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot); copy_v3_v3(ss->init_pivot_scale, ss->pivot_scale); + copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos); + copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot); + copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale); + SCULPT_undo_push_begin(ob, "Transform"); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); @@ -61,10 +67,18 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob) SCULPT_vertex_random_access_ensure(ss); SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS); + + if (sd->transform_mode == SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC) { + ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL; + } + else { + ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL; + } } static void sculpt_transform_matrices_init(SculptSession *ss, const char symm, + const SculptTransformDisplacementMode t_mode, float r_transform_mats[8][4][4]) { @@ -73,9 +87,18 @@ static void sculpt_transform_matrices_init(SculptSession *ss, transform_mat[4][4]; float start_pivot_pos[3], start_pivot_rot[4], start_pivot_scale[3]; - copy_v3_v3(start_pivot_pos, ss->init_pivot_pos); - copy_v4_v4(start_pivot_rot, ss->init_pivot_rot); - copy_v3_v3(start_pivot_scale, ss->init_pivot_scale); + switch (t_mode) { + case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL: + copy_v3_v3(start_pivot_pos, ss->init_pivot_pos); + copy_v4_v4(start_pivot_rot, ss->init_pivot_rot); + copy_v3_v3(start_pivot_scale, ss->init_pivot_scale); + break; + case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL: + copy_v3_v3(start_pivot_pos, ss->prev_pivot_pos); + copy_v4_v4(start_pivot_rot, ss->prev_pivot_rot); + copy_v3_v3(start_pivot_scale, ss->prev_pivot_scale); + break; + } for (int i = 0; i < PAINT_SYMM_AREAS; i++) { ePaintSymmetryAreas v_symm = i; @@ -127,23 +150,33 @@ static void sculpt_transform_task_cb(void *__restrict userdata, PBVHNode *node = data->nodes[i]; SculptOrigVertData orig_data; - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]); + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i], SCULPT_UNDO_COORDS); PBVHVertexIter vd; SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS); BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); + float *start_co; float transformed_co[3], orig_co[3], disp[3]; float fade = vd.mask ? *vd.mask : 0.0f; copy_v3_v3(orig_co, orig_data.co); char symm_area = SCULPT_get_vertex_symm_area(orig_co); - copy_v3_v3(transformed_co, orig_co); + switch (ss->filter_cache->transform_displacement_mode) { + case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL: + start_co = orig_co; + break; + case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL: + start_co = vd.co; + break; + } + + copy_v3_v3(transformed_co, start_co); mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co); - sub_v3_v3v3(disp, transformed_co, orig_co); + sub_v3_v3v3(disp, transformed_co, start_co); mul_v3_fl(disp, 1.0f - fade); - add_v3_v3v3(vd.co, orig_co, disp); + add_v3_v3v3(vd.co, start_co, disp); if (vd.mvert) { BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); @@ -165,7 +198,8 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob) .nodes = ss->filter_cache->nodes, }; - sculpt_transform_matrices_init(ss, symm, data.transform_mats); + sculpt_transform_matrices_init( + ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats); /* Regular transform applies all symmetry passes at once as it is split by symmetry areas * (each vertex can only be transformed once by the transform matrix of its area). */ @@ -175,6 +209,98 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob) 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings); } +static void sculpt_elastic_transform_task_cb(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + PBVHNode *node = data->nodes[i]; + + float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[i])->co; + + SculptOrigVertData orig_data; + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i], SCULPT_UNDO_COORDS); + + KelvinletParams params; + /* TODO(pablodp606): These parameters can be exposed if needed as transform strength and volume + * preservation like in the elastic deform brushes. Setting them to the same default as elastic + * deform triscale grab because they work well in most cases. */ + const float force = 1.0f; + const float shear_modulus = 1.0f; + const float poisson_ratio = 0.4f; + BKE_kelvinlet_init_params( + ¶ms, data->elastic_transform_radius, force, shear_modulus, poisson_ratio); + + SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + float transformed_co[3], orig_co[3], disp[3]; + const float fade = vd.mask ? *vd.mask : 0.0f; + copy_v3_v3(orig_co, orig_data.co); + + copy_v3_v3(transformed_co, vd.co); + mul_m4_v3(data->elastic_transform_mat, transformed_co); + sub_v3_v3v3(disp, transformed_co, vd.co); + + float final_disp[3]; + BKE_kelvinlet_grab_triscale(final_disp, ¶ms, vd.co, data->elastic_transform_pivot, disp); + mul_v3_fl(final_disp, 20.0f * (1.0f - fade)); + + copy_v3_v3(proxy[vd.i], final_disp); + + if (vd.mvert) { + BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + } + } + BKE_pbvh_vertex_iter_end; + + BKE_pbvh_node_mark_update(node); +} + +static void sculpt_transform_radius_elastic(Sculpt *sd, Object *ob, const float transform_radius) +{ + SculptSession *ss = ob->sculpt; + BLI_assert(ss->filter_cache->transform_displacement_mode == + SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL); + + const char symm = SCULPT_mesh_symmetry_xyz_get(ob); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .nodes = ss->filter_cache->nodes, + .elastic_transform_radius = transform_radius, + }; + + sculpt_transform_matrices_init( + ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats); + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode); + + /* Elastic transform needs to apply all transform matrices to all vertices and then combine the + * displacement proxies as all vertices are modified by all symmetry passes. */ + for (ePaintSymmetryFlags symmpass = 0; symmpass <= symm; symmpass++) { + if (SCULPT_is_symmetry_iteration_valid(symmpass, symm)) { + flip_v3_v3(data.elastic_transform_pivot, ss->pivot_pos, symmpass); + flip_v3_v3(data.elastic_transform_pivot_init, ss->init_pivot_pos, symmpass); + + printf( + "%.2f %.2f %.2f\n", ss->init_pivot_pos[0], ss->init_pivot_pos[1], ss->init_pivot_pos[2]); + + const int symm_area = SCULPT_get_vertex_symm_area(data.elastic_transform_pivot); + copy_m4_m4(data.elastic_transform_mat, data.transform_mats[symm_area]); + BLI_task_parallel_range( + 0, ss->filter_cache->totnode, &data, sculpt_elastic_transform_task_cb, &settings); + } + } + SCULPT_combine_transform_proxies(sd, ob); +} + void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -184,7 +310,36 @@ void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob) SCULPT_vertex_random_access_ensure(ss); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); - sculpt_transform_all_vertices(sd, ob); + switch (sd->transform_mode) { + case SCULPT_TRANSFORM_MODE_ALL_VERTICES: { + sculpt_transform_all_vertices(sd, ob); + break; + } + case SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC: { + Brush *brush = BKE_paint_brush(&sd->paint); + Scene *scene = CTX_data_scene(C); + float transform_radius; + + if (BKE_brush_use_locked_size(scene, brush)) { + transform_radius = BKE_brush_unprojected_radius_get(scene, brush); + } + else { + ViewContext vc; + + ED_view3d_viewcontext_init(C, &vc, depsgraph); + + transform_radius = paint_calc_object_space_radius( + &vc, ss->init_pivot_pos, BKE_brush_size_get(scene, brush)); + } + + sculpt_transform_radius_elastic(sd, ob, transform_radius); + break; + } + } + + copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos); + copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot); + copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale); if (ss->deform_modifiers_active || ss->shapekey_active) { SCULPT_flush_stroke_deform(sd, ob, true); @@ -267,10 +422,11 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op) /* Pivot to ray-cast surface. */ else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) { float stroke_location[3]; - float mouse[2]; - mouse[0] = RNA_float_get(op->ptr, "mouse_x"); - mouse[1] = RNA_float_get(op->ptr, "mouse_y"); - if (SCULPT_stroke_get_location(C, stroke_location, mouse)) { + const float mval[2] = { + RNA_float_get(op->ptr, "mouse_x"), + RNA_float_get(op->ptr, "mouse_y"), + }; + if (SCULPT_stroke_get_location(C, stroke_location, mval, false)) { copy_v3_v3(ss->pivot_pos, stroke_location); } } |