From BlenderWiki

Jump to: navigation, search
Note: This is an archived version of the Blender Developer Wiki. The current and active wiki is available on wiki.blender.org.

Euler Rotation Orders

When defining rotations as 'eulers' (i.e. 3 rotational angles defined in terms of each other), different permutations of combining the rotations can be useful in different situations. The "classic" implementation in Blender uses the "XYZ" order.

For more details on this matter, see: http://en.wikipedia.org/wiki/Euler_angles

Overview of Proposed (New) System

The base code for this has been adapted from:

ANSI C code from the article
"Euler Angle Conversion"
by Ken Shoemake, shoemake@graphics.cis.upenn.edu
in "Graphics Gems IV", Academic Press, 1994

Notes about changes made to this code:

  • Only the 'static' frame rotations have been used, and repeating axes have been left out for now. These could be restored, but the original code will need to be referenced again to find the parts that have been left out of the adapted implementation.
  • A major departure from the original code is the way in which rotation orders are defined. It is much more convenient in our code to define an enum of the possible rotation orders, and use this enum to provide access-indices to an array containing static structs with the values that needed to be packed/un-packed from the ordinals used in Shoemake's code. The C-code used to provide the necessary mapping used to generate the adapted code is presented in a later section.
  • The matrices used in Shoemake's code have been transposed (compared to Blender's original matrices). The result was that naively copying Shoemake's code with the modifications above, will result in objects/bones rotating in a direction opposite to the original code (i.e. Blender originally rotates clockwise, but Shoemake's code is counter-clockwise)

Code used to provide mapping from Shoemake's code to Blender's code

/* Test code for Euler rotations with custom rotation order */

/* ---------------------------------------- */
/* Ken Shoemake code */

// ken defines these constants too
#define X 0
#define Y 1
#define Z 2


/*** Order type constants, constructors, extractors ***/
    /* There are 24 possible conventions, designated by:    */
    /*	  o EulAxI = axis used initially		    */
    /*	  o EulPar = parity of axis permutation		    */
    /* Axes I,J,K will be a permutation of X,Y,Z.	    */
    /* Axis H will be either I or K, depending on EulRep.   */
    /* Frame S takes axes from initial static frame.	    */
    /* If ord = (AxI=X, Par=Even, Rep=No, Frm=S), then	    */
    /* {a,b,c,ord} means Rz(c)Ry(b)Rx(a), where Rz(c)v	    */
    /* rotates v around Z by c radians.			    */
#define EulFrmS	     0
#define EulFrmR	     1
#define EulFrm(ord)  ((unsigned)(ord)&1)
#define EulRepNo     0
#define EulRepYes    1
#define EulRep(ord)  (((unsigned)(ord)>>1)&1)
#define EulParEven   0
#define EulParOdd    1
#define EulPar(ord)  (((unsigned)(ord)>>2)&1)
#define EulSafe	     "\000\001\002\000"
#define EulNext	     "\001\002\000\001"
#define EulAxI(ord)  ((int)(EulSafe[(((unsigned)(ord)>>3)&3)]))
#define EulAxJ(ord)  ((int)(EulNext[EulAxI(ord)+(EulPar(ord)==EulParOdd)]))
#define EulAxK(ord)  ((int)(EulNext[EulAxI(ord)+(EulPar(ord)!=EulParOdd)]))
#define EulAxH(ord)  ((EulRep(ord)==EulRepNo)?EulAxK(ord):EulAxI(ord))
    /* EulGetOrd unpacks all useful information about order simultaneously. */
#define EulGetOrd(ord,i,j,k,h,n,s,f) \
	{\
		unsigned o=ord;\
		f=o&1;o>>=1;\
		s=o&1;o>>=1;\
		n=o&1;o>>=1;\
		i=EulSafe[o&3];\
		j=EulNext[i+n];\
		k=EulNext[i+1-n];\
		h=s?k:i;\
	}
    /* EulOrd creates an order value between 0 and 23 from 4-tuple choices. */
#define EulOrd(i,p,r,f)	   (((((((i)<<1)+(p))<<1)+(r))<<1)+(f))
    /* Static axes */
#define EulOrdXYZ    EulOrd(X,EulParEven,EulRepNo,EulFrmS)
#define EulOrdXYX    EulOrd(X,EulParEven,EulRepYes,EulFrmS)
#define EulOrdXZY    EulOrd(X,EulParOdd,EulRepNo,EulFrmS)
#define EulOrdXZX    EulOrd(X,EulParOdd,EulRepYes,EulFrmS)
#define EulOrdYZX    EulOrd(Y,EulParEven,EulRepNo,EulFrmS)
#define EulOrdYZY    EulOrd(Y,EulParEven,EulRepYes,EulFrmS)
#define EulOrdYXZ    EulOrd(Y,EulParOdd,EulRepNo,EulFrmS)
#define EulOrdYXY    EulOrd(Y,EulParOdd,EulRepYes,EulFrmS)
#define EulOrdZXY    EulOrd(Z,EulParEven,EulRepNo,EulFrmS)
#define EulOrdZXZ    EulOrd(Z,EulParEven,EulRepYes,EulFrmS)
#define EulOrdZYX    EulOrd(Z,EulParOdd,EulRepNo,EulFrmS)
#define EulOrdZYZ    EulOrd(Z,EulParOdd,EulRepYes,EulFrmS)

/* ---------------------------------------- */

#include <stdio.h>

/* // Structure for euler orders we're trying to make...
typedef struct EulerOrderData {
	short i;	// first axis
	short j;	// second axis
	short k;	// third axis
	
	short h;	// ???
	
	short n;	// even/odd?
	short s;	// repeats?
	short f;	// rotating or static axes
} EulerOrderData; 

 */

/* macro to give a printout of each rotation order */
#define PrintEulOrders(A) \
	{\
		int i,j,k,h,n,s,f; \
		printf("%s - %d\n", #A, EulOrd##A); \
		EulGetOrd(EulOrd##A, i,j,k, h, n,s,f)\
		printf("\t{%d, %d, %d,  %d,  %d, %d, %d} // %s\n", i, j, k,  h,  n, s, f,  #A); \
	}

int main (int argv, char **argc)
{
	/* go through each type... */
	PrintEulOrders(XYZ)
	PrintEulOrders(XYX)  
	PrintEulOrders(XZX)  
	PrintEulOrders(YZX)  
	PrintEulOrders(YZY)    
	PrintEulOrders(YXZ)    
	PrintEulOrders(YXY)    
	PrintEulOrders(ZXY)   
	PrintEulOrders(ZXZ)   
	PrintEulOrders(ZYX)    
	PrintEulOrders(ZYZ)   
	
	/* done.. */
	return 0;
}

Usage of Rotation Orders

In BLI_arithb.h, a list of defines for the possible (implemented) rotation orders is given in the enum eEulerRotationOrders. These values should be supplied as the 'order' argument for the relevant calls when converting to/from eulers.

The defines in this enum should match those given in ePchan_RotMode (DNA_action_types.h), with the latter having a few extra options (Quaternions, Axis-Angle, etc.).

For compatability, most tools in Blender should still just use the default XYZ rotation order still when dealing with Eulers. Only tools dealing directly with Object/Bone rotations (bones in particular, at the time of writing) need care to take into account rotation orders of the said parts when performing operations.

The following tools/code are most affected:

  • Constraints -> especially Copy/Limit Rotation constraints...
  • Transform -> this is still a bit patchy now (for bones support)

Obviously, PoseChannels and Objects are going to be affected too. For the initial round of improvements though, only PoseChannels will be touched, to reduce the errors/breakage that occurs when too many things are touched at once.