[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17216] branches/animsys2/source/blender: AnimSys2: Bone Rotation (aka choice of Quaternions or Eulers)

Joshua Leung aligorith at gmail.com
Wed Oct 29 12:20:02 CET 2008


Revision: 17216
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17216
Author:   aligorith
Date:     2008-10-29 12:20:02 +0100 (Wed, 29 Oct 2008)

Log Message:
-----------
AnimSys2: Bone Rotation (aka choice of Quaternions or Eulers)

This commit introduces an attempt at allowing animators to choose to use 'euler' rotations for bones (currently, only the default rotation order is used... multiple rotation orders may be implemented later). Animators often request this feature, so it's time to prove to us that it's genuinely useful!

To switch between quaternions and eulers, use the toggles in the Transform Properties panel in PoseMode. This will switch (the active bone only) to completely using quaternion rotations or euler rotations. 
- this is a per-bone setting, but can be copied (Ctrl-C menu)
- animation curves for quaternions/eulers will only animate the bone when their respective rotation mode is active for that bone (i.e. if you insert keyframes for a bone using quaternion rotations, then switch the bone to use eulers, bone will not be animated rotating until euler-rotation keyframes are added, and visa versa)
- quaternion/euler rotation mode cannot be changed in the middle of an animation (it's not implemented, and I don't intend on doing so either... it's just asking for trouble in the long run)
- by default, quaternions will be used (to preserve backwards compatability) and also because they provide smoother interpolation + no gimble lock
- when switching between interpolation modes, there is conversion of the current rotation from quat<->euler (whichever direction is applicable) to avoid pops
- euler rotations here use standard euler interpolation. In other words, these are not quats masquerading as eulers under a fancy skin.

A number of additional notes:
- Most tools which involve rotation have been adjusted to work with this so far. 
--> Note: Copy/Paste of poses doesn't work with this yet.
- NLA pose blending is currently (experimentally) using a simple linear interpolation between euler values of poses. This may not well at all, and also there are some cases not covered by that yet.
- Improved the keyframing code a bit to add a bit of flexibility so that keyframes could be inserted without doubling up entries.

Modified Paths:
--------------
    branches/animsys2/source/blender/blenkernel/intern/action.c
    branches/animsys2/source/blender/blenkernel/intern/armature.c
    branches/animsys2/source/blender/blenkernel/intern/ipo.c
    branches/animsys2/source/blender/include/BIF_keyframing.h
    branches/animsys2/source/blender/makesdna/DNA_action_types.h
    branches/animsys2/source/blender/makesdna/DNA_ipo_types.h
    branches/animsys2/source/blender/src/drawview.c
    branches/animsys2/source/blender/src/editarmature.c
    branches/animsys2/source/blender/src/editipo.c
    branches/animsys2/source/blender/src/editipo_lib.c
    branches/animsys2/source/blender/src/keyframing.c
    branches/animsys2/source/blender/src/poseobject.c
    branches/animsys2/source/blender/src/transform.c
    branches/animsys2/source/blender/src/transform_conversions.c

Modified: branches/animsys2/source/blender/blenkernel/intern/action.c
===================================================================
--- branches/animsys2/source/blender/blenkernel/intern/action.c	2008-10-29 10:58:00 UTC (rev 17215)
+++ branches/animsys2/source/blender/blenkernel/intern/action.c	2008-10-29 11:20:02 UTC (rev 17216)
@@ -401,7 +401,9 @@
 	
 	VECCOPY(pchan->loc, chan->loc);
 	VECCOPY(pchan->size, chan->size);
+	VECCOPY(pchan->eul, chan->eul);
 	QUATCOPY(pchan->quat, chan->quat);
+	pchan->rotmode= chan->rotmode;
 	Mat4CpyMat4(pchan->chan_mat, (float(*)[4])chan->chan_mat);
 	Mat4CpyMat4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
 	pchan->flag= chan->flag;
@@ -697,7 +699,6 @@
 	bPoseChannel *dchan;
 	const bPoseChannel *schan;
 	bConstraint *dcon, *scon;
-	float	dquat[4], squat[4];
 	float dstweight;
 	int i;
 	
@@ -719,23 +720,34 @@
 			
 			/* Do the transformation blend */
 			if (schan->flag & POSE_ROT) {
-				QUATCOPY(dquat, dchan->quat);
-				QUATCOPY(squat, schan->quat);
-				if(mode==ACTSTRIPMODE_BLEND)
-					QuatInterpol(dchan->quat, dquat, squat, srcweight);
-				else {
-					QuatMulFac(squat, srcweight);
-					QuatMul(dchan->quat, dquat, squat);
+				/* quat interpolation done separate */
+				if (schan->rotmode == PCHAN_ROT_QUAT) {
+					float dquat[4], squat[4];
+					
+					QUATCOPY(dquat, dchan->quat);
+					QUATCOPY(squat, schan->quat);
+					if (mode==ACTSTRIPMODE_BLEND)
+						QuatInterpol(dchan->quat, dquat, squat, srcweight);
+					else {
+						QuatMulFac(squat, srcweight);
+						QuatMul(dchan->quat, dquat, squat);
+					}
+					
+					NormalQuat(dchan->quat);
 				}
-				
-				NormalQuat (dchan->quat);
 			}
 
-			for (i=0; i<3; i++){
+			for (i=0; i<3; i++) {
+				/* blending for loc and scale are pretty self-explanatory... */
 				if (schan->flag & POSE_LOC)
 					dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight);
 				if (schan->flag & POSE_SIZE)
 					dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight);
+				
+				/* euler-rotation interpolation done here instead... */
+				// FIXME: are these results decent?
+				if ((schan->flag & POSE_ROT) && (schan->rotmode))
+					dchan->eul[i] = (dchan->eul[i]*dstweight) + (schan->eul[i]*srcweight);
 			}
 			dchan->flag |= schan->flag;
 		}

