iTaSC: Selection of constrained axis for CopyPose constraint
authorBenoit Bolsee <benoit.bolsee@online.be>
Wed, 14 Oct 2009 18:51:00 +0000 (18:51 +0000)
committerBenoit Bolsee <benoit.bolsee@online.be>
Wed, 14 Oct 2009 18:51:00 +0000 (18:51 +0000)
This commit implements more of the CopyPose capabilities in
Blender. It is now possible to select which axis will be
constrained in position and orientation to obtain
interesting effects. Another option selects if the axis
are relative to the end effector or to the target.

Unlocking a position axis means that the coordinate along
this axis is not constrained and can take any value.
Unlocking the Y axis of the End Effector produces an
'aiming' effect: the end effector is oriented towards
the target but without stretching.

Unlocking a rotation axis means that the end effector can
freely rotation along that axis. Unlocking the Y axis
produces a 'tangent' effect: the end effector aligns with
the Y axis of the target but can rotate along that axis.

A 'floor' effect is possible if the position Z axis of the
target is unlocked. More effects are possible an can be
combined.

release/scripts/ui/buttons_object_constraint.py
source/blender/ikplugin/intern/itasc_plugin.cpp
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesrna/intern/rna_constraint.c

index 6be166e8af0158230c41b9bd57b2751af09bf4ba..63fe27f2e4b5b50da573ad494e7f9e6308062b23 100644 (file)
@@ -50,6 +50,7 @@ class ConstraintButtonsPanel(bpy.types.Panel):
                                layout.item_pointerR(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
 
        def ik_template(self, layout, con):
+               # only used for iTaSC
                layout.itemR(con, "pole_target")
        
                if con.pole_target and con.pole_target.type == 'ARMATURE':
@@ -60,14 +61,14 @@ class ConstraintButtonsPanel(bpy.types.Panel):
                        row.itemL()
                        row.itemR(con, "pole_angle")
                
-               split = layout.split()
+               split = layout.split(percentage=0.33)
                col = split.column()
                col.itemR(con, "tail")
                col.itemR(con, "stretch")
 
                col = split.column()
-               col.itemR(con, "iterations")
                col.itemR(con, "chain_length")
+               col.itemR(con, "targetless")
 
        def CHILD_OF(self, context, layout, con):
                self.target_template(layout, con)
@@ -115,24 +116,74 @@ class ConstraintButtonsPanel(bpy.types.Panel):
                        layout.itemR(con, "ik_type")
                        getattr(self, "IK_"+con.ik_type)(context, layout, con)
                else:
-                       self.IK_COPY_POSE(context, layout, con)
+                       # Legacy IK constraint
+                       self.target_template(layout, con)
+                       layout.itemR(con, "pole_target")
+       
+                       if con.pole_target and con.pole_target.type == 'ARMATURE':
+                               layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
+               
+                       if con.pole_target:
+                               row = layout.row()
+                               row.itemL()
+                               row.itemR(con, "pole_angle")
+               
+                       split = layout.split()
+                       col = split.column()
+                       col.itemR(con, "tail")
+                       col.itemR(con, "stretch")
+
+                       col = split.column()
+                       col.itemR(con, "iterations")
+                       col.itemR(con, "chain_length")
+                       
+                       split = layout.split()
+                       col = split.column()
+                       col.itemL()
+                       col.itemR(con, "targetless")
+                       col.itemR(con, "rotation")
+
+                       col = split.column()
+                       col.itemL(text="Weight:")
+                       col.itemR(con, "weight", text="Position", slider=True)
+                       sub = col.column()
+                       sub.active = con.rotation
+                       sub.itemR(con, "orient_weight", text="Rotation", slider=True)
 
        def IK_COPY_POSE(self, context, layout, con):
                self.target_template(layout, con)
                self.ik_template(layout, con)
-
-               split = layout.split()
-               col = split.column()
-               col.itemL()
-               col.itemR(con, "targetless")
-               col.itemR(con, "rotation")
-
-               col = split.column()
-               col.itemL(text="Weight:")
-               col.itemR(con, "weight", text="Position", slider=True)
-               sub = col.column()
-               sub.active = con.rotation
-               sub.itemR(con, "orient_weight", text="Rotation", slider=True)
+       
+               row = layout.row()
+               row.itemL(text="Axis Ref:")
+               row.itemR(con, "axis_reference", expand=True)
+               split = layout.split(percentage=0.33)
+               split.row().itemR(con, "position")
+               row = split.row()
+               row.itemR(con, "weight", text="Weight", slider=True)
+               row.active = con.position
+               split = layout.split(percentage=0.33)
+               row = split.row()
+               row.itemL(text="Lock:")
+               row = split.row()
+               row.itemR(con, "pos_lock_x", text="X")
+               row.itemR(con, "pos_lock_y", text="Y")
+               row.itemR(con, "pos_lock_z", text="Z")
+               split.active = con.position
+               
+               split = layout.split(percentage=0.33)
+               split.row().itemR(con, "rotation")
+               row = split.row()
+               row.itemR(con, "orient_weight", text="Weight", slider=True)
+               row.active = con.rotation
+               split = layout.split(percentage=0.33)
+               row = split.row()
+               row.itemL(text="Lock:")
+               row = split.row()
+               row.itemR(con, "rot_lock_x", text="X")
+               row.itemR(con, "rot_lock_y", text="Y")
+               row.itemR(con, "rot_lock_z", text="Z")
+               split.active = con.rotation
                
        def IK_DISTANCE(self, context, layout, con):
                self.target_template(layout, con)
@@ -610,20 +661,13 @@ class BONE_PT_inverse_kinematics(ConstraintButtonsPanel):
                split.itemL()
 
                if ob.pose.ik_solver == "ITASC":
-                       layout.itemL(text="Joint constraint:")
-                       split = layout.split(percentage=0.3)
-                       row = split.row()
-                       row.itemR(pchan, "ik_rot_control", text="Rotation")
-                       row = split.row()
+                       row = layout.row()
+                       row.itemR(pchan, "ik_rot_control", text="Control Rotation")
                        row.itemR(pchan, "ik_rot_weight", text="Weight", slider=True)
-                       row.active = pchan.ik_rot_control
                        # not supported yet
-                       #split = layout.split(percentage=0.3)
-                       #row = split.row()
-                       #row.itemR(pchan, "ik_lin_control", text="Size")
-                       #row = split.row()
+                       #row = layout.row()
+                       #row.itemR(pchan, "ik_lin_control", text="Joint Size")
                        #row.itemR(pchan, "ik_lin_weight", text="Weight", slider=True)
-                       #row.active = pchan.ik_lin_control
 
 class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
        __label__ = "iTaSC parameters"
index 7f4c19672075c13acdd1955b1804a324089e551c..b6fceabdb46e3c0cba73769bd8aec6ffb21c50a6 100644 (file)
@@ -1417,10 +1417,22 @@ static IK_Scene* convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan)
                switch (condata->type) {
                case CONSTRAINT_IK_COPYPOSE:
                        controltype = 0;
-                       if ((condata->flag & CONSTRAINT_IK_ROT) && (condata->orientweight != 0.0))
-                               controltype |= iTaSC::CopyPose::CTL_ROTATION;
-                       if ((condata->weight != 0.0))
-                               controltype |= iTaSC::CopyPose::CTL_POSITION;
+                       if (condata->flag & CONSTRAINT_IK_ROT) {
+                               if (!(condata->flag & CONSTRAINT_IK_NO_ROT_X))
+                                       controltype |= iTaSC::CopyPose::CTL_ROTATIONX;
+                               if (!(condata->flag & CONSTRAINT_IK_NO_ROT_Y))
+                                       controltype |= iTaSC::CopyPose::CTL_ROTATIONY;
+                               if (!(condata->flag & CONSTRAINT_IK_NO_ROT_Z))
+                                       controltype |= iTaSC::CopyPose::CTL_ROTATIONZ;
+                       }
+                       if (condata->flag & CONSTRAINT_IK_POS) {
+                               if (!(condata->flag & CONSTRAINT_IK_NO_POS_X))
+                                       controltype |= iTaSC::CopyPose::CTL_POSITIONX;
+                               if (!(condata->flag & CONSTRAINT_IK_NO_POS_Y))
+                                       controltype |= iTaSC::CopyPose::CTL_POSITIONY;
+                               if (!(condata->flag & CONSTRAINT_IK_NO_POS_Z))
+                                       controltype |= iTaSC::CopyPose::CTL_POSITIONZ;
+                       }
                        if (controltype) {
                                iktarget->constraint = new iTaSC::CopyPose(controltype, controltype, bonelen);
                                // set the gain
@@ -1432,7 +1444,10 @@ static IK_Scene* convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan)
                                iktarget->errorCallback = copypose_error;
                                iktarget->controlType = controltype;
                                // add the constraint
-                               ret = scene->addConstraintSet(iktarget->constraintName, iktarget->constraint, armname, iktarget->targetName, ikscene->channels[iktarget->channel].tail);
+                               if (condata->flag & CONSTRAINT_IK_TARGETAXIS)
+                                       ret = scene->addConstraintSet(iktarget->constraintName, iktarget->constraint, iktarget->targetName, armname, "", ikscene->channels[iktarget->channel].tail);
+                               else
+                                       ret = scene->addConstraintSet(iktarget->constraintName, iktarget->constraint, armname, iktarget->targetName, ikscene->channels[iktarget->channel].tail);
                        }
                        break;
                case CONSTRAINT_IK_DISTANCE:
