diff options
author | Joshua Leung <aligorith@gmail.com> | 2009-09-28 14:19:20 +0400 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2009-09-28 14:19:20 +0400 |
commit | 7d2fd5449e21b533f9aeb6f5f79af5e2396a8063 (patch) | |
tree | d146b4680f3123a112238bffb875fd632b1e4931 /source/blender/blenkernel | |
parent | 981afef08e051d00e955526c1c79b8dd01d4bdd5 (diff) |
Durian Feature Request: Rotation Modes for Objects
This (biggish) commit generalises the rotation modes functionality added for Bones, allowing Objects to use the various Euler Rotation orders, Axis-Angle, and Quaternion rotation representations.
I've also cleaned up the nomenclature of the rotation-related settings so that the naming styles are more consistent with each other. Unfortunately, this will break all files involving object or bone rotation animation made in 2.5 versions (2.4x will still get correctly converted).
General Notes:
* By default, Objects still default to using Eulers, while Bones will use Quaternions by default still.
* I've fixed all areas that I'm currently aware of to work with these changes. However, there are probably a few places where I've missed a few changes (i.e. auto-keyframing will need attention later).
* Removed the old "IPO-Keys" stuff from Transform code. I'm unlikely to restore this in the near future, and trying to fix that to include support for this commit would have been too much work.
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_armature.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 61 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/ipo.c | 28 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 50 |
5 files changed, 114 insertions, 30 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 8dbd2721fb9..e5d0c4274b3 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -103,6 +103,9 @@ void armature_mat_pose_to_bone(struct bPoseChannel *pchan, float inmat[][4], flo void armature_loc_pose_to_bone(struct bPoseChannel *pchan, float *inloc, float *outloc); void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]); +/* Rotation Mode Conversions - Used for PoseChannels + Objects... */ +void BKE_rotMode_change_values(float quat[4], float eul[3], short oldMode, short newMode); + /* B-Bone support */ typedef struct Mat4 { float mat[4][4]; diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index b2368451414..6220835a620 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1279,6 +1279,65 @@ void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float Mat4MulMat4(delta_mat, pose_mat, imat); } +/* **************** Rotation Mode Conversions ****************************** */ +/* Used for Objects and Pose Channels, since both can have multiple rotation representations */ + +/* Called from RNA when rotation mode changes + * - the result should be that the rotations given in the provided pointers have had conversions + * applied (as appropriate), such that the rotation of the element hasn't 'visually' changed + * + * - as in SDNA data, quat is used to store quaternions AND axis-angle rotations... + */ +void BKE_rotMode_change_values (float quat[4], float eul[3], short oldMode, short newMode) +{ + /* check if any change - if so, need to convert data */ + if (newMode > 0) { /* to euler */ + if (oldMode == ROT_MODE_AXISANGLE) { + /* axis-angle to euler */ + AxisAngleToEulO(&quat[1], quat[0], eul, newMode); + } + else if (oldMode == ROT_MODE_QUAT) { + /* quat to euler */ + QuatToEulO(quat, eul, newMode); + } + /* else { no conversion needed } */ + } + else if (newMode == ROT_MODE_QUAT) { /* to quat */ + if (oldMode == ROT_MODE_AXISANGLE) { + /* axis angle to quat */ + float q[4]; + + /* copy to temp var first, since quats and axis-angle are stored in same place */ + QuatCopy(q, quat); + AxisAngleToQuat(q, &quat[1], quat[0]); + } + else if (oldMode > 0) { + /* euler to quat */ + EulOToQuat(eul, oldMode, quat); + } + /* else { no conversion needed } */ + } + else { /* to axis-angle */ + if (oldMode > 0) { + /* euler to axis angle */ + EulOToAxisAngle(eul, oldMode, &quat[1], &quat[0]); + } + else if (oldMode == ROT_MODE_QUAT) { + /* quat to axis angle */ + float q[4]; + + /* copy to temp var first, since quats and axis-angle are stored in same place */ + QuatCopy(q, quat); + QuatToAxisAngle(q, &quat[1], &quat[0]); + } + + /* when converting to axis-angle, we need a special exception for the case when there is no axis */ + if (IS_EQ(quat[1], quat[2]) && IS_EQ(quat[2], quat[3])) { + /* for now, rotate around y-axis then (so that it simply becomes the roll) */ + quat[2]= 1.0f; + } + } +} /* **************** The new & simple (but OK!) armature evaluation ********* */ @@ -1591,7 +1650,7 @@ void chan_calc_mat(bPoseChannel *chan) /* euler rotations (will cause gimble lock, but this can be alleviated a bit with rotation orders) */ EulOToMat3(chan->eul, chan->rotmode, rmat); } - else if (chan->rotmode == PCHAN_ROT_AXISANGLE) { + else if (chan->rotmode == ROT_MODE_AXISANGLE) { /* axis-angle - stored in quaternion data, but not really that great for 3D-changing orientations */ AxisAngleToMat3(&chan->quat[1], chan->quat[0], rmat); } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 4de6b53d26a..8846fe77809 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -692,9 +692,11 @@ static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstrain }\ else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { \ ct->type = CONSTRAINT_OBTYPE_VERT; \ + ct->rotOrder = EULER_ORDER_DEFAULT; \ } \ else {\ ct->type = CONSTRAINT_OBTYPE_OBJECT; \ + ct->rotOrder= ct->tar->rotmode; \ } \ } \ \ diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index dd7904b4782..811a2658ae3 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -213,17 +213,17 @@ static char *ob_adrcodes_to_paths (int adrcode, int *array_index) *array_index= 2; return "delta_location"; case OB_ROT_X: - *array_index= 0; return "rotation"; + *array_index= 0; return "rotation_euler"; case OB_ROT_Y: - *array_index= 1; return "rotation"; + *array_index= 1; return "rotation_euler"; case OB_ROT_Z: - *array_index= 2; return "rotation"; + *array_index= 2; return "rotation_euler"; case OB_DROT_X: - *array_index= 0; return "delta_rotation"; + *array_index= 0; return "delta_rotation_euler"; case OB_DROT_Y: - *array_index= 1; return "delta_rotation"; + *array_index= 1; return "delta_rotation_euler"; case OB_DROT_Z: - *array_index= 2; return "delta_rotation"; + *array_index= 2; return "delta_rotation_euler"; case OB_SIZE_X: *array_index= 0; return "scale"; @@ -281,23 +281,23 @@ static char *pchan_adrcodes_to_paths (int adrcode, int *array_index) /* result depends on adrcode */ switch (adrcode) { case AC_QUAT_W: - *array_index= 0; return "rotation"; + *array_index= 0; return "rotation_quaternion"; case AC_QUAT_X: - *array_index= 1; return "rotation"; + *array_index= 1; return "rotation_quaternion"; case AC_QUAT_Y: - *array_index= 2; return "rotation"; + *array_index= 2; return "rotation_quaternion"; case AC_QUAT_Z: - *array_index= 3; return "rotation"; + *array_index= 3; return "rotation_quaternion"; case AC_EUL_X: - *array_index= 0; return "euler_rotation"; + *array_index= 0; return "rotation_euler"; case AC_EUL_Y: - *array_index= 1; return "euler_rotation"; + *array_index= 1; return "rotation_euler"; case AC_EUL_Z: - *array_index= 2; return "euler_rotation"; + *array_index= 2; return "rotation_euler"; case -1: /* special case for euler-rotations used by old drivers */ - *array_index= 0; return "euler_rotation"; + *array_index= 0; return "rotation_euler"; case AC_LOC_X: *array_index= 0; return "location"; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index c98e2d5970b..7e2ec106062 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -127,8 +127,8 @@ void clear_workob(Object *workob) { memset(workob, 0, sizeof(Object)); - workob->size[0]= workob->size[1]= workob->size[2]= 1.0; - + workob->size[0]= workob->size[1]= workob->size[2]= 1.0f; + workob->rotmode= ROT_MODE_EUL; } void copy_baseflags(struct Scene *scene) @@ -1038,6 +1038,11 @@ Object *add_object(struct Scene *scene, int type) ob->data= add_obdata_from_type(type); ob->lay= scene->lay; + + /* objects should default to having Euler XYZ rotations, + * but rotations default to quaternions + */ + ob->rotmode= ROT_MODE_EUL; base= scene_add_base(scene, ob); scene_select_base(scene, base); @@ -1582,12 +1587,34 @@ void object_scale_to_mat3(Object *ob, float mat[][3]) // TODO: this should take rotation orders into account later... void object_rot_to_mat3(Object *ob, float mat[][3]) { - float vec[3]; + float rmat[3][3], dmat[3][3]; + + /* initialise the delta-rotation matrix, which will get (pre)multiplied + * with the rotation matrix to yield the appropriate rotation + */ + Mat3One(dmat); + + /* rotations may either be quats, eulers (with various rotation orders), or axis-angle */ + if (ob->rotmode > 0) { + /* euler rotations (will cause gimble lock, but this can be alleviated a bit with rotation orders) */ + EulOToMat3(ob->rot, ob->rotmode, rmat); + EulOToMat3(ob->drot, ob->rotmode, dmat); + } + else if (ob->rotmode == ROT_MODE_AXISANGLE) { + /* axis-angle - stored in quaternion data, but not really that great for 3D-changing orientations */ + AxisAngleToMat3(&ob->quat[1], ob->quat[0], rmat); + AxisAngleToMat3(&ob->dquat[1], ob->dquat[0], dmat); + } + else { + /* quats are normalised before use to eliminate scaling issues */ + NormalQuat(ob->quat); + QuatToMat3(ob->quat, rmat); + QuatToMat3(ob->dquat, dmat); + } - vec[0]= ob->rot[0]+ob->drot[0]; - vec[1]= ob->rot[1]+ob->drot[1]; - vec[2]= ob->rot[2]+ob->drot[2]; - EulToMat3(vec, mat); + /* combine these rotations */ + // XXX is this correct? if errors, change the order of multiplication... + Mat3MulMat3(mat, dmat, rmat); } void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ @@ -1600,14 +1627,7 @@ void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ object_scale_to_mat3(ob, smat); /* rot */ - /* Quats arnt used yet */ - /*if(ob->transflag & OB_QUAT) { - QuatMul(q1, ob->quat, ob->dquat); - QuatToMat3(q1, rmat); - } - else {*/ - object_rot_to_mat3(ob, rmat); - /*}*/ + object_rot_to_mat3(ob, rmat); Mat3MulMat3(mat, rmat, smat); } |