Modified: branches/animsys2/source/blender/blenkernel/intern/armature.c
===================================================================
--- branches/animsys2/source/blender/blenkernel/intern/armature.c	2008-10-29 10:58:00 UTC (rev 17215)
+++ branches/animsys2/source/blender/blenkernel/intern/armature.c	2008-10-29 11:20:02 UTC (rev 17216)
@@ -1216,7 +1216,10 @@
 	if (pchan==NULL) return;
 	
 	/* get the inverse matrix of the pchan's transforms */
-	LocQuatSizeToMat4(pc_trans, pchan->loc, pchan->quat, pchan->size);
+	if (pchan->rotmode)
+		LocEulSizeToMat4(pc_trans, pchan->loc, pchan->eul, pchan->size);
+	else
+		LocQuatSizeToMat4(pc_trans, pchan->loc, pchan->quat, pchan->size);
 	Mat4Invert(inv_trans, pc_trans);
 	
 	/* Remove the pchan's transforms from it's pose_mat.
@@ -1967,22 +1970,29 @@
 	float rmat[3][3];
 	float tmat[3][3];
 	
+	/* get scaling matrix */
 	SizeToMat3(chan->size, smat);
 	
-	NormalQuat(chan->quat);
-
-	QuatToMat3(chan->quat, rmat);
+	/* rotations may either be quats or eulers (no rotation modes for now...) */
+	if (chan->rotmode) {
+		/* euler rotations (will cause gimble lock... no rotation order to solve that yet) */
+		EulToMat3(chan->eul, rmat);
+	}
+	else {
+		/* quats are normalised before use to eliminate scaling issues */
+		NormalQuat(chan->quat);
+		QuatToMat3(chan->quat, rmat);
+	}
 	
+	/* calculate matrix of bone (as 3x3 matrix, but then copy the 4x4) */
 	Mat3MulMat3(tmat, rmat, smat);
-	
 	Mat4CpyMat3(chan->chan_mat, tmat);
 	
 	/* prevent action channels breaking chains */
 	/* need to check for bone here, CONSTRAINT_TYPE_ACTION uses this call */
-	if (chan->bone==NULL || !(chan->bone->flag & BONE_CONNECTED)) {
+	if ((chan->bone==NULL) || !(chan->bone->flag & BONE_CONNECTED)) {
 		VECCOPY(chan->chan_mat[3], chan->loc);
 	}
-
 }
 
 /* transform from bone(b) to bone(b+1), store in chan_mat */

