[Bf-blender-cvs] [c374e9f1f5b] master: Breakdowner - Constrain Transform and Axis

Joshua Leung noreply at git.blender.org
Fri Mar 10 23:57:33 CET 2017


Commit: c374e9f1f5b936a89ad1de00f1bae17878f994f7
Author: Joshua Leung
Date:   Sat Mar 11 11:52:58 2017 +1300
Branches: master
https://developer.blender.org/rBc374e9f1f5b936a89ad1de00f1bae17878f994f7

Breakdowner - Constrain Transform and Axis

This commit adds new features to the breakdowner, giving animators more
control over what gets interpolated by the breakdowner. Specifically:

   "Just as G R S let you move rotate scale, and then X Y Z let you do that
   in one desired axis, when using the Breakdower it would be great to be
   able to add GRS and XYZ to constrain what transform / axis is being
   breakdowned."

As requested here:
https://rightclickselect.com/p/animation/csbbbc/breakdowner-constrain-transform-and-axis


Notes:
* In addition to G/R/S, there's also B (Bendy Bone settings and C (custom properties)
* Pressing G/R/S/B/C or X/Y/Z again will turn these constraints off again

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

M	source/blender/editors/armature/pose_slide.c

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

diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 8e8345d34c9..21cb405c32b 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -98,8 +98,11 @@ typedef struct tPoseSlideOp {
 	int prevFrame;      /* frame before current frame (blend-from) */
 	int nextFrame;      /* frame after current frame (blend-to) */
 	
-	int mode;           /* sliding mode (ePoseSlide_Modes) */
-	int flag;           /* unused for now, but can later get used for storing runtime settings.... */
+	short mode;         /* sliding mode (ePoseSlide_Modes) */
+	short flag;         /* unused for now, but can later get used for storing runtime settings.... */
+	
+	short channels;     /* which transforms/channels are affected (ePoseSlide_Channels) */
+	short axislock;     /* axis-limits for transforms (ePoseSlide_AxisLock) */
 	
 	float percentage;   /* 0-1 value for determining the influence of whatever is relevant */
 	
@@ -113,6 +116,49 @@ typedef enum ePoseSlide_Modes {
 	POSESLIDE_BREAKDOWN,        /* slide between the endpoint poses, finding a 'soft' spot */
 } ePoseSlide_Modes;
 
+
+/* Transforms/Channels to Affect */
+typedef enum ePoseSlide_Channels {
+	PS_TFM_ALL = 0,              /* All transforms and properties */
+	
+	PS_TFM_LOC,                  /* Loc/Rot/Scale */
+	PS_TFM_ROT,
+	PS_TFM_SIZE,
+	
+	PS_TFM_BBONE_SHAPE,          /* Bendy Bones */
+	
+	PS_TFM_PROPS                 /* Custom Properties */
+} ePoseSlide_Channels;
+
+/* Property enum for ePoseSlide_Channels */
+static EnumPropertyItem prop_channels_types[] = {
+	{PS_TFM_ALL, "ALL", 0, "All Properties", 
+	 "All properties, including transforms, bendy bone shape, and custom properties"},
+	{PS_TFM_LOC, "LOC", 0, "Location", "Location only"},
+	{PS_TFM_ROT, "ROT", 0, "Rotation", "Rotation only"},
+	{PS_TFM_SIZE, "SIZE", 0, "Scale", "Scale only"},
+	{PS_TFM_BBONE_SHAPE, "BBONE", 0, "Bendy Bone", "Bendy Bone shape properties"},
+	{PS_TFM_PROPS, "CUSTOM", 0, "Custom Properties", "Custom properties"},
+	{0, NULL, 0, NULL, NULL}
+};
+
+/* Axis Locks */
+typedef enum ePoseSlide_AxisLock {
+	PS_LOCK_X = (1 << 0),
+	PS_LOCK_Y = (1 << 1),
+	PS_LOCK_Z = (1 << 2)
+} ePoseSlide_AxisLock;
+
+/* Property enum for ePoseSlide_AxisLock */
+static EnumPropertyItem prop_axis_lock_types[] = {
+	{0, "FREE", 0, "Free", "All axes are affected"},
+	{PS_LOCK_X, "X", 0, "X", "Only X-axis transforms are affected"},
+	{PS_LOCK_Y, "Y", 0, "Y", "Only Y-axis transforms are affected"},
+	{PS_LOCK_Z, "Z", 0, "Z", "Only Z-axis transforms are affected"},
+	/* TODO: Combinations? */
+	{0, NULL, 0, NULL, NULL}
+};
+
 /* ------------------------------------ */
 
 /* operator init */
@@ -139,6 +185,10 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode)
 	pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
 	pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
 	
