Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2009-09-12 16:30:23 +0400
committerJoshua Leung <aligorith@gmail.com>2009-09-12 16:30:23 +0400
commitad43aaf881652a10a47a850277bfe3d376a82433 (patch)
tree9e3f721a567b6ef2bc473db204ce8fd6bfa39ec6
parent3a9d99e3e86a44ee7c9abf144c7b03fe246adc37 (diff)
2.5 - Rotation Locking for Bones
* Added Transform Locks panel. The layout for rotation I'm not satisfied with yet, though it is the best alternative so far. * Rotations can now be locked per-component for quats/axis-angle instead of going through eulers. This is currently enabled by the checkbox for the 'label' of the Lock Rotation column. - The naming of the property in RNA + the way this is presented in the UI can get some work done. - The setting for the 'w' component for quats/axis-angle is currently a separate flag in RNA, since I can't figure out how to lump this in under the 'lock_rotation' property instead (i.e. getting that to be either 3 or 4 components, depending on whether per-component locking is enabled). - Editing values directly should not be possible when these locks are set... * Fixed some tools which made use of this
-rw-r--r--release/ui/buttons_data_bone.py30
-rw-r--r--source/blender/editors/armature/editarmature.c80
-rw-r--r--source/blender/editors/armature/poseobject.c1
-rw-r--r--source/blender/editors/transform/transform.c123
-rw-r--r--source/blender/makesdna/DNA_object_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_pose.c17
6 files changed, 186 insertions, 67 deletions
diff --git a/release/ui/buttons_data_bone.py b/release/ui/buttons_data_bone.py
index 5aac44bbc94..a0121821e55 100644
--- a/release/ui/buttons_data_bone.py
+++ b/release/ui/buttons_data_bone.py
@@ -71,6 +71,35 @@ class BONE_PT_transform(BoneButtonsPanel):
col = layout.column(align=True)
col.itemL(text="Euler:")
col.row().itemR(pchan, "euler_rotation", text="")
+
+class BONE_PT_transform_locks(BoneButtonsPanel):
+ __label__ = "Transform Locks"
+
+ def poll(self, context):
+ return context.bone
+
+ def draw(self, context):
+ layout = self.layout
+
+ ob = context.object
+ bone = context.bone
+ pchan = ob.pose.pose_channels[context.bone.name]
+
+ row = layout.row()
+ col = row.column()
+ col.itemR(pchan, "lock_location")
+ col.active = not (bone.parent and bone.connected)
+
+ col = row.column()
+ if pchan.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'):
+ col.itemR(pchan, "lock_rotations_4d", text="Lock Rotation")
+ if pchan.lock_rotations_4d:
+ col.itemR(pchan, "lock_rotation_w", text="W")
+ col.itemR(pchan, "lock_rotation", text="")
+ else:
+ col.itemR(pchan, "lock_rotation", text="Rotation")
+
+ row.column().itemR(pchan, "lock_scale")
class BONE_PT_bone(BoneButtonsPanel):
__label__ = "Bone"
@@ -243,6 +272,7 @@ class BONE_PT_deform(BoneButtonsPanel):
bpy.types.register(BONE_PT_context_bone)
bpy.types.register(BONE_PT_transform)
+bpy.types.register(BONE_PT_transform_locks)
bpy.types.register(BONE_PT_bone)
bpy.types.register(BONE_PT_deform)
bpy.types.register(BONE_PT_inverse_kinematics)
diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c
index e2293b65878..7d196d23c98 100644
--- a/source/blender/editors/armature/editarmature.c
+++ b/source/blender/editors/armature/editarmature.c
@@ -4849,42 +4849,56 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op)
/* only clear those channels that are not locked */
CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) {
- if (pchan->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ)) {
- float eul[3], oldeul[3], quat1[4];
-
- if (pchan->rotmode == PCHAN_ROT_QUAT) {
- QUATCOPY(quat1, pchan->quat);
- QuatToEul(pchan->quat, oldeul);
- }
- else if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
- continue; // XXX
+ if (pchan->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) {
+ /* check if convert to eulers for locking... */
+ if (pchan->protectflag & OB_LOCK_ROT4D) {
+ /* perform clamping on a component by component basis */
+ if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
+ pchan->quat[0]= (pchan->rotmode == PCHAN_ROT_AXISANGLE) ? 0.0f : 1.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
+ pchan->quat[1]= 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
+ pchan->quat[2]= 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
+ pchan->quat[3]= 0.0f;
}
else {
- VECCOPY(oldeul, pchan->eul);
- }
-
- eul[0]= eul[1]= eul[2]= 0.0f;
-
- // TODO: for 4 channel rotations, we need special flags for those too...
- if (pchan->protectflag & OB_LOCK_ROTX)
- eul[0]= oldeul[0];
- if (pchan->protectflag & OB_LOCK_ROTY)
- eul[1]= oldeul[1];
- if (pchan->protectflag & OB_LOCK_ROTZ)
- eul[2]= oldeul[2];
-
- if (pchan->rotmode == PCHAN_ROT_QUAT) {
- EulToQuat(eul, pchan->quat);
- /* quaternions flip w sign to accumulate rotations correctly */
- if ((quat1[0]<0.0f && pchan->quat[0]>0.0f) || (quat1[0]>0.0f && pchan->quat[0]<0.0f)) {
- QuatMulf(pchan->quat, -1.0f);
+ /* perform clamping using euler form (3-components) */
+ float eul[3], oldeul[3], quat1[4];
+
+ if (pchan->rotmode == PCHAN_ROT_QUAT) {
+ QUATCOPY(quat1, pchan->quat);
+ QuatToEul(pchan->quat, oldeul);
+ }
+ else if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
+ AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], oldeul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ VECCOPY(oldeul, pchan->eul);
+ }
+
+ eul[0]= eul[1]= eul[2]= 0.0f;
+
+ if (pchan->protectflag & OB_LOCK_ROTX)
+ eul[0]= oldeul[0];
+ if (pchan->protectflag & OB_LOCK_ROTY)
+ eul[1]= oldeul[1];
+ if (pchan->protectflag & OB_LOCK_ROTZ)
+ eul[2]= oldeul[2];
+
+ if (pchan->rotmode == PCHAN_ROT_QUAT) {
+ EulToQuat(eul, pchan->quat);
+ /* quaternions flip w sign to accumulate rotations correctly */
+ if ((quat1[0]<0.0f && pchan->quat[0]>0.0f) || (quat1[0]>0.0f && pchan->quat[0]<0.0f)) {
+ QuatMulf(pchan->quat, -1.0f);
+ }
+ }
+ else if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
+ AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], oldeul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ VECCOPY(pchan->eul, eul);
}
- }
- else if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
- // TODO...
- }
- else {
- VECCOPY(pchan->eul, eul);
}
}
else {
diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c
index b473b9ee226..7d7f54309a8 100644
--- a/source/blender/editors/armature/poseobject.c
+++ b/source/blender/editors/armature/poseobject.c
@@ -998,7 +998,6 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
pchan->flag= chan->flag;
/* check if rotation modes are compatible (i.e. do they need any conversions) */
- // FIXME: add axis-angle here too...
if (pchan->rotmode == chan->rotmode) {
/* copy the type of rotation in use */
if (pchan->rotmode > 0) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 467f5c59e3d..e877f1fecae 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1610,29 +1610,88 @@ static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
eul[2]= oldeul[2];
}
-static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
+
+/* this function only does the delta rotation */
+/* axis-angle is usually internally stored as quats... */
+static void protectedAxisAngleBits(short protectflag, float *quat, float *oldquat)
{
- /* quaternions get limited with euler... */
- /* this function only does the delta rotation */
+ /* check that protection flags are set */
+ if ((protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) == 0)
+ return;
- // FIXME: need special checks for quality here...
- if(protectflag) {
+ if (protectflag & OB_LOCK_ROT4D) {
+ /* axis-angle getting limited as 4D entities that they are... */
+ if (protectflag & OB_LOCK_ROTW)
+ quat[0]= oldquat[0];
+ if (protectflag & OB_LOCK_ROTX)
+ quat[1]= oldquat[1];
+ if (protectflag & OB_LOCK_ROTY)
+ quat[2]= oldquat[2];
+ if (protectflag & OB_LOCK_ROTZ)
+ quat[3]= oldquat[3];
+ }
+ else {
+ /* axis-angle get limited with euler... */
float eul[3], oldeul[3], quat1[4];
+
+ QUATCOPY(quat1, quat);
+ AxisAngleToEulO(quat+1, quat[0], eul, EULER_ORDER_DEFAULT);
+ AxisAngleToEulO(oldquat+1, oldquat[0], oldeul, EULER_ORDER_DEFAULT);
+
+ if (protectflag & OB_LOCK_ROTX)
+ eul[0]= oldeul[0];
+ if (protectflag & OB_LOCK_ROTY)
+ eul[1]= oldeul[1];
+ if (protectflag & OB_LOCK_ROTZ)
+ eul[2]= oldeul[2];
+
+ EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, quat+1, quat);
+
+ /* 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;
+ }
+ }
+}
+/* this function only does the delta rotation */
+static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
+{
+ /* check that protection flags are set */
+ if ((protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) == 0)
+ return;
+
+ if (protectflag & OB_LOCK_ROT4D) {
+ /* quaternions getting limited as 4D entities that they are... */
+ if (protectflag & OB_LOCK_ROTW)
+ quat[0]= oldquat[0];
+ if (protectflag & OB_LOCK_ROTX)
+ quat[1]= oldquat[1];
+ if (protectflag & OB_LOCK_ROTY)
+ quat[2]= oldquat[2];
+ if (protectflag & OB_LOCK_ROTZ)
+ quat[3]= oldquat[3];
+ }
+ else {
+ /* quaternions get limited with euler... (compatability mode) */
+ float eul[3], oldeul[3], quat1[4];
+
QUATCOPY(quat1, quat);
QuatToEul(quat, eul);
QuatToEul(oldquat, oldeul);
-
- if(protectflag & OB_LOCK_ROTX)
+
+ if (protectflag & OB_LOCK_ROTX)
eul[0]= oldeul[0];
- if(protectflag & OB_LOCK_ROTY)
+ if (protectflag & OB_LOCK_ROTY)
eul[1]= oldeul[1];
- if(protectflag & OB_LOCK_ROTZ)
+ if (protectflag & OB_LOCK_ROTZ)
eul[2]= oldeul[2];
-
+
EulToQuat(eul, quat);
+
/* quaternions flip w sign to accumulate rotations correctly */
- if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
+ if ( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
QuatMulf(quat, -1.0f);
}
}
@@ -1733,17 +1792,24 @@ static void constraintRotLim(TransInfo *t, TransData *td)
else
return;
}
- else if (td->tdi) {
+ else if (td->tdi) { // XXX depreceated
/* ipo-keys eulers */
TransDataIpokey *tdi= td->tdi;
float eul[3];
-
+
eul[0]= tdi->rotx[0];
eul[1]= tdi->roty[0];
eul[2]= tdi->rotz[0];
-
+
EulOToMat4(eul, td->rotOrder, cob.matrix);
}
+ else if (td->rotOrder == PCHAN_ROT_AXISANGLE) {
+ /* axis angle */
+ if (td->ext)
+ AxisAngleToMat4(&td->ext->quat[1], td->ext->quat[0], cob.matrix);
+ else
+ return;
+ }
else {
/* eulers */
if (td->ext)
@@ -1751,22 +1817,22 @@ static void constraintRotLim(TransInfo *t, TransData *td)
else
return;
}
-
+
/* Evaluate valid constraints */
for (con= td->con; con; con= con->next) {
/* only consider constraint if enabled */
if (con->flag & CONSTRAINT_DISABLE) continue;
if (con->enforce == 0.0f) continue;
-
+
/* we're only interested in Limit-Rotation constraints */
if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
bRotLimitConstraint *data= con->data;
float tmat[4][4];
-
+
/* only use it if it's tagged for this purpose */
if ((data->flag2 & LIMIT_TRANSFORM)==0)
continue;
-
+
/* do space conversions */
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
/* just multiply by td->mtx (this should be ok) */
@@ -1777,10 +1843,10 @@ static void constraintRotLim(TransInfo *t, TransData *td)
/* skip... incompatable spacetype */
continue;
}
-
+
/* do constraint */
cti->evaluate_constraint(con, &cob, NULL);
-
+
/* convert spaces again */
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
/* just multiply by td->mtx (this should be ok) */
@@ -1789,7 +1855,7 @@ static void constraintRotLim(TransInfo *t, TransData *td)
}
}
}
-
+
/* copy results from cob->matrix */
if (td->flag & TD_USEQUAT) {
/* quats */
@@ -1799,13 +1865,17 @@ static void constraintRotLim(TransInfo *t, TransData *td)
/* ipo-keys eulers */
TransDataIpokey *tdi= td->tdi;
float eul[3];
-
+
Mat4ToEulO(cob.matrix, eul, td->rotOrder);
-
+
tdi->rotx[0]= eul[0];
tdi->roty[0]= eul[1];
tdi->rotz[0]= eul[2];
}
+ else if (td->rotOrder == PCHAN_ROT_AXISANGLE) {
+ /* axis angle */
+ Mat4ToAxisAngle(cob.matrix, &td->ext->quat[1], &td->ext->quat[0]);
+ }
else {
/* eulers */
Mat4ToEulO(cob.matrix, td->ext->rot, td->rotOrder);
@@ -2688,12 +2758,11 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
QuatMul(td->ext->quat, quat, iquat);
/* make temp copy (since stored in same place) */
- QuatCopy(quat, td->ext->quat); // this is just a 4d vector copying function
+ QUATCOPY(quat, td->ext->quat); // this is just a 4d vector copying macro
QuatToAxisAngle(quat, &td->ext->quat[1], &td->ext->quat[0]);
/* this function works on end result */
- // TODO: we really need a specialised version of this for axis-angle that doesn't try to do quats...
- protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
+ protectedAxisAngleBits(td->protectflag, td->ext->quat, td->ext->iquat);
}
else {
float eulmat[3][3];
@@ -2714,7 +2783,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
protectedRotateBits(td->protectflag, eul, td->ext->irot);
VECCOPY(td->ext->rot, eul);
}
-
+
constraintRotLim(t, td);
}
}
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index d1e70c16408..a89f8e1fb2e 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -515,6 +515,8 @@ extern Object workob;
#define OB_LOCK_SCALEY 128
#define OB_LOCK_SCALEZ 256
#define OB_LOCK_SCALE 448
+#define OB_LOCK_ROTW 512
+#define OB_LOCK_ROT4D 1024
/* ob->mode */
typedef enum ObjectMode {
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index d143c94ebb1..3a03e7a624d 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -698,14 +698,19 @@ 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 (with three components) in the interface.");
+ RNA_def_property_ui_text(prop, "Lock Rotation", "Lock editing of rotation 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");
+ // XXX this is sub-optimal - it really should be included above, but due to technical reasons we can't do this!
+ prop= RNA_def_property(srna, "lock_rotation_w", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_ROTW);
+ RNA_def_property_ui_text(prop, "Lock Rotation (4D Angle)", "Lock editing of 'angle' component of four-component rotations in the interface.");
+ RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update");
+ // XXX this needs a better name
+ prop= RNA_def_property(srna, "lock_rotations_4d", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_ROT4D);
+ RNA_def_property_ui_text(prop, "Lock Rotations (4D)", "Lock editing of four component rotations by components (instead of as Eulers).");
+ 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);