2.5 Rotations: As a experiment, enabling Axis-Angle for Bones
The support for this is really quite hacky, and I might disable this later if we cannot get some parts to work nicely. Some notes: * This is currently stored in the same variable that quaternions are stored in, since they both have 4 components. However, in RNA, I've added 2 properties specially for this. * There are some shearing issues using certain axes - i.e. (1,1,0) - that will need to be checked on. * Transform code is really quite temporary for this. Just a quick demo of what can be done...
This commit is contained in:
@@ -58,6 +58,10 @@ class BONE_PT_transform(BoneButtonsPanel):
|
||||
col = row.column()
|
||||
if pchan.rotation_mode == 'QUATERNION':
|
||||
col.itemR(pchan, "rotation", text="Rotation")
|
||||
elif pchan.rotation_mode == 'AXIS_ANGLE':
|
||||
col.itemL(text="Rotation")
|
||||
col.itemR(pchan, "rotation_angle", text="Angle")
|
||||
col.itemR(pchan, "rotation_axis", text="Axis")
|
||||
else:
|
||||
col.itemR(pchan, "euler_rotation", text="Rotation")
|
||||
|
||||
|
||||
@@ -1986,11 +1986,15 @@ void chan_calc_mat(bPoseChannel *chan)
|
||||
/* get scaling matrix */
|
||||
SizeToMat3(chan->size, smat);
|
||||
|
||||
/* rotations may either be quats or eulers (no rotation modes for now...) */
|
||||
/* rotations may either be quats, eulers (with various rotation orders), or axis-angle */
|
||||
if (chan->rotmode > 0) {
|
||||
/* euler rotations (will cause gimble lock... no rotation order to solve that yet) */
|
||||
/* 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) {
|
||||
/* axis-angle - stored in quaternion data, but not really that great for 3D-changing orientations */
|
||||
VecRotToMat3(&chan->quat[1], chan->quat[0], rmat);
|
||||
}
|
||||
else {
|
||||
/* quats are normalised before use to eliminate scaling issues */
|
||||
NormalQuat(chan->quat);
|
||||
|
||||
@@ -2663,7 +2663,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
|
||||
|
||||
/* rotation */
|
||||
if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
|
||||
/* euler or quaternion? */
|
||||
/* euler or quaternion/axis-angle? */
|
||||
if (td->flag & TD_USEQUAT) {
|
||||
Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
|
||||
|
||||
@@ -2672,6 +2672,15 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
|
||||
QuatMul(td->ext->quat, quat, td->ext->iquat);
|
||||
/* this function works on end result */
|
||||
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
|
||||
|
||||
/* if axis-angle, we now convert the quat representation to axis-angle again
|
||||
* - this means that the math above is not totally correct, but it works well enough so far...
|
||||
*/
|
||||
if (td->rotOrder == PCHAN_ROT_AXISANGLE) {
|
||||
/* make temp copy (since stored in same place) */
|
||||
QuatCopy(quat, td->ext->quat);
|
||||
QuatToAxisAngle(quat, &td->ext->quat[1], &td->ext->quat[0]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
float eulmat[3][3];
|
||||
|
||||
@@ -552,8 +552,9 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
|
||||
|
||||
td->ob = ob;
|
||||
td->flag = TD_SELECTED;
|
||||
if (pchan->rotmode == PCHAN_ROT_QUAT)
|
||||
if ((pchan->rotmode == PCHAN_ROT_QUAT) || (pchan->rotmode == PCHAN_ROT_AXISANGLE))
|
||||
{
|
||||
// XXX: for now, axis-angle will be treated like for quats (the only difference is the normalisation)
|
||||
td->flag |= TD_USEQUAT;
|
||||
}
|
||||
if (bone->flag & BONE_HINGE_CHILD_TRANSFORM)
|
||||
@@ -587,6 +588,7 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
|
||||
td->ext->quat= pchan->quat;
|
||||
|
||||
QUATCOPY(td->ext->iquat, pchan->quat);
|
||||
td->rotOrder= pchan->rotmode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -110,26 +110,64 @@ IDProperty *rna_PoseChannel_idproperties(PointerRNA *ptr, int create)
|
||||
return pchan->prop;
|
||||
}
|
||||
|
||||
/* rotation - euler angles */
|
||||
static void rna_PoseChannel_euler_rotation_get(PointerRNA *ptr, float *value)
|
||||
{
|
||||
bPoseChannel *pchan= ptr->data;
|
||||
|
||||
if(pchan->rotmode == PCHAN_ROT_QUAT)
|
||||
|
||||
if(pchan->rotmode == PCHAN_ROT_AXISANGLE) {
|
||||
float m[3][3];
|
||||
|
||||
/* go through a 3x3 matrix */
|
||||
VecRotToMat3(&pchan->quat[1], pchan->quat[0], m);
|
||||
Mat3ToEul(m, value);
|
||||
}
|
||||
else if(pchan->rotmode == PCHAN_ROT_QUAT) /* default XYZ eulers when using axis-angle... */
|
||||
QuatToEul(pchan->quat, value);
|
||||
else
|
||||
VECCOPY(value, pchan->eul);
|
||||
}
|
||||
|
||||
/* rotation - euler angles */
|
||||
static void rna_PoseChannel_euler_rotation_set(PointerRNA *ptr, const float *value)
|
||||
{
|
||||
bPoseChannel *pchan= ptr->data;
|
||||
|
||||
if(pchan->rotmode == PCHAN_ROT_QUAT) /* default XYZ eulers when using quats... */
|
||||
|
||||
if(pchan->rotmode == PCHAN_ROT_AXISANGLE) { /* default XYZ eulers when using axis-angle... */
|
||||
float q[4];
|
||||
|
||||
/* convert to temp quat, then to axis angle (since stored in same var) */
|
||||
EulToQuat((float *)value, q);
|
||||
QuatToAxisAngle(q, &pchan->quat[1], &pchan->quat[0]);
|
||||
}
|
||||
else if(pchan->rotmode == PCHAN_ROT_QUAT) /* default XYZ eulers when using quats... */
|
||||
EulToQuat((float*)value, pchan->quat);
|
||||
else
|
||||
VECCOPY(pchan->eul, value);
|
||||
}
|
||||
|
||||
/* rotation - axis angle only */
|
||||
static void rna_PoseChannel_rotation_axis_get(PointerRNA *ptr, float *value)
|
||||
{
|
||||
bPoseChannel *pchan= ptr->data;
|
||||
|
||||
if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
|
||||
/* axis is stord in quat for now */
|
||||
VecCopyf(value, &pchan->quat[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* rotation - axis angle only */
|
||||
static void rna_PoseChannel_rotation_axis_set(PointerRNA *ptr, const float *value)
|
||||
{
|
||||
bPoseChannel *pchan= ptr->data;
|
||||
|
||||
if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
|
||||
/* axis is stored in quat for now */
|
||||
VecCopyf(&pchan->quat[1], (float *)value);
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_PoseChannel_rotation_mode_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
bPoseChannel *pchan= ptr->data;
|
||||
@@ -185,6 +223,12 @@ static void rna_PoseChannel_rotation_mode_set(PointerRNA *ptr, int value)
|
||||
QuatCopy(q, pchan->quat);
|
||||
QuatToAxisAngle(q, &pchan->quat[1], &pchan->quat[0]);
|
||||
}
|
||||
|
||||
/* when converting to axis-angle, we need a special exception for the case when there is no axis */
|
||||
if (IS_EQ(pchan->quat[1], pchan->quat[2]) && IS_EQ(pchan->quat[2], pchan->quat[3])) {
|
||||
/* for now, rotate around y-axis then (so that it simply becomes the roll) */
|
||||
pchan->quat[2]= 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* finally, set the new rotation type */
|
||||
@@ -421,7 +465,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
|
||||
{PCHAN_ROT_YZX, "YZX", 0, "YZX Euler", "YZX Rotation Order. Prone to Gimbal Lock"},
|
||||
{PCHAN_ROT_ZXY, "ZXY", 0, "ZXY Euler", "ZXY Rotation Order. Prone to Gimbal Lock"},
|
||||
{PCHAN_ROT_ZYX, "ZYX", 0, "ZYX Euler", "ZYX Rotation Order. Prone to Gimbal Lock"},
|
||||
//{PCHAN_ROT_AXISANGLE, "AXIS_ANGLE", 0, "Axis Angle", "Axis Angle (W+XYZ). Defines a rotation around some axis defined by 3D-Vector."},
|
||||
{PCHAN_ROT_AXISANGLE, "AXIS_ANGLE", 0, "Axis Angle", "Axis Angle (W+XYZ). Defines a rotation around some axis defined by 3D-Vector."},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
StructRNA *srna;
|
||||
@@ -493,6 +537,18 @@ static void rna_def_pose_channel(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Rotation", "Rotation in Quaternions.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Pose_update");
|
||||
|
||||
prop= RNA_def_property(srna, "rotation_angle", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "quat[0]");
|
||||
RNA_def_property_ui_text(prop, "Rotation Angle", "Angle of Rotation for Axis-Angle rotation representation.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Pose_update");
|
||||
|
||||
prop= RNA_def_property(srna, "rotation_axis", PROP_FLOAT, PROP_XYZ);
|
||||
RNA_def_property_float_sdna(prop, NULL, "quat");
|
||||
RNA_def_property_float_funcs(prop, "rna_PoseChannel_rotation_axis_get", "rna_PoseChannel_rotation_axis_set", NULL);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Rotation Axis", "Axis for Axis-Angle rotation representation.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Pose_update");
|
||||
|
||||
prop= RNA_def_property(srna, "euler_rotation", PROP_FLOAT, PROP_EULER);
|
||||
RNA_def_property_float_sdna(prop, NULL, "eul");
|
||||
RNA_def_property_float_funcs(prop, "rna_PoseChannel_euler_rotation_get", "rna_PoseChannel_euler_rotation_set", NULL);
|
||||
@@ -662,8 +718,14 @@ static void rna_def_pose_channel(BlenderRNA *brna)
|
||||
prop= RNA_def_property(srna, "lock_rotation", PROP_BOOLEAN, PROP_XYZ);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_ROTX);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Lock Rotation", "Lock editing of rotation in the interface.");
|
||||
RNA_def_property_ui_text(prop, "Lock Rotation", "Lock editing of rotation (with three components) in the interface.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update");
|
||||
|
||||
//prop= RNA_def_property(srna, "lock_rotation_4d", PROP_BOOLEAN, PROP_XYZ);
|
||||
//RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_ROTW);
|
||||
//RNA_def_property_array(prop, 4);
|
||||
//RNA_def_property_ui_text(prop, "Lock Rotation (4D)", "Lock editing of rotations (with four components) in the interface.");
|
||||
//RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update");
|
||||
|
||||
prop= RNA_def_property(srna, "lock_scale", PROP_BOOLEAN, PROP_XYZ);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_SCALEX);
|
||||
|
||||
@@ -281,7 +281,7 @@ void WM_read_file(bContext *C, char *name, ReportList *reports)
|
||||
|
||||
|
||||
/* called on startup, (context entirely filled with NULLs) */
|
||||
/* or called for 'Erase All' */
|
||||
/* or called for 'New File' */
|
||||
/* op can be NULL */
|
||||
int WM_read_homefile(bContext *C, wmOperator *op)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user