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:
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py7
-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
6 files changed, 157 insertions, 20 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 96a27ae796c..03788ed410a 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -424,9 +424,10 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
row.prop(brush, "elastic_deform_type")
row = col.row()
row.prop(brush, "elastic_deform_volume_preservation", slider=True)
-
-
- if brush.sculpt_tool == 'GRAB':
+ elif brush.sculpt_tool == 'POSE':
+ row = col.row()
+ row.prop(brush, "pose_offset")
+ elif brush.sculpt_tool == 'GRAB':
col.separator()
row = col.row()
row.prop(brush, "use_grab_active_vertex")
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);