From f0361fcf54e8d15790e2bad5c7402f6af3c24083 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 13 Jan 2015 18:06:53 +1300 Subject: Pataz-Gooseberry Request: Limits on Volume Preservation for Spline IK This commit adds a new type of volume preservation mode to Spline IK which makes it possible to set limits on the minimum and maximum scaling of bone "fatness". * The old volume preseving mode has been kept but renamed, to avoid breaking old rigs. "Volume Presevation" uses the new method, while "Inverse Preservation" is the old one. * The code and settings for this new xz scale mode are directly lifted from the improved Stretch To constraint --- .../scripts/startup/bl_ui/properties_constraint.py | 20 ++++++++- source/blender/blenkernel/intern/armature.c | 52 +++++++++++++++++++++- source/blender/makesdna/DNA_constraint_types.h | 24 +++++++--- source/blender/makesrna/intern/rna_constraint.c | 38 +++++++++++++++- 4 files changed, 123 insertions(+), 11 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index e6b62cae6ef..0c5aae1de2f 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -768,9 +768,27 @@ class ConstraintButtonsPanel(): col = layout.column() col.label(text="Chain Scaling:") col.prop(con, "use_y_stretch") - col.prop(con, "xz_scale_mode") col.prop(con, "use_curve_radius") + layout.prop(con, "xz_scale_mode") + + if con.xz_scale_mode == 'VOLUME_PRESERVE': + layout.prop(con, "bulge", text="Volume Variation") + split = layout.split() + col = split.column(align=True) + col.prop(con, "use_bulge_min", text="Volume Min") + sub = col.column() + sub.active = con.use_bulge_min + sub.prop(con, "bulge_min", text="") + col = split.column(align=True) + col.prop(con, "use_bulge_max", text="Volume Max") + sub = col.column() + sub.active = con.use_bulge_max + sub.prop(con, "bulge_max", text="") + col = layout.column() + col.active = con.use_bulge_min or con.use_bulge_max + col.prop(con, "bulge_smooth", text="Smooth") + def PIVOT(self, context, layout, con): self.target_template(layout, con) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index df57db21e3b..88b46efc9e6 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -2166,9 +2166,9 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o mul_v3_fl(poseMat[2], scale); break; } - case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: + case CONSTRAINT_SPLINEIK_XZS_INVERSE: { - /* 'volume preservation' */ + /* old 'volume preservation' method using the inverse scale */ float scale; /* calculate volume preservation factor which is @@ -2189,6 +2189,54 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o mul_v3_fl(poseMat[2], scale); break; } + case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: + { + /* improved volume preservation based on the Stretch To constraint */ + float scale; + + /* as the basis for volume preservation, we use the inverse scale factor... */ + if (fabsf(scaleFac) != 0.0f) { + /* NOTE: The method here is taken wholesale from the Stretch To constraint */ + float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge); + + if (bulge > 1.0f) { + if (ikData->flag & STRETCHTOCON_USE_BULGE_MAX) { + float bulge_max = max_ff(ikData->bulge_max, 1.0f); + float hard = min_ff(bulge, bulge_max); + + float range = bulge_max - 1.0f; + float scale = (range > 0.0f) ? 1.0f / range : 0.0f; + float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (0.5f * M_PI); + + bulge = interpf(soft, hard, ikData->bulge_smooth); + } + } + if (bulge < 1.0f) { + if (ikData->flag & STRETCHTOCON_USE_BULGE_MIN) { + float bulge_min = CLAMPIS(ikData->bulge_max, 0.0f, 1.0f); + float hard = max_ff(bulge, bulge_min); + + float range = 1.0f - bulge_min; + float scale = (range > 0.0f) ? 1.0f / range : 0.0f; + float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (0.5f * M_PI); + + bulge = interpf(soft, hard, ikData->bulge_smooth); + } + } + + /* compute scale factor for xz axes from this value */ + scale = sqrt(bulge); + } + else { + /* no scaling, so scale factor is simple */ + scale = 1.0f; + } + + /* apply the scaling (assuming normalised scale) */ + mul_v3_fl(poseMat[0], scale); + mul_v3_fl(poseMat[2], scale); + break; + } } /* finally, multiply the x and z scaling by the radius of the curve too, diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index fb33879e2c1..86991245068 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -173,6 +173,12 @@ typedef struct bSplineIKConstraint { /* settings */ short flag; /* general settings for constraint */ short xzScaleMode; /* method used for determining the x & z scaling of the bones */ + + /* volume preservation settings */ + float bulge; + float bulge_min; + float bulge_max; + float bulge_smooth; } bSplineIKConstraint; @@ -680,15 +686,19 @@ typedef enum eKinematic_Flags { /* bSplineIKConstraint->flag */ typedef enum eSplineIK_Flags { /* chain has been attached to spline */ - CONSTRAINT_SPLINEIK_BOUND = (1<<0), + CONSTRAINT_SPLINEIK_BOUND = (1 << 0), /* root of chain is not influenced by the constraint */ - CONSTRAINT_SPLINEIK_NO_ROOT = (1<<1), + CONSTRAINT_SPLINEIK_NO_ROOT = (1 << 1), /* bones in the chain should not scale to fit the curve */ - CONSTRAINT_SPLINEIK_SCALE_LIMITED = (1<<2), + CONSTRAINT_SPLINEIK_SCALE_LIMITED = (1 << 2), /* evenly distribute the bones along the path regardless of length */ - CONSTRAINT_SPLINEIK_EVENSPLITS = (1<<3), + CONSTRAINT_SPLINEIK_EVENSPLITS = (1 << 3), /* don't adjust the x and z scaling of the bones by the curve radius */ - CONSTRAINT_SPLINEIK_NO_CURVERAD = (1<<4) + CONSTRAINT_SPLINEIK_NO_CURVERAD = (1 << 4), + + /* for "volumetric" xz scale mode, limit the minimum or maximum scale values */ + CONSTRAINT_SPLINEIK_USE_BULGE_MIN = (1 << 5), + CONSTRAINT_SPLINEIK_USE_BULGE_MAX = (1 << 6), } eSplineIK_Flags; /* bSplineIKConstraint->xzScaleMode */ @@ -698,7 +708,9 @@ typedef enum eSplineIK_XZScaleModes { /* bones in the chain should take their x/z scales from the original scaling */ CONSTRAINT_SPLINEIK_XZS_ORIGINAL = 1, /* x/z scales are the inverse of the y-scale */ - CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC = 2 + CONSTRAINT_SPLINEIK_XZS_INVERSE = 2, + /* x/z scales are computed using a volume preserving technique (from Stretch To constraint) */ + CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC = 3 } eSplineIK_XZScaleModes; /* MinMax (floor) flags */ diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 77355dbad0e..b6845b1df2e 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -1388,7 +1388,7 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna) prop = RNA_def_property(srna, "bulge_smooth", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0, 1.0f); - RNA_def_property_ui_text(prop, "Volume Variation Smoothness", ""); + RNA_def_property_ui_text(prop, "Volume Variation Smoothness", "Strength of volume stretching clamping"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); } @@ -2272,8 +2272,10 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) {CONSTRAINT_SPLINEIK_XZS_NONE, "NONE", 0, "None", "Don't scale the X and Z axes (Default)"}, {CONSTRAINT_SPLINEIK_XZS_ORIGINAL, "BONE_ORIGINAL", 0, "Bone Original", "Use the original scaling of the bones"}, + {CONSTRAINT_SPLINEIK_XZS_INVERSE, "INVERSE_PRESERVE", 0, "Inverse Scale", + "Scale of the X and Z axes is the inverse of the Y-Scale"}, {CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC, "VOLUME_PRESERVE", 0, "Volume Preservation", - "Scale of the X and Z axes is the inverse of the Y-Scale"}, + "Scale of the X and Z axes are adjusted to preserve the volume of the bones"}, {0, NULL, 0, NULL, NULL} }; @@ -2333,12 +2335,44 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) "on top of XZ Scale mode"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + /* xz scaling mode */ prop = RNA_def_property(srna, "xz_scale_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "xzScaleMode"); RNA_def_property_enum_items(prop, splineik_xz_scale_mode); RNA_def_property_ui_text(prop, "XZ Scale Mode", "Method used for determining the scaling of the X and Z axes of the bones"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + /* volume presevation for "volumetric" scale mode */ + prop = RNA_def_property(srna, "bulge", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 100.f); + RNA_def_property_ui_text(prop, "Volume Variation", "Factor between volume variation and stretching"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "use_bulge_min", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_USE_BULGE_MIN); + RNA_def_property_ui_text(prop, "Use Volume Variation Minimum", "Use lower limit for volume variation"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "use_bulge_max", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_USE_BULGE_MAX); + RNA_def_property_ui_text(prop, "Use Volume Variation Maximum", "Use upper limit for volume variation"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "bulge_min", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1.0f); + RNA_def_property_ui_text(prop, "Volume Variation Minimum", "Minimum volume stretching factor"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "bulge_max", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 1.0, 100.0f); + RNA_def_property_ui_text(prop, "Volume Variation Maximum", "Maximum volume stretching factor"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "bulge_smooth", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0, 1.0f); + RNA_def_property_ui_text(prop, "Volume Variation Smoothness", "Strength of volume stretching clamping"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); } static void rna_def_constraint_pivot(BlenderRNA *brna) -- cgit v1.2.3