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:
authorAlexander Gavrilov <angavrilov@gmail.com>2018-07-15 20:39:02 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2018-11-06 10:56:08 +0300
commit798cdaeeb6927cb9ca42597fa23845eac04c02b2 (patch)
tree92e444a0a2268d891cdd90f56299ccb8f1c1bf3b /source/blender/makesrna/intern/rna_constraint.c
parenta817613be5ab1545b000e9173a8d3079aaaefa01 (diff)
Implement an Armature constraint that mimics the modifier.
The main use one can imagine for this is adding tweak controls to parts of a model that are already deformed by multiple other major bones. It is natural to expect such locations to deform as if the tweaks aren't there by default; however currently there is no easy way to make a bone follow multiple other bones. This adds a new constraint that implements the math behind the Armature modifier, with support for explicit weights, bone envelopes, and dual quaternion blending. It can also access bones from multiple armatures at the same time (mainly because it's easier to code it that way.) This also fixes dquat_to_mat4, which wasn't used anywhere before. Differential Revision: https://developer.blender.org/D3664
Diffstat (limited to 'source/blender/makesrna/intern/rna_constraint.c')
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c227
1 files changed, 223 insertions, 4 deletions
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 51d4d93586c..e2d4093b753 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -27,6 +27,9 @@
#include <stdlib.h>
#include "BLI_math.h"
+#include "BLI_listbase.h"
+
+#include "MEM_guardedalloc.h"
#include "BLT_translation.h"
@@ -106,6 +109,8 @@ const EnumPropertyItem rna_enum_constraint_type_items[] = {
"Custom constraint(s) written in Python (Not yet implemented)"}, */
{CONSTRAINT_TYPE_SHRINKWRAP, "SHRINKWRAP", ICON_CONSTRAINT, "Shrinkwrap",
"Restrict movements to surface of target mesh"},
+ {CONSTRAINT_TYPE_ARMATURE, "ARMATURE", ICON_CONSTRAINT, "Armature",
+ "Apply weight-blended transformation from multiple bones like the Armature modifier"},
{0, NULL, 0, NULL, NULL}
};
@@ -192,6 +197,8 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
return &RNA_MaintainVolumeConstraint;
case CONSTRAINT_TYPE_PYTHON:
return &RNA_PythonConstraint;
+ case CONSTRAINT_TYPE_ARMATURE:
+ return &RNA_ArmatureConstraint;
case CONSTRAINT_TYPE_ACTION:
return &RNA_ActionConstraint;
case CONSTRAINT_TYPE_LOCKTRACK:
@@ -235,6 +242,17 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
}
}
+static void rna_ConstraintTargetBone_target_set(PointerRNA *ptr, PointerRNA value)
+{
+ bConstraintTarget *tgt = (bConstraintTarget *)ptr->data;
+ Object *ob = value.data;
+
+ if (!ob || ob->type == OB_ARMATURE) {
+ id_lib_extern((ID *)ob);
+ tgt->tar = ob;
+ }
+}
+
static void rna_Constraint_name_set(PointerRNA *ptr, const char *value)
{
bConstraint *con = ptr->data;
@@ -260,10 +278,8 @@ static void rna_Constraint_name_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(NULL, "constraints", oldname, con->name);
}
-static char *rna_Constraint_path(PointerRNA *ptr)
+static char *rna_Constraint_do_compute_path(Object *ob, bConstraint *con)
{
- Object *ob = ptr->id.data;
- bConstraint *con = ptr->data;
bPoseChannel *pchan;
ListBase *lb = get_constraint_lb(ob, con, &pchan);
@@ -285,6 +301,55 @@ static char *rna_Constraint_path(PointerRNA *ptr)
}
}
+static char *rna_Constraint_path(PointerRNA *ptr)
+{
+ Object *ob = ptr->id.data;
+ bConstraint *con = ptr->data;
+
+ return rna_Constraint_do_compute_path(ob, con);
+}
+
+static bConstraint* rna_constraint_from_target(PointerRNA *ptr)
+{
+ Object *ob = ptr->id.data;
+ bConstraintTarget *tgt = ptr->data;
+
+ return BKE_constraint_find_from_target(ob, tgt);
+}
+
+static char *rna_ConstraintTarget_path(PointerRNA *ptr)
+{
+ Object *ob = ptr->id.data;
+ bConstraintTarget *tgt = ptr->data;
+ bConstraint *con = rna_constraint_from_target(ptr);
+ int index = -1;
+
+ if (con != NULL) {
+ if (con->type == CONSTRAINT_TYPE_ARMATURE) {
+ bArmatureConstraint *acon = (bArmatureConstraint*)con->data;
+ index = BLI_findindex(&acon->targets, tgt);
+ }
+ else if (con->type == CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *pcon = (bPythonConstraint*)con->data;
+ index = BLI_findindex(&pcon->targets, tgt);
+ }
+ }
+
+ if (index >= 0) {
+ char *con_path = rna_Constraint_do_compute_path(ob, con);
+ char *result = BLI_sprintfN("%s.targets[%d]", con_path, index);
+
+ MEM_freeN(con_path);
+ return result;
+ }
+ else {
+ printf("%s: internal error, constraint '%s' of object '%s' does not contain the target\n",
+ __func__, con->name, ob->id.name);
+ }
+
+ return NULL;
+}
+
static void rna_Constraint_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
ED_object_constraint_tag_update(bmain, ptr->id.data, ptr->data);
@@ -295,6 +360,16 @@ static void rna_Constraint_dependency_update(Main *bmain, Scene *UNUSED(scene),
ED_object_constraint_dependency_tag_update(bmain, ptr->id.data, ptr->data);
}
+static void rna_ConstraintTarget_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ED_object_constraint_tag_update(bmain, ptr->id.data, rna_constraint_from_target(ptr));
+}
+
+static void rna_ConstraintTarget_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ED_object_constraint_dependency_tag_update(bmain, ptr->id.data, rna_constraint_from_target(ptr));
+}
+
static void rna_Constraint_influence_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Object *ob = ptr->id.data;
@@ -360,6 +435,42 @@ static const EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSE
return space_object_items;
}
+static bConstraintTarget *rna_ArmatureConstraint_target_new(ID *id, bConstraint *con, Main *bmain)
+{
+ bArmatureConstraint *acon = (bArmatureConstraint*)con->data;
+ bConstraintTarget *tgt = MEM_callocN(sizeof(bConstraintTarget), "Constraint Target");
+
+ tgt->weight = 1.0f;
+ BLI_addtail(&acon->targets, tgt);
+
+ ED_object_constraint_dependency_tag_update(bmain, (Object*)id, con);
+ return tgt;
+}
+
+static void rna_ArmatureConstraint_target_remove(ID *id, bConstraint *con, Main *bmain, ReportList *reports, PointerRNA *target_ptr)
+{
+ bArmatureConstraint *acon = (bArmatureConstraint*)con->data;
+ bConstraintTarget *tgt = target_ptr->data;
+
+ if (BLI_findindex(&acon->targets, tgt) < 0) {
+ BKE_reportf(reports, RPT_ERROR, "Target is not in the constraint target list");
+ return;
+ }
+
+ BLI_freelinkN(&acon->targets, tgt);
+
+ ED_object_constraint_dependency_tag_update(bmain, (Object*)id, con);
+}
+
+static void rna_ArmatureConstraint_target_clear(ID *id, bConstraint *con, Main *bmain)
+{
+ bArmatureConstraint *acon = (bArmatureConstraint*)con->data;
+
+ BLI_freelistN(&acon->targets);
+
+ ED_object_constraint_dependency_tag_update(bmain, (Object*)id, con);
+}
+
static void rna_ActionConstraint_minmax_range(PointerRNA *ptr, float *min, float *max,
float *UNUSED(softmin), float *UNUSED(softmax))
{
@@ -564,16 +675,58 @@ static void rna_def_constraint_target_common(StructRNA *srna)
static void rna_def_constrainttarget(BlenderRNA *brna)
{
StructRNA *srna;
+ PropertyRNA *prop;
srna = RNA_def_struct(brna, "ConstraintTarget", NULL);
RNA_def_struct_ui_text(srna, "Constraint Target", "Target object for multi-target constraints");
+ RNA_def_struct_path_func(srna, "rna_ConstraintTarget_path");
RNA_def_struct_sdna(srna, "bConstraintTarget");
- rna_def_constraint_target_common(srna);
+ 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");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_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", "Armature bone, mesh or lattice vertex group, ...");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_dependency_update");
/* space, flag and type still to do */
}
+static void rna_def_constrainttarget_bone(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ConstraintTargetBone", NULL);
+ RNA_def_struct_ui_text(srna, "Constraint Target Bone", "Target bone for multi-target constraints");
+ RNA_def_struct_path_func(srna, "rna_ConstraintTarget_path");
+ RNA_def_struct_sdna(srna, "bConstraintTarget");
+
+ 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 armature");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_ConstraintTargetBone_target_set", NULL, "rna_Armature_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_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", "Target armature bone");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_dependency_update");
+
+ prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "weight");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Blend Weight", "Blending weight of this bone");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_update");
+}
+
static void rna_def_constraint_childof(BlenderRNA *brna)
{
StructRNA *srna;
@@ -673,6 +826,70 @@ static void rna_def_constraint_python(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Script Error", "The linked Python script has thrown an error");
}
+
+static void rna_def_constraint_armature_deform_targets(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "ArmatureConstraintTargets");
+ srna = RNA_def_struct(brna, "ArmatureConstraintTargets", NULL);
+ RNA_def_struct_sdna(srna, "bConstraint");
+ RNA_def_struct_ui_text(srna, "Armature Deform Constraint Targets", "Collection of target bones and weights");
+
+ func = RNA_def_function(srna, "new", "rna_ArmatureConstraint_target_new");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Add a new target to the constraint");
+ parm = RNA_def_pointer(func, "target", "ConstraintTargetBone", "", "New target bone");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_ArmatureConstraint_target_remove");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Delete target from the constraint");
+ parm = RNA_def_pointer(func, "target", "ConstraintTargetBone", "", "Target to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "clear", "rna_ArmatureConstraint_target_clear");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Delete all targets from object");
+}
+
+static void rna_def_constraint_armature_deform(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ArmatureConstraint", "Constraint");
+ RNA_def_struct_ui_text(srna, "Armature Constraint", "Applies transformations done by the Armature modifier");
+ RNA_def_struct_sdna_from(srna, "bArmatureConstraint", "data");
+
+ prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "targets", NULL);
+ RNA_def_property_struct_type(prop, "ConstraintTargetBone");
+ RNA_def_property_ui_text(prop, "Targets", "Target Bones");
+ rna_def_constraint_armature_deform_targets(brna, prop);
+
+ prop = RNA_def_property(srna, "use_deform_preserve_volume", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_ARMATURE_QUATERNION);
+ RNA_def_property_ui_text(prop, "Preserve Volume", "Deform rotation interpolation with quaternions");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_ARMATURE_ENVELOPE);
+ RNA_def_property_ui_text(prop, "Use Envelopes",
+ "Multiply weights by envelope for all bones, instead of acting like Vertex Group based blending. "
+ "The specified weights are still used, and only the listed bones are considered");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_current_location", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_ARMATURE_CUR_LOCATION);
+ RNA_def_property_ui_text(prop, "Use Current Location",
+ "Use the current bone location for envelopes and choosing B-Bone segments instead of rest position");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+}
+
static void rna_def_constraint_kinematic(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2465,9 +2682,11 @@ void RNA_def_constraint(BlenderRNA *brna)
/* pointers */
rna_def_constrainttarget(brna);
+ rna_def_constrainttarget_bone(brna);
rna_def_constraint_childof(brna);
rna_def_constraint_python(brna);
+ rna_def_constraint_armature_deform(brna);
rna_def_constraint_stretch_to(brna);
rna_def_constraint_follow_path(brna);
rna_def_constraint_locked_track(brna);