Modified: branches/animsys2/source/blender/blenkernel/intern/ipo.c
===================================================================
--- branches/animsys2/source/blender/blenkernel/intern/ipo.c	2008-10-29 10:58:00 UTC (rev 17215)
+++ branches/animsys2/source/blender/blenkernel/intern/ipo.c	2008-10-29 11:20:02 UTC (rev 17216)
@@ -103,8 +103,9 @@
 };
 
 int ac_ar[AC_TOTIPO]= {
-	AC_LOC_X, AC_LOC_Y, AC_LOC_Z,  
-	 AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z,
+	AC_LOC_X, AC_LOC_Y, AC_LOC_Z,
+	AC_EUL_X, AC_EUL_Y, AC_EUL_Z,
+	AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z,
 	AC_SIZE_X, AC_SIZE_Y, AC_SIZE_Z
 };
 
@@ -1158,7 +1159,7 @@
 		/* get pointers */
 		BezTriple *bezt, *prevbezt, *lastbezt;
 		float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac;
-		float cycdx, cycdy, ofs, cycyofs= 0.0;
+		float cycdx, cycdy, ofs, cycyofs= 0.0f;
 		int a, b;
 		
 		/* get pointers */
@@ -1468,12 +1469,17 @@
 	if (achan && achan->ipo && pchan) {
 		IpoCurve *icu;
 		
-		/* loop over IPO-curves, getting a pointer to pchan var to write to
-		 *	- assume for now that only 'float' channels will ever get written into
-		 */
+		/* loop over IPO-curves, getting a pointer to pchan var to write to */
 		for (icu= achan->ipo->curve.first; icu; icu= icu->next) {
 			void *poin= get_pchan_ipo_poin(pchan, icu->adrcode);
-			if (poin) write_ipo_poin(poin, IPO_FLOAT, icu->curval);
+			
+			if (poin) {
+				/* only euler-rotations are of type float-degree, all others are 'float' only */
+				if (ELEM3(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z))
+					write_ipo_poin(poin, IPO_FLOAT_DEGR, icu->curval);
+				else
+					write_ipo_poin(poin, IPO_FLOAT, icu->curval);
+			}
 		}
 	}
 }
@@ -1792,6 +1798,7 @@
 /* --------------------- Get Pointer API ----------------------------- */ 
 
 /* get pointer to pose-channel's channel, but set appropriate flags first */
+// TODO: most channels (except euler rots, which are float-degr) are floats, so do we need type arg?
 void *get_pchan_ipo_poin (bPoseChannel *pchan, int adrcode)
 {
 	void *poin= NULL;
@@ -1814,6 +1821,22 @@
 			pchan->flag |= POSE_ROT;
 			break;
 			
+		case AC_EUL_X:
+			poin= &(pchan->eul[0]);
+			pchan->flag |= POSE_ROT;
+			//type= IPO_FLOAT_DEGR;
+			break;
+		case AC_EUL_Y:
+			poin= &(pchan->eul[1]);
+			pchan->flag |= POSE_ROT;
+			//type= IPO_FLOAT_DEGR;
+			break;
+		case AC_EUL_Z:
+			poin= &(pchan->eul[2]);
+			pchan->flag |= POSE_ROT;
+			//type= IPO_FLOAT_DEGR;
+			break;
+			
 		case AC_LOC_X:
 			poin= &(pchan->loc[0]); 
 			pchan->flag |= POSE_LOC;

Modified: branches/animsys2/source/blender/include/BIF_keyframing.h
===================================================================
--- branches/animsys2/source/blender/include/BIF_keyframing.h	2008-10-29 10:58:00 UTC (rev 17215)
+++ branches/animsys2/source/blender/include/BIF_keyframing.h	2008-10-29 11:20:02 UTC (rev 17216)
@@ -58,8 +58,11 @@
 	INSERTKEY_FASTR		= (1<<3),	/* don't realloc mem (or increase count, as array has already been set out) */
 	INSERTKEY_REPLACE 	= (1<<4),	/* only replace an existing keyframe (this overrides INSERTKEY_NEEDED) */
 	
-		/* used by common_*key() functions */
+		/* used by common_*key() functions - Note: these are generally mutually exclusive (only one will work at a time) */
 	COMMONKEY_ADDMAP	= (1<<10),	/* common key: add texture-slot offset bitflag to adrcode before use */
+	COMMONKEY_PCHANROT	= (1<<11),	/* common key: extend channel list using relevant pchan-rotations */
+		/* all possible items for common_*key() functions */
+	COMMONKEY_MODES 	= (COMMONKEY_ADDMAP|COMMONKEY_PCHANROT)
 } eInsertKeyFlags;
 
 /* -------- */