+	/* get the set of properties/axes that can be operated on */
+	pso->channels = RNA_enum_get(op->ptr, "channels");
+	pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
+	
 	/* check the settings from the context */
 	if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
 		return 0;
@@ -293,10 +343,20 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, floa
 	/* using this path, find each matching F-Curve for the variables we're interested in */
 	while ( (ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) {
 		FCurve *fcu = (FCurve *)ld->data;
-
-		/* just work on these channels one by one... there's no interaction between values */
+		const int idx  = fcu->array_index;
+		const int lock = pso->axislock;
+		
+		/* check if this F-Curve is ok given the current axis locks */
 		BLI_assert(fcu->array_index < 3);
-		pose_slide_apply_val(pso, fcu, &vec[fcu->array_index]);
+		
+		if ((lock == 0) ||
+		    ((lock & PS_LOCK_X) && (idx == 0)) ||
+		    ((lock & PS_LOCK_Y) && (idx == 1)) ||
+		    ((lock & PS_LOCK_Z) && (idx == 2)))
+		{
+			/* just work on these channels one by one... there's no interaction between values */
+			pose_slide_apply_val(pso, fcu, &vec[fcu->array_index]);
+		}
 	}
 	
 	/* free the temp path we got */
@@ -494,17 +554,17 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
 		 */
 		bPoseChannel *pchan = pfl->pchan;
 		 
-		if (pchan->flag & POSE_LOC) {
+		if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
 			/* calculate these for the 'location' vector, and use location curves */
 			pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
 		}
 		
-		if (pchan->flag & POSE_SIZE) {
+		if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
 			/* calculate these for the 'scale' vector, and use scale curves */
 			pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
 		}
 		
-		if (pchan->flag & POSE_ROT) {
+		if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
 			/* everything depends on the rotation mode */
 			if (pchan->rotmode > 0) {
 				/* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
@@ -519,12 +579,12 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
 			}
 		}
 		
-		if (pchan->flag & POSE_BBONE_SHAPE) {
+		if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) {
 			/* bbone properties - they all start a "bbone_" prefix */
 			pose_slide_apply_props(pso, pfl, "bbone_"); 
 		}
 		
-		if (pfl->oldprops) {
+		if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) {
 			/* not strictly a transform, but custom properties contribute to the pose produced in many rigs
 			 * (e.g. the facial rigs used in Sintel)
 			 */
@@ -553,9 +613,12 @@ static void pose_slide_reset(tPoseSlideOp *pso)
 /* ------------------------------------ */
 
 /* draw percentage indicator in header */
+// TODO: Include hints about locks here...
 static void pose_slide_draw_status(tPoseSlideOp *pso)
 {
 	char status_str[UI_MAX_DRAW_STR];
+	char limits_str[UI_MAX_DRAW_STR];
+	char axis_str[50];
 	char mode_str[32];
 	
 	switch (pso->mode) {
@@ -575,16 +638,58 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
 			break;
 	}
 	
+	switch (pso->axislock) {
+		case PS_LOCK_X:
+			BLI_strncpy(axis_str, "[X]/Y/Z axis only (X to clear)", sizeof(axis_str));
+			break;
+		case PS_LOCK_Y:
+			BLI_strncpy(axis_str, "X/[Y]/Z axis only (Y to clear)", sizeof(axis_str));
+			break;
+		case PS_LOCK_Z:
+			BLI_strncpy(axis_str, "X/Y/[Z] axis only (Z to clear)", sizeof(axis_str));
+			break;
+			
+		default:
+			if (ELEM(pso->channels, PS_TFM_LOC, PS_TFM_ROT, PS_TFM_SIZE)) {
+				BLI_strncpy(axis_str, "X/Y/Z = Axis Constraint", sizeof(axis_str));
+			}
+			else {
+				axis_str[0] = '\0';
+			}
+			break;
+	}
+	
+	switch (pso->channels) {
+		case PS_TFM_LOC:
+			BLI_snprintf(limits_str, sizeof(limits_str), "[G]/R/S/B/C - Location only (G to clear) | %s", axis_str);
+			break;
+		case PS_TFM_ROT:
+			BLI_snprintf(limits_str, sizeof(limits_str), "G/[R]/S/B/C - Rotation only (R to clear) | %s", axis_str);
+			break;
+		case PS_TFM_SIZE:
+			BLI_snprintf(limits_str, sizeof(limits_str), "G/R/[S]/B/C - Scale only (S to clear) | %s", axis_str);
+			break;
+		case PS_TFM_BBONE_SHAPE:
+			BLI_strncpy(limits_str, "G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s", sizeof(limits_str));
+			break;
+		case PS_TFM_PROPS:
+			BLI_strncpy(limits_str, "G/R/S/B/[C] - Custom Properties only (C to clear) | %s", sizeof(limits_str));
+			break;
+		default:
+			BLI_strncpy(limits_str, "G/R/S/B/C - Limit to Transform/Property Set", sizeof(limits_str));
+			break;
+	}
+	
 	if (hasNumInput(&pso->num)) {
 		Scene *scene = pso->scene;
 		char str_offs[NUM_STR_REP_LEN];
 		
 		outputNumInput(&pso->num, str_offs, &scene->unit);
 		
-		BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs);
+		BLI_snprintf(status_str, sizeof(status_str), "%s: %s     |   %s", mode_str, str_offs, limits_str);
 	}
 	else {
-		BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f));
+		BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%     |   %s", mode_str, (int)(pso->percentage * 100.0f), limits_str);
 	}
 	
 	ED_area_headerprint(pso->sa, status_str);
@@ -675,11 +780,58 @@ static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso, wmOperator *op
 	RNA_float_set(op->ptr, "percentage", pso->percentage);
 }
 
