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:
authorCampbell Barton <ideasman42@gmail.com>2016-01-21 13:05:49 +0300
committerCampbell Barton <ideasman42@gmail.com>2016-01-21 13:28:07 +0300
commitf758ee50e6d96e5342a9971bd76d9ff0352aafa3 (patch)
tree17dd061e81f09a0966984ceaf13818c908b76109 /source/blender/editors/sculpt_paint
parentadcef2bd3686a887fba8f08192751ab6736b9782 (diff)
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.
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h1
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c23
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c115
3 files changed, 138 insertions, 1 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index f1e35f84576..a3d74956d90 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 7b66632fa42..dc0852aaee0 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 f97d877255b..587f33468a6 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);
+ }
}
}