Spline IK: UI/Scaling Tweaks
authorJoshua Leung <aligorith@gmail.com>
Thu, 12 Nov 2009 12:20:57 +0000 (12:20 +0000)
committerJoshua Leung <aligorith@gmail.com>
Thu, 12 Nov 2009 12:20:57 +0000 (12:20 +0000)
* Renamed "Keep Max Length" to "Y Scaling" which has the opposite meaning

* Improved the way that Y-Scaling off behaves. Most of the time, bones that do not fit on the curve are now "blended off" their default rotations instead of being scaled to zero.

* Added option to offset an entire chain by moving the root bone of the chain. This is named "Chain Offset"

release/scripts/ui/properties_object_constraint.py
source/blender/blenkernel/intern/armature.c
source/blender/editors/animation/anim_channels_defines.c
source/blender/editors/object/object_constraint.c
source/blender/makesrna/intern/rna_constraint.c

index c662706743c65c926ed768d9e3a3ae77b2708be1..49a228f38c934ba544d13872ac97f6357f41f9e3 100644 (file)
@@ -602,11 +602,11 @@ class ConstraintButtonsPanel(bpy.types.Panel):
         col.itemL(text="Spline Fitting:")
         col.itemR(con, "chain_length")
         col.itemR(con, "even_divisions")
-        #col.itemR(con, "affect_root") # XXX: this is not that useful yet
+        col.itemR(con, "chain_offset")
 
         col = layout.column()
         col.itemL(text="Chain Scaling:")
-        col.itemR(con, "keep_max_length")
+        col.itemR(con, "y_scaling")
         col.itemR(con, "xz_scaling_mode")
 
 
index 798c3a87846802d0a4c97c723bdf5d8ea568c991..cf84fea1f68ad9d04467c381d08457ab61f044e2 100644 (file)
@@ -1707,7 +1707,7 @@ static void splineik_init_tree_from_pchan(Object *ob, bPoseChannel *pchan_tip)
                                 */
                                if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
                                        /* 1) equi-spaced joints */
-                                       ikData->points[i]= segmentLen;
+                                       ikData->points[i]= ikData->points[i-1] - segmentLen;
                                }
                                else {
                                         /*     2) to find this point on the curve, we take a step from the previous joint
@@ -1811,9 +1811,7 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
 {
        bSplineIKConstraint *ikData= tree->ikData;
        float poseHead[3], poseTail[3], poseMat[4][4]; 
-       float splineVec[3], scaleFac;
-       float rad, radius=1.0f;
-       float vec[4], dir[3];
+       float splineVec[3], scaleFac, radius=1.0f;
        
        /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
        where_is_pose_bone(scene, ob, pchan, ctime);
@@ -1821,24 +1819,41 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
        VECCOPY(poseHead, pchan->pose_head);
        VECCOPY(poseTail, pchan->pose_tail);
        
-       /* step 1a: get xyz positions for the tail endpoint of the bone */
-       if ( where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad) ) {
-               /* convert the position to pose-space, then store it */
-               mul_m4_v3(ob->imat, vec);
-               VECCOPY(poseTail, vec);
+       /* step 1: determine the positions for the endpoints of the bone */
+       {
+               float vec[4], dir[3], rad;
+               float tailBlendFac= 1.0f;
+               
+               /* determine if the bone should still be affected by SplineIK */
+               if (tree->points[index+1] >= 1.0f) {
+                       /* spline doesn't affect the bone anymore, so done... */
+                       pchan->flag |= POSE_DONE;
+                       return;
+               }
+               else if ((tree->points[index] >= 1.0f) && (tree->points[index+1] < 1.0f)) {
+                       /* blending factor depends on the amount of the bone still left on the chain */
+                       tailBlendFac= (1.0f - tree->points[index+1]) / (tree->points[index] - tree->points[index+1]);
+               }
                
-               /* set the new radius */
-               radius= rad;
-       }
-       
-       /* step 1b: get xyz positions for the head endpoint of the bone */
-       if ( where_on_path(ikData->tar, tree->points[index+1], vec, dir, NULL, &rad) ) {
-               /* store the position, and convert it to pose space */
-               mul_m4_v3(ob->imat, vec);
-               VECCOPY(poseHead, vec);
+               /* tail endpoint */
+               if ( where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad) ) {
+                       /* convert the position to pose-space, then store it */
+                       mul_m4_v3(ob->imat, vec);
+                       interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac);
+                       
+                       /* set the new radius */
+                       radius= rad;
+               }
                