+/* handle an event to toggle channels mode */
+static void pose_slide_toggle_channels_mode(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_Channels channel)
+{
+	/* Turn channel on or off? */
+	if (pso->channels == channel) {
+		/* Already limiting to transform only, so pressing this again turns it off */
+		pso->channels = PS_TFM_ALL;
+	}
+	else {
+		/* Only this set of channels */
+		pso->channels = channel;
+	}
+	RNA_enum_set(op->ptr, "channels", pso->channels);
+	
+	
+	/* Reset axis limits too for good measure */
+	pso->axislock = 0;
+	RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+}
+
+/* handle an event to toggle axis locks - returns whether any change in state is needed */
+static bool pose_slide_toggle_axis_locks(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_AxisLock axis)
+{
+	/* Axis can only be set when a transform is set - it doesn't make sense otherwise */
+	if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE, PS_TFM_PROPS)) {
+		pso->axislock = 0;
+		RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+		return false;
+	}
+	
+	/* Turn on or off? */
+	if (pso->axislock == axis) {
+		/* Already limiting on this axis, so turn off */
+		pso->axislock = 0;
+	}
+	else {
+		/* Only this axis */
+		pso->axislock = axis;
+	}
+	RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+	
+	/* Setting changed, so pose update is needed */
+	return true;
+}
+
 /* common code for modal() */
 static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
 {
 	tPoseSlideOp *pso = op->customdata;
 	wmWindow *win = CTX_wm_window(C);
+	bool do_pose_update = false;
+	
 	const bool has_numinput = hasNumInput(&pso->num);
 	
 	switch (event->type) {
@@ -718,7 +870,8 @@ static

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list