[Bf-blender-cvs] [f758ee5] master: Sculpt: Add rake option to snake-hook

Campbell Barton noreply at git.blender.org
Thu Jan 21 11:37:07 CET 2016


Commit: f758ee50e6d96e5342a9971bd76d9ff0352aafa3
Author: Campbell Barton
Date:   Thu Jan 21 21:05:49 2016 +1100
Branches: master
https://developer.blender.org/rBf758ee50e6d96e5342a9971bd76d9ff0352aafa3

Sculpt: Add rake option to snake-hook

This allows for dragging out shapes that rotate to follow the cursor motion.

Values over 1 can be set for 'interesting' artistic effects.

===================================================================

M	release/scripts/startup/bl_ui/space_view3d_toolbar.py
M	source/blender/editors/sculpt_paint/paint_intern.h
M	source/blender/editors/sculpt_paint/paint_utils.c
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/makesdna/DNA_brush_types.h
M	source/blender/makesrna/intern/rna_brush.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 9b6a0d4..7cff69f 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -951,6 +951,12 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
                 row = col.row(align=True)
                 row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
 
+            # rake_factor
+            if capabilities.has_rake_factor:
+                col.separator()
+                row = col.row(align=True)
+                row.prop(brush, "rake_factor", slider=True)
+
             # use_original_normal and sculpt_plane
             if capabilities.has_sculpt_plane:
                 col.separator()
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index f1e35f8..a3d7495 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -234,6 +234,7 @@ int paint_curve_poll(struct bContext *C);
 
 int facemask_paint_poll(struct bContext *C);
 void flip_v3_v3(float out[3], const float in[3], const char symm);
+void flip_qt_qt(float out[3], const float in[3], const char symm);
 
 /* stroke operator */
 typedef enum BrushStrokeMode {
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 7b66632..dc0852a 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -397,6 +397,29 @@ void flip_v3_v3(float out[3], const float in[3], const char symm)
 		out[2] = in[2];
 }
 
