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:
authorPablo Dobarro <pablodp606@gmail.com>2019-09-27 19:03:18 +0300
committerPablo Dobarro <pablodp606@gmail.com>2019-09-27 19:35:42 +0300
commit6a74b7c14b393c769f85e78360ec0e74198199cf (patch)
tree9e5eed6ce58313371848198b108200b798b450f7 /source/blender
parent7ae549448eabe633091a0c94257dc6090eda0d64 (diff)
Sculpt: Pose brush origin offset
With the previous behavior, it was impossible to manipulate areas with a lot of complex shapes like fingers, as the pose origin was calculated only with the topology inside the radius. With pose offset, the previous method is used to calculate the direction of the "bone", and an extra offset is added on top of it. This way you can set the pose origin in the correct place in this kind of situations. The pose factor grows to fit the new rotation origin. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D5841
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c146
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h5
-rw-r--r--source/blender/makesdna/DNA_brush_types.h5
-rw-r--r--source/blender/makesrna/intern/rna_brush.c7
5 files changed, 153 insertions, 17 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index df3d4b115cc..286cf97c20e 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1352,10 +1352,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
SculptCursorGeometryInfo gi;
float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin};
+ int prev_active_vertex_index = -1;
bool is_cursor_over_mesh = false;
/* Update the active vertex */
- if ((mode == PAINT_MODE_SCULPT) && !ups->stroke_active) {
+ if ((mode == PAINT_MODE_SCULPT) && ss && !ups->stroke_active) {
+ prev_active_vertex_index = ss->active_vertex_index;
is_cursor_over_mesh = sculpt_cursor_geometry_info_update(
C, &gi, mouse, !(brush->falloff_shape & BRUSH_AIRBRUSH));
}
@@ -1374,7 +1376,6 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
if (!ups->stroke_active) {
- int prev_active_vertex_index = ss->active_vertex_index;
bool update_previews = false;
if (is_cursor_over_mesh && !alpha_overlay_active) {
@@ -1404,7 +1405,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
if (update_previews) {
BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false);
sculpt_pose_calc_pose_data(
- sd, vc.obact, ss, gi.location, rds, ss->pose_origin, NULL);
+ sd, vc.obact, ss, gi.location, rds, brush->pose_offset, ss->pose_origin, NULL);
}
cursor_draw_point_screen_space(pos, ar, ss->pose_origin, vc.obact->obmat, 5);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 5a5d29806d7..b15262064b3 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -3574,32 +3574,107 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
}
-static void pose_brush_init_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+typedef struct PoseGrowFactorTLSData {
+ float pos_avg[3];
+ int tot_pos_avg;
+} PoseGrowFactorTLSData;
+
+static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
+ PoseGrowFactorTLSData *gftd = tls->userdata_chunk;
SculptSession *ss = data->ob->sculpt;
+ const char symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SculptVertexNeighborIter ni;
- float avg = 0;
- int total = 0;
+ float max = 0.0f;
sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
{
- avg += ss->cache->pose_factor[ni.index];
- total++;
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f > max) {
+ max = vmask_f;
+ }
}
sculpt_vertex_neighbors_iter_end(ni);
-
- if (total > 0) {
- ss->cache->pose_factor[vd.index] = avg / (float)total;
+ if (max != data->pose_factor[vd.index]) {
+ if (check_vertex_pivot_symmetry(vd.co, ss->cache->pose_initial_co, symm)) {
+ add_v3_v3(gftd->pos_avg, vd.co);
+ gftd->tot_pos_avg++;
+ }
}
+ data->pose_factor[vd.index] = max;
}
+
BKE_pbvh_vertex_iter_end;
}
+static void pose_brush_grow_factor_finalize(void *__restrict userdata, void *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ PoseGrowFactorTLSData *gftd = tls;
+ add_v3_v3(data->tot_pos_avg, gftd->pos_avg);
+ data->tot_pos_count += gftd->tot_pos_avg;
+}
+
+/* Grow the factor until its boundary is near to the offset pose origin */
+static void sculpt_pose_grow_pose_factor(
+ Sculpt *sd, Object *ob, SculptSession *ss, float pose_origin[3], float *pose_factor)
+{
+ PBVHNode **nodes;
+ PBVH *pbvh = ob->sculpt->pbvh;
+ int totnode;
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .totnode = totnode,
+ .pose_factor = pose_factor,
+ };
+ TaskParallelSettings settings;
+ PoseGrowFactorTLSData gftd;
+ gftd.tot_pos_avg = 0;
+ zero_v3(gftd.pos_avg);
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.func_finalize = pose_brush_grow_factor_finalize;
+ settings.userdata_chunk = &gftd;
+ settings.userdata_chunk_size = sizeof(PoseGrowFactorTLSData);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+
+ bool grow_next_iteration = true;
+ float prev_len = FLT_MAX;
+ data.prev_mask = MEM_mallocN(sculpt_vertex_count_get(ss) * sizeof(float), "prev mask");
+ while (grow_next_iteration) {
+ zero_v3(data.tot_pos_avg);
+ data.tot_pos_count = 0;
+ zero_v3(gftd.pos_avg);
+ gftd.tot_pos_avg = 0;
+ memcpy(data.prev_mask, pose_factor, sculpt_vertex_count_get(ss) * sizeof(float));
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings);
+ if (data.tot_pos_count != 0) {
+ mul_v3_fl(data.tot_pos_avg, 1.0f / (float)data.tot_pos_count);
+ float len = len_v3v3(data.tot_pos_avg, pose_origin);
+ if (len < prev_len) {
+ prev_len = len;
+ grow_next_iteration = true;
+ }
+ else {
+ grow_next_iteration = false;
+ memcpy(pose_factor, data.prev_mask, sculpt_vertex_count_get(ss) * sizeof(float));
+ }
+ }
+ else {
+ grow_next_iteration = false;
+ }
+ }
+ MEM_freeN(data.prev_mask);
+}
+
static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3],
const float br_co[3],
float radius,
@@ -3626,6 +3701,7 @@ void sculpt_pose_calc_pose_data(Sculpt *sd,
SculptSession *ss,
float initial_location[3],
float radius,
+ float pose_offset,
float *r_pose_origin,
float *r_pose_factor)
{
@@ -3708,7 +3784,43 @@ void sculpt_pose_calc_pose_data(Sculpt *sd,
if (tot_co > 0) {
mul_v3_fl(pose_origin, 1.0f / (float)tot_co);
}
+
+ /* Offset the pose origin */
+ float pose_d[3];
+ sub_v3_v3v3(pose_d, pose_origin, pose_initial_co);
+ normalize_v3(pose_d);
+ madd_v3_v3fl(pose_origin, pose_d, radius * pose_offset);
copy_v3_v3(r_pose_origin, pose_origin);
+
+ if (pose_offset != 0 && calc_pose_factor) {
+ sculpt_pose_grow_pose_factor(sd, ob, ss, pose_origin, r_pose_factor);
+ }
+}
+
+static void pose_brush_init_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ SculptVertexNeighborIter ni;
+ float avg = 0;
+ int total = 0;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+ {
+ avg += ss->cache->pose_factor[ni.index];
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ ss->cache->pose_factor[vd.index] = avg / (float)total;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void sculpt_pose_brush_init(
@@ -3717,12 +3829,11 @@ static void sculpt_pose_brush_init(
float *pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
sculpt_pose_calc_pose_data(
- sd, ob, ss, initial_location, radius, ss->cache->pose_origin, pose_factor);
+ sd, ob, ss, initial_location, radius, br->pose_offset, ss->cache->pose_origin, pose_factor);
copy_v3_v3(ss->cache->pose_initial_co, initial_location);
ss->cache->pose_factor = pose_factor;
- /* Smooth the pose brush factor for cleaner deformation */
PBVHNode **nodes;
PBVH *pbvh = ob->sculpt->pbvh;
int totnode;
@@ -3736,6 +3847,7 @@ static void sculpt_pose_brush_init(
.nodes = nodes,
};
+ /* Smooth the pose brush factor for cleaner deformation */
for (int i = 0; i < 4; i++) {
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -5082,6 +5194,16 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
};
BKE_pbvh_search_gather(ss->pbvh, NULL, &data, &nodes, &totnode);
}
+ else if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ float final_radius = ss->cache->radius * (1 + brush->pose_offset);
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = final_radius * final_radius,
+ .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;
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index ba7c2e601ff..94ceb25c011 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -63,6 +63,7 @@ void sculpt_pose_calc_pose_data(struct Sculpt *sd,
struct SculptSession *ss,
float initial_location[3],
float radius,
+ float pose_offset,
float *r_pose_origin,
float *r_pose_factor);
@@ -198,8 +199,12 @@ typedef struct SculptThreadedTaskData {
float *pose_origin;
float *pose_initial_co;
+ float *pose_factor;
float (*transform_rot)[4], (*transform_trans)[4], (*transform_trans_inv)[4];
+ float tot_pos_avg[3];
+ int tot_pos_count;
+
float max_distance_squared;
float nearest_vertex_search_co[3];
int nearest_vertex_index;
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index a1b50e8f125..aec28c0fe75 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -321,11 +321,12 @@ typedef struct Brush {
int curve_preset;
int automasking_flags;
- char _pad1[4];
-
int elastic_deform_type;
float elastic_deform_volume_preservation;
+ /* pose */
+ float pose_offset;
+
/* overlay */
int texture_overlay_alpha;
int mask_overlay_alpha;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 9633f6595e3..8b111830cdd 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1863,6 +1863,13 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Crease Brush Pinch Factor", "How much the crease brush pinches");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "pose_offset", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "pose_offset");
+ RNA_def_property_range(prop, 0.0f, 2.0f);
+ RNA_def_property_ui_text(
+ prop, "Pose Origin Offset", "Offset of the pose origin in relation to the brush radius");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "auto_smooth_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "autosmooth_factor");
RNA_def_property_float_default(prop, 0);