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>2010-05-27 14:50:06 +0400
committerJoshua Leung <aligorith@gmail.com>2010-05-27 14:50:06 +0400
commit4ebc634168e0349c07c74fdf61defaad05db70f9 (patch)
tree0b75054def0d074a4cb245fee44e2974b4a76d4d
parent135f8be2c7933bb06b817ae204f867aff96040cc (diff)
== Pivot Constraint ==
This constraint allows an object or bone to have their rotations applied as if their origin/pivot-point was located elsewhere. The most obvious uses include foot-roll, see-saws, but could also include more complicated rolling-box examples. == Usage Examples == === Foot Roll === 1. Add 'Pivot' Constraint to the bone without any target. 2. Set the 'Y' value of the offset to the length of the bone. Usually this should be negative (if you rig with feet facing 'forwards' along -Y axis). This gives you a pivot point relative to the bone's (preconstraint) location, which should be at the tip of the bone here. Disabling the 'Use Relative Offset' would make this offset be relative to 0,0,0 instead of to the owner/bone-head. 3. Ensure that the 'Pivot When' setting is set to '-X Rot', (default) which means that the pivot will only used when the rotation on the X-Axis is negative to get tip-toe 'roll'. === See Saw === 1. Add a 'Pivot' constraint too see-saw plank object, this time with a target that you wish to have as the pivot-point. It's possible to do this without too (as before), but is less intuitive. 2. Optionally, if you want the plank slightly raised, set the z-offset value, which should make the pivot-point used to be relative to the target with the z-offset applied. 3. Ensure that 'Pivot When' is set to 'Always', which means that the pivot will always be used, irrespective of the rotation. == Notes == * The 'Pivot When' setting has been integrated in the constraint, since this is something that will often be required for these setups. Having to set up additional drivers to drive the constraint to do this kindof beats the purpose of providing this. * The 'Offset' functionality is probably not presented as clearly as it could be. We may need to go over this again. * For foot-roll - if any scaling of the foot is required, simply set up a driver on the y-offset to make this dynamically respond to the "scale" RNA property of the bones (don't use the "Transform Channel" vartype since that won't work correct here). However, this shouldn't be common enough to warrant special treatment.
-rw-r--r--release/scripts/ui/properties_object_constraint.py18
-rw-r--r--source/blender/blenkernel/intern/constraint.c113
-rw-r--r--source/blender/editors/object/object_constraint.c17
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h54
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c60
6 files changed, 257 insertions, 6 deletions
diff --git a/release/scripts/ui/properties_object_constraint.py b/release/scripts/ui/properties_object_constraint.py
index f53bac05a7c..11527ad9bda 100644
--- a/release/scripts/ui/properties_object_constraint.py
+++ b/release/scripts/ui/properties_object_constraint.py
@@ -76,7 +76,7 @@ class ConstraintButtonsPanel(bpy.types.Panel):
else:
layout.prop_object(con, "subtarget", con.target.data, "bones", text="")
- if con.type in ('COPY_LOCATION', 'STRETCH_TO', 'TRACK_TO'):
+ if con.type in ('COPY_LOCATION', 'STRETCH_TO', 'TRACK_TO', 'PIVOT'):
row = layout.row()
row.label(text="Head/Tail:")
row.prop(con, "head_tail", text="")
@@ -730,6 +730,22 @@ class ConstraintButtonsPanel(bpy.types.Panel):
col.prop(con, "xz_scaling_mode", text="")
col.prop(con, "use_curve_radius")
+ def PIVOT(self, context, layout, con, wide_ui):
+ self.target_template(layout, con, wide_ui)
+
+ if con.target:
+ col = layout.column()
+ col.prop(con, "offset", text="Pivot Offset")
+ else:
+ col = layout.column()
+ col.prop(con, "use_relative_position")
+ if con.use_relative_position:
+ col.prop(con, "offset", text="Relative Pivot Point")
+ else:
+ col.prop(con, "offset", text="Absolute Pivot Point")
+
+ col = layout.column()
+ col.prop(con, "enabled_rotation_range", text="Pivot When")
class OBJECT_PT_constraints(ConstraintButtonsPanel):
bl_label = "Object Constraints"
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index a3f1cb0cb0c..1a8d665a91d 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -3831,6 +3831,118 @@ static bConstraintTypeInfo CTI_SPLINEIK = {
NULL /* evaluate - solved as separate loop */
};
+/* ----------- Pivot ------------- */
+
+static void pivotcon_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+ bPivotConstraint *data= con->data;
+
+ /* target only */
+ func(con, (ID**)&data->tar, userdata);
+}
+
+static int pivotcon_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bPivotConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static void pivotcon_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bPivotConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+static void pivotcon_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bPivotConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ float pivot[3], vec[3];
+ float rotMat[3][3];
+
+ /* firstly, check if pivoting should take place based on the current rotation */
+ if (data->rotAxis != PIVOTCON_AXIS_NONE) {
+ float rot[3];
+
+ /* extract euler-rotation of target */
+ mat4_to_eulO(rot, cob->rotOrder, cob->matrix);
+
+ /* check which range might be violated */
+ if (data->rotAxis < PIVOTCON_AXIS_X) {
+ /* negative rotations (data->rotAxis = 0 -> 2) */
+ if (rot[data->rotAxis] > 0.0f)
+ return;
+ }
+ else {
+ /* positive rotations (data->rotAxis = 3 -> 5 */
+ if (rot[data->rotAxis - PIVOTCON_AXIS_X] < 0.0f)
+ return;
+ }
+ }
+
+ /* find the pivot-point to use */
+ if (VALID_CONS_TARGET(ct)) {
+ /* apply offset to target location */
+ add_v3_v3v3(pivot, ct->matrix[3], data->offset);
+ }
+ else {
+ /* no targets to worry about... */
+ if ((data->flag & PIVOTCON_FLAG_OFFSET_ABS) == 0) {
+ /* offset is relative to owner */
+ add_v3_v3v3(pivot, cob->matrix[3], data->offset);
+ }
+ else {
+ /* directly use the 'offset' specified as an absolute position instead */
+ VECCOPY(pivot, data->offset);
+ }
+ }
+
+ /* get rotation matrix representing the rotation of the owner */
+ // TODO: perhaps we might want to include scaling based on the pivot too?
+ copy_m3_m4(rotMat, cob->matrix);
+ normalize_m3(rotMat);
+
+ /* perform the pivoting... */
+ /* 1. take the vector from owner to the pivot */
+ sub_v3_v3v3(vec, pivot, cob->matrix[3]);
+ /* 2. rotate this vector by the rotation of the object... */
+ mul_m3_v3(rotMat, vec);
+ /* 3. make the rotation in terms of the pivot now */
+ add_v3_v3v3(cob->matrix[3], pivot, vec);
+}
+
+
+static bConstraintTypeInfo CTI_PIVOT = {
+ CONSTRAINT_TYPE_PIVOT, /* type */
+ sizeof(bPivotConstraint), /* size */
+ "Pivot", /* name */
+ "bPivotConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ pivotcon_id_looper, /* id looper */
+ NULL, /* copy data */
+ NULL, /* new data */ // XXX: might be needed to get 'normal' pivot behaviour...
+ pivotcon_get_tars, /* get constraint targets */
+ pivotcon_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ pivotcon_evaluate /* evaluate */
+};
+
/* ************************* Constraints Type-Info *************************** */
/* All of the constraints api functions use bConstraintTypeInfo structs to carry out
* and operations that involve constraint specific code.
@@ -3867,6 +3979,7 @@ static void constraints_init_typeinfo () {
constraintsTypeInfo[22]= &CTI_SPLINEIK; /* Spline IK Constraint */
constraintsTypeInfo[23]= &CTI_TRANSLIKE; /* Copy Transforms Constraint */
constraintsTypeInfo[24]= &CTI_SAMEVOL; /* Maintain Volume Constraint */
+ constraintsTypeInfo[25]= &CTI_PIVOT; /* Pivot Constraint */
}
/* This function should be used for getting the appropriate type-info when only
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 9163baf606f..eaabcd866cd 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -322,6 +322,23 @@ static void test_constraints (Object *owner, bPoseChannel *pchan)
/* targets have already been checked for this */
continue;
}
+ else if (curcon->type == CONSTRAINT_TYPE_PIVOT) {
+ bPivotConstraint *data = curcon->data;
+
+ /* target doesn't have to exist, but if it is non-null, it must exist! */
+ if (data->tar && exist_object(data->tar)==0) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->tar == owner) {
+ if (!get_named_bone(get_armature(owner), data->subtarget)) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ /* targets have already been checked for this */
+ continue;
+ }
else if (curcon->type == CONSTRAINT_TYPE_ACTION) {
bActionConstraint *data = curcon->data;
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 6c7bda171eb..00694a7ea1f 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -174,6 +174,7 @@ typedef struct bSplineIKConstraint {
/* Single-target subobject constraints --------------------- */
+
/* Track To Constraint */
typedef struct bTrackToConstraint {
Object *tar;
@@ -336,6 +337,24 @@ typedef struct bTransformConstraint {
float to_max[3];
} bTransformConstraint;
+/* Pivot Constraint */
+typedef struct bPivotConstraint {
+ /* Pivot Point:
+ * Either target object + offset, or just offset is used
+ */
+ Object *tar; /* target object (optional) */
+ char subtarget[32]; /* subtarget name (optional) */
+ float offset[3]; /* offset from the target to use, regardless of whether it exists */
+
+ /* Rotation-driven activation:
+ * This option provides easier one-stop setups for footrolls
+ */
+ short rotAxis; /* rotation axes to consider for this (ePivotConstraint_Axis) */
+
+ /* General flags */
+ short flag; /* ePivotConstraint_Flag */
+} bPivotConstraint;
+
/* transform limiting constraints - zero target ---------------------------- */
/* Limit Location Constraint */
typedef struct bLocLimitConstraint {
@@ -419,6 +438,7 @@ typedef enum eBConstraint_Types {
CONSTRAINT_TYPE_SPLINEIK, /* Spline-IK - Align 'n' bones to a curve */
CONSTRAINT_TYPE_TRANSLIKE, /* Copy transform matrix */
CONSTRAINT_TYPE_SAMEVOL, /* Maintain volume during scaling */
+ CONSTRAINT_TYPE_PIVOT, /* Pivot Constraint */
/* NOTE: no constraints are allowed to be added after this */
NUM_CONSTRAINT_TYPES
@@ -469,11 +489,6 @@ typedef enum eConstraintChannel_Flags {
/* -------------------------------------- */
-/**
- * The flags for ROTLIKE, LOCLIKE and SIZELIKE should be kept identical
- * (that is, same effect, different name). It simplifies the Python API access a lot.
- */
-
/* bRotateLikeConstraint.flag */
typedef enum eCopyRotation_Flags {
ROTLIKE_X = (1<<0),
@@ -688,6 +703,35 @@ typedef enum eChildOf_Flags {
CHILDOF_SIZEZ = (1<<8),
} eChildOf_Flags;
+/* Pivot Constraint */
+ /* Restrictions for Pivot Constraint axis to consider for enabling constraint */
+typedef enum ePivotConstraint_Axis {
+ /* do not consider this activity-clamping */
+ PIVOTCON_AXIS_NONE = -1,
+
+ /* consider -ve x-axis rotations */
+ PIVOTCON_AXIS_X_NEG,
+ /* consider -ve y-axis rotations */
+ PIVOTCON_AXIS_Y_NEG,
+ /* consider -ve z-axis rotations */
+ PIVOTCON_AXIS_Z_NEG,
+
+ /* consider +ve x-axis rotations */
+ PIVOTCON_AXIS_X,
+ /* consider +ve y-axis rotations */
+ PIVOTCON_AXIS_Y,
+ /* consider +ve z-axis rotations */
+ PIVOTCON_AXIS_Z,
+} ePivotConstraint_Axis;
+
+ /* settings for Pivot Constraint in general */
+typedef enum ePivotConstraint_Flag {
+ /* offset is to be interpreted as being a fixed-point in space */
+ PIVOTCON_FLAG_OFFSET_ABS = (1<<0),
+ /* rotation-based activation uses negative rotation to drive result */
+ PIVOTCON_FLAG_ROTACT_NEG = (1<<1),
+} ePivotConstraint_Flag;
+
/* Rigid-Body Constraint */
#define CONSTRAINT_DRAW_PIVOT 0x40
#define CONSTRAINT_DISABLE_LINKED_COLLISION 0x80
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index f9802e558bb..3badc401514 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -356,6 +356,7 @@ extern StructRNA RNA_SPHFluidSettings;
extern StructRNA RNA_ParticleSystem;
extern StructRNA RNA_ParticleSystemModifier;
extern StructRNA RNA_ParticleTarget;
+extern StructRNA RNA_PivotConstraint;
extern StructRNA RNA_PluginSequence;
extern StructRNA RNA_PluginTexture;
extern StructRNA RNA_PointCache;
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index b4ae49ae2f4..b1c5cac1865 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -67,6 +67,7 @@ EnumPropertyItem constraint_type_items[] ={
{CONSTRAINT_TYPE_RIGIDBODYJOINT, "RIGID_BODY_JOINT", ICON_CONSTRAINT_DATA, "Rigid Body Joint", ""},
{CONSTRAINT_TYPE_PYTHON, "SCRIPT", ICON_CONSTRAINT_DATA, "Script", ""},
{CONSTRAINT_TYPE_SHRINKWRAP, "SHRINKWRAP", ICON_CONSTRAINT_DATA, "Shrinkwrap", ""},
+ {CONSTRAINT_TYPE_PIVOT, "PIVOT", ICON_CONSTRAINT_DATA, "Pivot", ""},
{0, NULL, 0, NULL, NULL}};
EnumPropertyItem space_pchan_items[] = {
@@ -157,6 +158,8 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
return &RNA_SplineIKConstraint;
case CONSTRAINT_TYPE_TRANSLIKE:
return &RNA_CopyTransformsConstraint;
+ case CONSTRAINT_TYPE_PIVOT:
+ return &RNA_PivotConstraint;
default:
return &RNA_UnknownType;
}
@@ -1839,6 +1842,62 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
}
+static void rna_def_constraint_pivot(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem pivot_rotAxis_items[] = {
+ {PIVOTCON_AXIS_NONE, "ALWAYS_ACTIVE", 0, "Always", ""},
+ {PIVOTCON_AXIS_X_NEG, "NX", 0, "-X Rot", ""},
+ {PIVOTCON_AXIS_Y_NEG, "NY", 0, "-Y Rot", ""},
+ {PIVOTCON_AXIS_Z_NEG, "NZ", 0, "-Z Rot", ""},
+ {PIVOTCON_AXIS_X, "X", 0, "X Rot", ""},
+ {PIVOTCON_AXIS_Y, "Y", 0, "Y Rot", ""},
+ {PIVOTCON_AXIS_Z, "Z", 0, "Z Rot", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ srna= RNA_def_struct(brna, "PivotConstraint", "Constraint");
+ RNA_def_struct_ui_text(srna, "Pivot Constraint", "Rotate around a different point");
+
+ prop= RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
+ RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
+ RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_def_struct_sdna_from(srna, "bPivotConstraint", "data");
+
+ /* target-defined pivot */
+ prop= RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "tar");
+ RNA_def_property_ui_text(prop, "Target", "Target Object, defining the position of the pivot when defined");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update");
+
+ prop= RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "subtarget");
+ RNA_def_property_ui_text(prop, "Sub-Target", "");
+ RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update");
+
+ /* pivot offset */
+ prop= RNA_def_property(srna, "use_relative_position", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", PIVOTCON_FLAG_OFFSET_ABS);
+ RNA_def_property_ui_text(prop, "Use Relative Offset", "Offset will be an absolute point in space instead of relative to the target");
+ RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop= RNA_def_property(srna, "offset", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "offset");
+ RNA_def_property_ui_text(prop, "Offset", "Offset of pivot from target (when set), or from owner's location (when Fixed Position is off), or the absolute pivot point");
+ RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
+
+ /* rotation-based activation */
+ prop= RNA_def_property(srna, "enabled_rotation_range", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "rotAxis");
+ RNA_def_property_enum_items(prop, pivot_rotAxis_items);
+ RNA_def_property_ui_text(prop, "Enabled Rotation Range", "Rotation range on which pivoting should occur");
+ RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
+}
+
/* base struct for constraints */
void RNA_def_constraint(BlenderRNA *brna)
{
@@ -1943,6 +2002,7 @@ void RNA_def_constraint(BlenderRNA *brna)
rna_def_constraint_shrinkwrap(brna);
rna_def_constraint_damped_track(brna);
rna_def_constraint_spline_ik(brna);
+ rna_def_constraint_pivot(brna);
}
#endif