index fccec7a556f3b87cad84f1a106b8b9233a6d234e..7232042c87600726e6677dfd198c23ab21ca372d 100644 (file)
@@ -502,6 +502,16 @@ typedef enum B_CONSTRAINTCHANNEL_FLAG {
 #define CONSTRAINT_IK_POS              32
 #define CONSTRAINT_IK_SETANGLE 64
 #define CONSTRAINT_IK_GETANGLE 128
+       /* limit axis */
+#define CONSTRAINT_IK_NO_POS_X 256
+#define CONSTRAINT_IK_NO_POS_Y 512
+#define CONSTRAINT_IK_NO_POS_Z 1024
+#define CONSTRAINT_IK_NO_ROT_X 2048
+#define CONSTRAINT_IK_NO_ROT_Y 4096
+#define CONSTRAINT_IK_NO_ROT_Z 8192
+       /* axis relative to target */
+#define CONSTRAINT_IK_TARGETAXIS       16384
+
 
 /* MinMax (floor) flags */
 #define MINMAX_STICKY  0x01
index 325318ba34a3c8b559b79ddca82f46579fe1d8f2..395633f5240c5a9c685ab2b8d2ab5165ab490f1c 100644 (file)
@@ -87,6 +87,12 @@ EnumPropertyItem constraint_ik_type_items[] ={
        {0, NULL, 0, NULL, NULL},
 };
 
+EnumPropertyItem constraint_ik_axisref_items[] ={
+       {0, "BONE", 0, "Bone", ""},
+       {CONSTRAINT_IK_TARGETAXIS, "TARGET", 0, "Target", ""},
+       {0, NULL, 0, NULL, NULL},
+};
+
 #ifdef RNA_RUNTIME
 
 #include "BKE_action.h"
@@ -497,11 +503,52 @@ static void rna_def_constraint_kinematic(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Use Tail", "Include bone's tail as last element in chain.");
        RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update");
 
+       prop= RNA_def_property(srna, "axis_reference", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+       RNA_def_property_enum_items(prop, constraint_ik_axisref_items);
+       RNA_def_property_ui_text(prop, "Axis Reference", "Constraint axis Lock options relative to Bone or Target reference");
+       RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update");
+
+       prop= RNA_def_property(srna, "position", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_IK_POS);
+       RNA_def_property_ui_text(prop, "Position", "Chain follows position of target.");
+       RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update");
+
+       prop= RNA_def_property(srna, "pos_lock_x", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_IK_NO_POS_X);
+       RNA_def_property_ui_text(prop, "Lock X Pos", "Constraint position along X axis");
+       RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Constraint_dependency_update");
+
+       prop= RNA_def_property(srna, "pos_lock_y", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_IK_NO_POS_Y);
+       RNA_def_property_ui_text(prop, "Lock Y Pos", "Constraint position along Y axis");
+       RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Constraint_dependency_update");
+
+       prop= RNA_def_property(srna, "pos_lock_z", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_IK_NO_POS_Z);
+       RNA_def_property_ui_text(prop, "Lock Z Pos", "Constraint position along Z axis");
+       RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Constraint_dependency_update");
+
        prop= RNA_def_property(srna, "rotation", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_IK_ROT);
        RNA_def_property_ui_text(prop, "Rotation", "Chain follows rotation of target.");
        RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update");
 
+       prop= RNA_def_property(srna, "rot_lock_x", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_IK_NO_ROT_X);
+       RNA_def_property_ui_text(prop, "Lock X Rot", "Constraint rotation along X axis");
+       RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Constraint_dependency_update");
+
+       prop= RNA_def_property(srna, "rot_lock_y", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_IK_NO_ROT_Y);
+       RNA_def_property_ui_text(prop, "Lock Y Rot", "Constraint rotation along Y axis");
+       RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Constraint_dependency_update");
+
+       prop= RNA_def_property(srna, "rot_lock_z", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_IK_NO_ROT_Z);
+       RNA_def_property_ui_text(prop, "Lock Z Rot", "Constraint rotation along Z axis");
+       RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Constraint_dependency_update");
+
        prop= RNA_def_property(srna, "targetless", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_IK_AUTO);
        RNA_def_property_ui_text(prop, "Targetless", "Use targetless IK.");