Modified: branches/animsys2/source/blender/makesdna/DNA_action_types.h
===================================================================
--- branches/animsys2/source/blender/makesdna/DNA_action_types.h	2008-10-29 10:58:00 UTC (rev 17215)
+++ branches/animsys2/source/blender/makesdna/DNA_action_types.h	2008-10-29 11:20:02 UTC (rev 17216)
@@ -22,6 +22,7 @@
  *
  * Contributor(s): Original design: Reevan McKay
  * Contributor(s): Full recode, Ton Roosendaal, Crete 2005
+ * Contributor(s): Animation recode, Joshua Leung
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -70,9 +71,13 @@
 	void				*dual_quat;
 	void				*b_bone_dual_quats;
 	
-	float		loc[3];				/* written in by actions or transform */
+	float		loc[3];				/* transforms - written in by actions or transform */
 	float		size[3];
+	
+	float 		eul[3];				/* rotations - written in by actions or transform (but only euler/quat in use at any one time!) */
 	float		quat[4];
+	short 		rotmode;			/* for now either quat (0), or xyz-euler (1) */
+	short 		pad;
 	
 	float		chan_mat[4][4];		/* matrix result of loc/quat/size , and where we put deform in, see next line */
 	float		pose_mat[4][4];		/* constraints accumulate here. in the end, pose_mat = bone->arm_mat * chan_mat */
@@ -325,6 +330,13 @@
 	BONE_IK_NO_ZDOF_TEMP = (1<<12)
 } PCHAN_IKFLAG;
 
+/* PoseChannel->rotmode */
+typedef enum PCHAN_ROTMODE {
+		/* quaternion rotations (default, and for older Blender versions) */
+	PCHAN_ROT_QUAT	= 0,
+		/* euler rotations (xyz only) */
+	PCHAN_ROT_EUL,
+} PCHAN_ROTMODE;
 
 #endif
 

Modified: branches/animsys2/source/blender/makesdna/DNA_ipo_types.h
===================================================================
--- branches/animsys2/source/blender/makesdna/DNA_ipo_types.h	2008-10-29 10:58:00 UTC (rev 17215)
+++ branches/animsys2/source/blender/makesdna/DNA_ipo_types.h	2008-10-29 11:20:02 UTC (rev 17216)
@@ -349,8 +349,8 @@
 
 /* ******* PoseChannel (ID_PO) ********* */
 
-#define AC_TOTIPO	10
-#define AC_TOTNAM	10
+#define AC_TOTIPO	13
+#define AC_TOTNAM	13
 
 #define AC_LOC_X	1
 #define AC_LOC_Y	2
@@ -360,6 +360,10 @@
 #define AC_SIZE_Y	14
 #define AC_SIZE_Z	15
 
+#define AC_EUL_X	16
+#define AC_EUL_Y	17
+#define AC_EUL_Z	18
+
 #define AC_QUAT_W	25
 #define AC_QUAT_X	26
 #define AC_QUAT_Y	27
@@ -463,7 +467,6 @@
 #define IPO_CONST		0
 #define IPO_LIN			1
 #define IPO_BEZ			2
-	/* not used yet */
 #define IPO_MIXED		3 
 
 /* icu->extrap */

Modified: branches/animsys2/source/blender/src/drawview.c
===================================================================
--- branches/animsys2/source/blender/src/drawview.c	2008-10-29 10:58:00 UTC (rev 17215)
+++ branches/animsys2/source/blender/src/drawview.c	2008-10-29 11:20:02 UTC (rev 17216)

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list