+void flip_qt_qt(float out[4], const float in[4], const char symm)
+{
+	float axis[3], angle;
+
+	quat_to_axis_angle(axis, &angle, in);
+	normalize_v3(axis);
+
+	if (symm & PAINT_SYMM_X) {
+		axis[0] *= -1.0f;
+		angle *= -1.0f;
+	}
+	if (symm & PAINT_SYMM_Y) {
+		axis[1] *= -1.0f;
+		angle *= -1.0f;
+	}
+	if (symm & PAINT_SYMM_Z) {
+		axis[2] *= -1.0f;
+		angle *= -1.0f;
+	}
+
+	axis_angle_normalized_to_quat(out, axis, angle);
+}
+
 /* used for both 3d view and image window */
 void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette)
 {
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index f97d877..587f334 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -158,9 +158,21 @@ static int sculpt_brush_needs_normal(const Brush *brush)
 
 	        (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
 }
-
 /** \} */
 
+static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
+{
+	return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
+}
+
+/* Factor of brush to have rake point following behind
+ * (could be configurable but this is reasonable default). */
+#define SCULPT_RAKE_BRUSH_FACTOR 0.25f
+
+struct SculptRakeData {
+	float follow_dist;
+	float follow_co[3];
+};
 
 typedef enum StrokeFlags {
 	CLIP_X = 1,
@@ -208,6 +220,11 @@ typedef struct StrokeCache {
 	float grab_delta[3], grab_delta_symmetry[3];
 	float old_grab_location[3], orig_grab_location[3];
 
+	/* screen-space rotation defined by mouse motion */
+	float   rake_rotation[4], rake_rotation_symmetry[4];
+	bool is_rake_rotation_valid;
+	struct SculptRakeData rake_data;
+
 	int symmetry; /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
 	               * 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
 	int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
@@ -328,6 +345,43 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
 	}
 }
 
+static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3])
+{
+	float rake_dist = len_v3v3(srd->follow_co, co);
+	if (rake_dist > srd->follow_dist) {
+		interp_v3_v3v3(srd->follow_co, srd->follow_co, co, rake_dist - srd->follow_dist);
+	}
+}
+
+
+static void sculpt_rake_rotate(
+        const SculptSession *ss, const float sculpt_co[3], const float v_co[3], float factor, float r_delta[3])
+{
+	float vec_rot[3];
+
+#if 0
+	/* lerp */
+	sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+	mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
+	add_v3_v3(vec_rot, sculpt_co);
+	sub_v3_v3v3(r_delta, vec_rot, v_co);
+	mul_v3_fl(r_delta, factor);
+#else
+	/* slerp */
+	float q_interp[4];
+	sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+
+	copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
+	mul_fac_qt_fl(q_interp, factor);
+	mul_qt_v3(q_interp, vec_rot);
+
+	add_v3_v3(vec_rot, sculpt_co);
+	sub_v3_v3v3(r_delta, vec_rot, v_co);
+#endif
+
+}
+
+
 /** \name SculptProjectVector
  *
  * Fast-path for #project_plane_v3_v3v3
@@ -2230,6 +2284,7 @@ static void do_snake_hook_brush_task_cb_ex(
 	SculptBrushTest test;
 	float (*proxy)[3];
 	const float bstrength = ss->cache->bstrength;
+	const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
 
 	proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
 
@@ -2243,6 +2298,12 @@ static void do_snake_hook_brush_task_cb_ex(
 
 			mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
 
+			if (do_rake_rotation) {
+				float delta_rotate[3];
+				sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
+				add_v3_v3(proxy[vd.i], delta_rotate);
+			}
+
 			if (vd.mvert)
 				vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 		}
@@ -3605,6 +3666,10 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
 		flip_v3_v3(cache->gravity_direction, cache->true_gravity_direction, symm);
 		mul_m4_v3(cache->symm_rot_mat, cache->gravity_direction);
 	}
+
+	if (cache->is_rake_rotation_valid) {
+		flip_qt_qt(cache->rake_rotation_symmetry, cache->rake_rotation, symm);
+	}
 }
 
 typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups);
@@ -4098,6 +4163,54 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
 			copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
 			ups->anchored_size = ups->pixel_radius;
 		}
+
+
+		/* handle 'rake' */
+		cache->is_rake_rotation_valid = false;
+
+		if (cache->first_time) {
+			copy_v3_v3(cache->rake_data.follow_co, grab_location);
+		}
+
+		if (sculpt_brush_needs_rake_rotation(brush)) {
+			cache->rake_data.follow_dist = cache->radius * SCULPT_RAKE_BRUSH_FACTOR;
+
+			if (!is_zero_v3(cache->grab_delta)) {
+				const float eps = 0.00001f;
+
+				float v1[3], v2[3];
+
+				copy_v3_v3(v1, cache->rake_data.follow_co);
+				copy_v3_v3(v2, cache->rake_data.follow_co);
+				sub_v3_v3(v2, cache->grab_delta);
+
+				sub_v3_v3(v1, grab_location);
+				sub_v3_v3(v2, grab_location);
+
+				if ((normalize_v3(v2) > eps) &&
+				    (normalize_v3(v1) > eps) &&
+				    (len_squared_v3v3(v1, v2) > eps))
+				{
+					const float rake_dist_sq = len_squared_v3v3(cache->rake_data.follow_co, grab_location);
+					const float rake_fade = (rake_dist_sq > SQUARE(cache->rake_data.follow_dist)) ?
+					        1.0f : sqrtf(rake_dist_sq) / cache->rake_data.follow_dist;
+
+					float axis[3], angle;
+					float tquat[4];
+
+					rotation_between_vecs_to_quat(tquat, v1, v2);
+
+					/* use axis-angle to scale rotation since the factor may be above 1 */
+					quat_to_axis_angle(axis, &angle, tquat);
+					normalize_v3(axis);
+
+					angle *= brush->rake_factor * rake_fade;
+					axis_angle_normalized_to_quat(cache->rake_rotation, axis, angle);
+					cache->is_rake_rotation_valid = true;
+				}
+			}
+			sculpt_rake_data_update(&cache->rake_data, grab_location);
+		}
 	}
 }
 
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 7ec8645..3dca087 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -69,6 +69,8 @@ typedef struct Brush {
 	char icon_filepath[1024]; /* 1024 = FILE_MAX */
 
 	float normal_weight;
+	float rake_factor;  /* rake actual data (not texture), used for sculpt */
+	int pad;
 
 	short blend;        /* blend mode */
 	short ob_mode;      /* & with ob->mode to see if the brush is compatible, use for display only. */
@@ -273,6 +275,10 @@ typedef enum BrushSculptTool {
 	SCULPT_TOOL_SNAKE_HOOK \
 	)
 
+#define SCULPT_TOOL_HAS_RAKE(t) ELEM(t, \
+	SCULPT_TOOL_SNAKE_HOOK \
+	)
+
 #define SCULPT_TOOL_HAS_DYNTOPO(t) (ELEM(t, \
 	/* These brushes, as currently coded, cannot support dynamic topology */ \
 	SCULPT_TOOL_GRAB, \
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 691fba2..9822b9f 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -154,6 +154,12 @@ static int rna_SculptToolCapabilities_has_normal_weight_get(PointerRNA *ptr)
 	return SCULPT_TOOL_HAS_NORMAL_WEIGHT(br->sculpt_tool);
 }
 
+static int rna_SculptToolCapabilities_has_rake_factor_get(PointerRNA *ptr)
+{
+	Brush *br = (Brush *)ptr->data;
+	return SCULPT_TOOL_HAS_RAKE(br->sculpt_tool);
+}
+
 static int rna_BrushCapabilities_has_overlay_get(PointerRNA *ptr)
 {
 	Brush *br = (Brush *)ptr->data;
@@ -706,6 +712,7 @@ static void rna_def_sculpt_capabilities(BlenderRNA *brna)
 	SCULPT_TOOL_CAPABILITY(has_height, "Has Height");
 	SCULPT_TOOL_CAPABILITY(has_jitter, "Has Jitter");
 	SCULPT_TOOL_CAPABILITY(has_normal_weight, "Has Crease/Pinch Factor");
+	SCULPT_TOOL_CAPABILITY(has_rake_factor, "Has Rake Factor");
 	SCULPT_TOOL_CAPABILITY(has_persistence, "Has Persistence");
 	SCULPT_TOOL_CAPABILITY(has_pinch_factor, "Has Pinch Factor");
 	SCULPT_TOOL_CAPABILITY(has_plane_offset, "Has Plane Offset");
@@ -1025,6 +1032,14 @@ static void rna_def_brush(BlenderRNA *brna)
 	RNA_def_property_ui_text(prop, "Normal Weight", "How much grab will pull vertexes out of surface during a grab");
 	RNA_def_property_update(prop, 0, "rna_Brush_update");
 
+	prop = RNA_def_property(srna, "rake_factor", PROP_FLOAT, PROP_FACTOR);
+	RNA_def_property_float_sdna(prop, NULL, "rake_factor");
+	RNA_def_property_float_default(prop, 0);
+	RNA_def_property_range(prop, 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list