-               /* set the new radius (it should be the average value) */
-               radius = (radius+rad) / 2;
+               /* head endpoint */
+               if ( where_on_path(ikData->tar, tree->points[index+1], vec, dir, NULL, &rad) ) {
+                       /* store the position, and convert it to pose space */
+                       mul_m4_v3(ob->imat, vec);
+                       VECCOPY(poseHead, vec);
+                       
+                       /* set the new radius (it should be the average value) */
+                       radius = (radius+rad) / 2;
+               }
        }
        
        /* step 2: determine the implied transform from these endpoints 
@@ -1918,8 +1933,16 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
                }
        }
        
-       /* step 5: set the location of the bone in the matrix */
-       VECCOPY(poseMat[3], poseHead);
+       /* step 5: set the location of the bone in the matrix 
+        *      - when the 'no-root' option is affected, the chain can retain
+        *        the shape but be moved elsewhere
+        */
+       if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) {
+               VECCOPY(poseMat[3], pchan->pose_head);
+       }
+       else {
+               VECCOPY(poseMat[3], poseHead);
+       }
        
        /* finally, store the new transform */
        copy_m4_m4(pchan->pose_mat, poseMat);
index 865e89c927abef08cb2a1dd872132acd99e04b64..24a8fb445c7841938e5478e2d34333c8c61bb24b 100644 (file)
@@ -1732,7 +1732,7 @@ static bAnimChannelType ACF_DSARM=
        acf_dsarm_icon,                         /* icon */
        
        acf_generic_dataexpand_setting_valid,   /* has setting */
-       acf_dsarm_setting_flag,                         /* flag for setting */
+       acf_dsarm_setting_flag,                                 /* flag for setting */
        acf_dsarm_setting_ptr                                   /* pointer for setting */
 };
 
@@ -1794,19 +1794,19 @@ static void *acf_dsntree_setting_ptr(bAnimListElem *ale, int setting, short *typ
        }
 }
 
-/* metaball expander type define */
+/* node tree expander type define */
 static bAnimChannelType ACF_DSNTREE= 
 {
-acf_generic_dataexpand_backdrop,/* backdrop */
-acf_generic_indention_1,               /* indent level */
-acf_generic_basic_offset,              /* offset */
-
-acf_generic_idblock_name,              /* name */
-acf_dsntree_icon,                              /* icon */
-
-acf_generic_dataexpand_setting_valid,  /* has setting */
-acf_dsntree_setting_flag,                              /* flag for setting */
-acf_dsntree_setting_ptr                                        /* pointer for setting */
+       acf_generic_dataexpand_backdrop,/* backdrop */
+       acf_generic_indention_1,                /* indent level */              // XXX this only works for compositing
+       acf_generic_basic_offset,               /* offset */
+       
+       acf_generic_idblock_name,               /* name */
+       acf_dsntree_icon,                               /* icon */
+       
+       acf_generic_dataexpand_setting_valid,   /* has setting */
+       acf_dsntree_setting_flag,                               /* flag for setting */
+       acf_dsntree_setting_ptr                                 /* pointer for setting */
 };
 
 
index 9c890006c4598f31f11b0be2a81ea1bbc2be8c73..dbc7973b67ba4a20472cec07f8bc92faf895fbe8 100644 (file)
@@ -351,9 +351,7 @@ static void test_constraints (Object *owner, const char substring[])
                                /* if the number of points does not match the amount required by the chain length,
                                 * free the points array and request a rebind...
                                 */
-                               if ( (data->points == NULL) ||
-                                        (!(data->flag & CONSTRAINT_SPLINEIK_NO_ROOT) && (data->numpoints != data->chainlen+1)) ||
-                                        ( (data->flag & CONSTRAINT_SPLINEIK_NO_ROOT) && (data->numpoints != data->chainlen)) )
+                               if ((data->points == NULL) || (data->numpoints != data->chainlen+1))
                                {
                                        /* free the points array */
                                        if (data->points) {
index 7f7976c365f8ae79f9638ef031279bd5773158bd..24aff923ba88867be55f98ff91b539b424487dac 100644 (file)
@@ -1706,9 +1706,9 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna)
        // TODO: add access to the positions array to allow more flexible aligning?
        
        /* settings */
-       prop= RNA_def_property(srna, "affect_root", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_NO_ROOT);
-       RNA_def_property_ui_text(prop, "Affect Root", "Include the root joint in the calculations.");
+       prop= RNA_def_property(srna, "chain_offset", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_NO_ROOT);
+       RNA_def_property_ui_text(prop, "Chain Offset", "Offset the entire chain relative to the root joint.");
        RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
        
        prop= RNA_def_property(srna, "even_divisions", PROP_BOOLEAN, PROP_NONE);
@@ -1716,9 +1716,9 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Even Divisions", "Ignore the relative lengths of the bones when fitting to the curve.");
        RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
        
-       prop= RNA_def_property(srna, "keep_max_length", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_SCALE_LIMITED);
-       RNA_def_property_ui_text(prop, "Keep Max Length", "Maintain the maximum length of the chain when spline is stretched.");
+       prop= RNA_def_property(srna, "y_scaling", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_SCALE_LIMITED);
+       RNA_def_property_ui_text(prop, "Y Scaling", "Stretch the Y axis of the bones to fit the curve.");
        RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
        
        prop= RNA_def_property(srna, "xz_scaling_mode", PROP_ENUM, PROP_NONE);