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:
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py23
-rw-r--r--source/blender/blenkernel/BKE_constraint.h4
-rw-r--r--source/blender/blenkernel/intern/constraint.c304
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c8
-rw-r--r--source/blender/editors/armature/armature_add.c17
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h13
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c29
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c21
-rw-r--r--tests/python/bl_constraints.py74
9 files changed, 398 insertions, 95 deletions
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index f46e9f9727f..71a7b056d07 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -85,14 +85,23 @@ class ConstraintButtonsPanel(Panel):
row.operator("constraint.disable_keep_transform", text="", icon='CANCEL')
@staticmethod
- def space_template(layout, con, target=True, owner=True):
+ def space_template(layout, con, target=True, owner=True, separator=True):
if target or owner:
- layout.separator()
+ if separator:
+ layout.separator()
if target:
layout.prop(con, "target_space", text="Target")
if owner:
layout.prop(con, "owner_space", text="Owner")
+ if con.target_space == 'CUSTOM' or con.owner_space == 'CUSTOM':
+ col = layout.column()
+ col.prop(con, "space_object")
+ if con.space_object and con.space_object.type == 'ARMATURE':
+ col.prop_search(con, "space_subtarget", con.space_object.data, "bones", text="Bone")
+ elif con.space_object and con.space_object.type in {'MESH', 'LATTICE'}:
+ col.prop_search(con, "space_subtarget", con.space_object, "vertex_groups", text="Vertex Group")
+
@staticmethod
def target_template(layout, con, subtargets=True):
col = layout.column()
@@ -237,7 +246,7 @@ class ConstraintButtonsPanel(Panel):
row.label(icon="BLANK1")
layout.prop(con, "use_transform_limit")
- layout.prop(con, "owner_space")
+ self.space_template(layout, con, target=False, owner=True)
self.draw_influence(layout, con)
@@ -306,7 +315,7 @@ class ConstraintButtonsPanel(Panel):
row.prop_decorator(con, "max_z")
layout.prop(con, "use_transform_limit")
- layout.prop(con, "owner_space")
+ self.space_template(layout, con, target=False, owner=True)
self.draw_influence(layout, con)
@@ -375,7 +384,7 @@ class ConstraintButtonsPanel(Panel):
row.prop_decorator(con, "max_z")
layout.prop(con, "use_transform_limit")
- layout.prop(con, "owner_space")
+ self.space_template(layout, con, target=False, owner=True)
self.draw_influence(layout, con)
@@ -483,7 +492,7 @@ class ConstraintButtonsPanel(Panel):
layout.prop(con, "volume")
- layout.prop(con, "owner_space")
+ self.space_template(layout, con, target=False, owner=True)
self.draw_influence(layout, con)
@@ -1117,7 +1126,7 @@ class ConstraintButtonsSubPanel(Panel):
col = layout.column()
col.active = not con.use_eval_time
col.prop(con, "transform_channel", text="Channel")
- col.prop(con, "target_space")
+ ConstraintButtonsPanel.space_template(col, con, target=True, owner=False, separator=False)
sub = col.column(align=True)
sub.prop(con, "min", text="Range Min")
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index e5c4535560d..4b9f480e091 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -56,6 +56,8 @@ typedef struct bConstraintOb {
float matrix[4][4];
/** original matrix (before constraint solving) */
float startmat[4][4];
+ /** space matrix for custom object space */
+ float space_obj_world_matrix[4][4];
/** type of owner */
short type;
@@ -203,6 +205,7 @@ void BKE_constraints_clear_evalob(struct bConstraintOb *cob);
void BKE_constraint_mat_convertspace(struct Object *ob,
struct bPoseChannel *pchan,
+ struct bConstraintOb *cob,
float mat[4][4],
short from,
short to,
@@ -221,6 +224,7 @@ void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
struct bConstraintOb *ob,
struct ListBase *targets,
float ctime);
+void BKE_constraint_custom_object_space_get(float r_mat[4][4], struct bConstraint *con);
void BKE_constraints_solve(struct Depsgraph *depsgraph,
struct ListBase *conlist,
struct bConstraintOb *cob,
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 5497065bb34..1a16f1d3c6e 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -261,8 +261,13 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob)
* of a matrix from one space to another for constraint evaluation.
* For now, this is only implemented for Objects and PoseChannels.
*/
-void BKE_constraint_mat_convertspace(
- Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale)
+void BKE_constraint_mat_convertspace(Object *ob,
+ bPoseChannel *pchan,
+ bConstraintOb *cob,
+ float mat[4][4],
+ short from,
+ short to,
+ const bool keep_scale)
{
float diff_mat[4][4];
float imat[4][4];
@@ -282,25 +287,30 @@ void BKE_constraint_mat_convertspace(
switch (from) {
case CONSTRAINT_SPACE_WORLD: /* ---------- FROM WORLDSPACE ---------- */
{
- /* world to pose */
- invert_m4_m4(imat, ob->obmat);
- mul_m4_m4m4(mat, imat, mat);
-
- /* use pose-space as stepping stone for other spaces... */
- if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) {
- /* call self with slightly different values */
- BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
+ if (to == CONSTRAINT_SPACE_CUSTOM) {
+ /* World to custom. */
+ BLI_assert(cob);
+ invert_m4_m4(imat, cob->space_obj_world_matrix);
+ mul_m4_m4m4(mat, imat, mat);
+ }
+ else {
+ /* World to pose. */
+ invert_m4_m4(imat, ob->obmat);
+ mul_m4_m4m4(mat, imat, mat);
+
+ /* Use pose-space as stepping stone for other spaces. */
+ if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) {
+ /* Call self with slightly different values. */
+ BKE_constraint_mat_convertspace(
+ ob, pchan, cob, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
+ }
}
break;
}
case CONSTRAINT_SPACE_POSE: /* ---------- FROM POSESPACE ---------- */
{
- /* pose to world */
- if (to == CONSTRAINT_SPACE_WORLD) {
- mul_m4_m4m4(mat, ob->obmat, mat);
- }
/* pose to local */
- else if (to == CONSTRAINT_SPACE_LOCAL) {
+ if (to == CONSTRAINT_SPACE_LOCAL) {
if (pchan->bone) {
BKE_armature_mat_pose_to_bone(pchan, mat, mat);
}
@@ -312,6 +322,16 @@ void BKE_constraint_mat_convertspace(
mul_m4_m4m4(mat, imat, mat);
}
}
+ else {
+ /* Pose to world. */
+ mul_m4_m4m4(mat, ob->obmat, mat);
+ /* Use world-space as stepping stone for other spaces. */
+ if (to != CONSTRAINT_SPACE_WORLD) {
+ /* Call self with slightly different values. */
+ BKE_constraint_mat_convertspace(
+ ob, pchan, cob, mat, CONSTRAINT_SPACE_WORLD, to, keep_scale);
+ }
+ }
break;
}
case CONSTRAINT_SPACE_LOCAL: /* ------------ FROM LOCALSPACE --------- */
@@ -323,9 +343,10 @@ void BKE_constraint_mat_convertspace(
}
/* use pose-space as stepping stone for other spaces */
- if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) {
+ if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL, CONSTRAINT_SPACE_CUSTOM)) {
/* call self with slightly different values */
- BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, cob, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
}
break;
}
@@ -337,9 +358,24 @@ void BKE_constraint_mat_convertspace(
}
/* use pose-space as stepping stone for other spaces */
- if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) {
+ if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_CUSTOM)) {
/* call self with slightly different values */
- BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, cob, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
+ }
+ break;
+ }
+ case CONSTRAINT_SPACE_CUSTOM: /* -------------- FROM CUSTOM SPACE ---------- */
+ {
+ /* Custom to world. */
+ BLI_assert(cob);
+ mul_m4_m4m4(mat, cob->space_obj_world_matrix, mat);
+
+ /* Use world-space as stepping stone for other spaces. */
+ if (to != CONSTRAINT_SPACE_WORLD) {
+ /* Call self with slightly different values. */
+ BKE_constraint_mat_convertspace(
+ ob, pchan, cob, mat, CONSTRAINT_SPACE_WORLD, to, keep_scale);
}
break;
}
@@ -347,37 +383,44 @@ void BKE_constraint_mat_convertspace(
}
else {
/* objects */
- if (from == CONSTRAINT_SPACE_WORLD && to == CONSTRAINT_SPACE_LOCAL) {
- /* check if object has a parent */
- if (ob->parent) {
- /* 'subtract' parent's effects from owner */
- mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv);
- invert_m4_m4_safe(imat, diff_mat);
- mul_m4_m4m4(mat, imat, mat);
- }
- else {
- /* Local space in this case will have to be defined as local to the owner's
- * transform-property-rotated axes. So subtract this rotation component.
- */
- /* XXX This is actually an ugly hack, local space of a parent-less object *is* the same as
- * global space!
- * Think what we want actually here is some kind of 'Final Space', i.e
- * . once transformations are applied - users are often confused about this too,
- * this is not consistent with bones
- * local space either... Meh :|
- * --mont29
- */
- BKE_object_to_mat4(ob, diff_mat);
- if (!keep_scale) {
- normalize_m4(diff_mat);
+ if (from == CONSTRAINT_SPACE_WORLD) {
+ if (to == CONSTRAINT_SPACE_LOCAL) {
+ /* Check if object has a parent. */
+ if (ob->parent) {
+ /* 'subtract' parent's effects from owner. */
+ mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv);
+ invert_m4_m4_safe(imat, diff_mat);
+ mul_m4_m4m4(mat, imat, mat);
}
- zero_v3(diff_mat[3]);
+ else {
+ /* Local space in this case will have to be defined as local to the owner's
+ * transform-property-rotated axes. So subtract this rotation component.
+ */
+ /* XXX This is actually an ugly hack, local space of a parent-less object *is* the same
+ * as global space! Think what we want actually here is some kind of 'Final Space', i.e
+ * . once transformations are applied - users are often confused about this too,
+ * this is not consistent with bones
+ * local space either... Meh :|
+ * --mont29
+ */
+ BKE_object_to_mat4(ob, diff_mat);
+ if (!keep_scale) {
+ normalize_m4(diff_mat);
+ }
+ zero_v3(diff_mat[3]);
- invert_m4_m4_safe(imat, diff_mat);
+ invert_m4_m4_safe(imat, diff_mat);
+ mul_m4_m4m4(mat, imat, mat);
+ }
+ }
+ else if (to == CONSTRAINT_SPACE_CUSTOM) {
+ /* 'subtract' custom objects's effects from owner. */
+ BLI_assert(cob);
+ invert_m4_m4_safe(imat, cob->space_obj_world_matrix);
mul_m4_m4m4(mat, imat, mat);
}
}
- else if (from == CONSTRAINT_SPACE_LOCAL && to == CONSTRAINT_SPACE_WORLD) {
+ else if (from == CONSTRAINT_SPACE_LOCAL) {
/* check that object has a parent - otherwise this won't work */
if (ob->parent) {
/* 'add' parent's effect back to owner */
@@ -397,6 +440,24 @@ void BKE_constraint_mat_convertspace(
mul_m4_m4m4(mat, diff_mat, mat);
}
+ if (to == CONSTRAINT_SPACE_CUSTOM) {
+ /* 'subtract' objects's effects from owner. */
+ BLI_assert(cob);
+ invert_m4_m4_safe(imat, cob->space_obj_world_matrix);
+ mul_m4_m4m4(mat, imat, mat);
+ }
+ }
+ else if (from == CONSTRAINT_SPACE_CUSTOM) {
+ /* Custom to world. */
+ BLI_assert(cob);
+ mul_m4_m4m4(mat, cob->space_obj_world_matrix, mat);
+
+ /* Use world-space as stepping stone for other spaces. */
+ if (to != CONSTRAINT_SPACE_WORLD) {
+ /* Call self with slightly different values. */
+ BKE_constraint_mat_convertspace(
+ ob, pchan, cob, mat, CONSTRAINT_SPACE_WORLD, to, keep_scale);
+ }
}
}
}
@@ -573,6 +634,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
/* The cases where the target can be object data have not been implemented */
static void constraint_target_to_mat4(Object *ob,
const char *substring,
+ bConstraintOb *cob,
float mat[4][4],
short from,
short to,
@@ -582,7 +644,7 @@ static void constraint_target_to_mat4(Object *ob,
/* Case OBJECT */
if (substring[0] == '\0') {
copy_m4_m4(mat, ob->obmat);
- BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
+ BKE_constraint_mat_convertspace(ob, NULL, cob, mat, from, to, false);
}
/* Case VERTEXGROUP */
/* Current method just takes the average location of all the points in the
@@ -595,11 +657,11 @@ static void constraint_target_to_mat4(Object *ob,
*/
else if (ob->type == OB_MESH) {
contarget_get_mesh_mat(ob, substring, mat);
- BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
+ BKE_constraint_mat_convertspace(ob, NULL, cob, mat, from, to, false);
}
else if (ob->type == OB_LATTICE) {
contarget_get_lattice_mat(ob, substring, mat);
- BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
+ BKE_constraint_mat_convertspace(ob, NULL, cob, mat, from, to, false);
}
/* Case BONE */
else {
@@ -662,7 +724,7 @@ static void constraint_target_to_mat4(Object *ob,
}
/* convert matrix space as required */
- BKE_constraint_mat_convertspace(ob, pchan, mat, from, to, false);
+ BKE_constraint_mat_convertspace(ob, pchan, cob, mat, from, to, false);
}
}
@@ -705,13 +767,14 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
*/
static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
bConstraint *con,
- bConstraintOb *UNUSED(cob),
+ bConstraintOb *cob,
bConstraintTarget *ct,
float UNUSED(ctime))
{
if (VALID_CONS_TARGET(ct)) {
constraint_target_to_mat4(ct->tar,
ct->subtarget,
+ cob,
ct->matrix,
CONSTRAINT_SPACE_WORLD,
ct->space,
@@ -727,13 +790,14 @@ static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
*/
static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
bConstraint *con,
- bConstraintOb *UNUSED(cob),
+ bConstraintOb *cob,
bConstraintTarget *ct,
float UNUSED(ctime))
{
if (VALID_CONS_TARGET(ct)) {
constraint_target_to_mat4(ct->tar,
ct->subtarget,
+ cob,
ct->matrix,
CONSTRAINT_SPACE_WORLD,
ct->space,
@@ -844,6 +908,32 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
} \
(void)0
+static void custom_space_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+ func(con, (ID **)&con->space_object, false, userdata);
+}
+
+static int get_space_tar(bConstraint *con, ListBase *list)
+{
+ if (!con || !list ||
+ (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) {
+ return 0;
+ }
+ bConstraintTarget *ct;
+ SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, list);
+ return 1;
+}
+
+static void flush_space_tar(bConstraint *con, ListBase *list, bool no_copy)
+{
+ if (!con || !list ||
+ (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) {
+ return;
+ }
+ bConstraintTarget *ct = (bConstraintTarget *)list->last;
+ SINGLETARGET_FLUSH_TARS(con, con->space_object, con->space_subtarget, ct, list, no_copy);
+}
+
/* --------- ChildOf Constraint ------------ */
static void childof_new_data(void *cdata)
@@ -1030,6 +1120,8 @@ static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *use
/* target only */
func(con, (ID **)&data->tar, false, userdata);
+
+ custom_space_id_looper(con, func, userdata);
}
static int trackto_get_tars(bConstraint *con, ListBase *list)
@@ -1041,7 +1133,7 @@ static int trackto_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
+ return 1 + get_space_tar(con, list);
}
return 0;
@@ -1055,6 +1147,7 @@ static void trackto_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ flush_space_tar(con, list, no_copy);
}
}
@@ -1262,6 +1355,7 @@ static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
if (VALID_CONS_TARGET(ct)) {
constraint_target_to_mat4(ct->tar,
ct->subtarget,
+ cob,
ct->matrix,
CONSTRAINT_SPACE_WORLD,
ct->space,
@@ -1533,11 +1627,11 @@ static bConstraintTypeInfo CTI_LOCLIMIT = {
"Limit Location", /* name */
"bLocLimitConstraint", /* struct name */
NULL, /* free data */
- NULL, /* id looper */
+ custom_space_id_looper, /* id looper */
NULL, /* copy data */
NULL, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
+ get_space_tar, /* get constraint targets */
+ flush_space_tar, /* flush constraint targets */
NULL, /* get target matrix */
loclimit_evaluate, /* evaluate */
};
@@ -1596,11 +1690,11 @@ static bConstraintTypeInfo CTI_ROTLIMIT = {
"Limit Rotation", /* name */
"bRotLimitConstraint", /* struct name */
NULL, /* free data */
- NULL, /* id looper */
+ custom_space_id_looper, /* id looper */
NULL, /* copy data */
NULL, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
+ get_space_tar, /* get constraint targets */
+ flush_space_tar, /* flush constraint targets */
NULL, /* get target matrix */
rotlimit_evaluate, /* evaluate */
};
@@ -1663,11 +1757,11 @@ static bConstraintTypeInfo CTI_SIZELIMIT = {
"Limit Scale", /* name */
"bSizeLimitConstraint", /* struct name */
NULL, /* free data */
- NULL, /* id looper */
+ custom_space_id_looper, /* id looper */
NULL, /* copy data */
NULL, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
+ get_space_tar, /* get constraint targets */
+ flush_space_tar, /* flush constraint targets */
NULL, /* get target matrix */
sizelimit_evaluate, /* evaluate */
};
@@ -1687,6 +1781,8 @@ static void loclike_id_looper(bConstraint *con, ConstraintIDFunc func, void *use
/* target only */
func(con, (ID **)&data->tar, false, userdata);
+
+ custom_space_id_looper(con, func, userdata);
}
static int loclike_get_tars(bConstraint *con, ListBase *list)
@@ -1698,7 +1794,7 @@ static int loclike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
+ return 1 + get_space_tar(con, list);
}
return 0;
@@ -1712,6 +1808,7 @@ static void loclike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ flush_space_tar(con, list, no_copy);
}
}
@@ -1784,6 +1881,8 @@ static void rotlike_id_looper(bConstraint *con, ConstraintIDFunc func, void *use
/* target only */
func(con, (ID **)&data->tar, false, userdata);
+
+ custom_space_id_looper(con, func, userdata);
}
static int rotlike_get_tars(bConstraint *con, ListBase *list)
@@ -1795,7 +1894,7 @@ static int rotlike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
+ return 1 + get_space_tar(con, list);
}
return 0;
@@ -1809,6 +1908,7 @@ static void rotlike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ flush_space_tar(con, list, no_copy);
}
}
@@ -1962,6 +2062,8 @@ static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *us
/* target only */
func(con, (ID **)&data->tar, false, userdata);
+
+ custom_space_id_looper(con, func, userdata);
}
static int sizelike_get_tars(bConstraint *con, ListBase *list)
@@ -1973,7 +2075,7 @@ static int sizelike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
+ return 1 + get_space_tar(con, list);
}
return 0;
@@ -1987,6 +2089,7 @@ static void sizelike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ flush_space_tar(con, list, no_copy);
}
}
@@ -2084,6 +2187,8 @@ static void translike_id_looper(bConstraint *con, ConstraintIDFunc func, void *u
/* target only */
func(con, (ID **)&data->tar, false, userdata);
+
+ custom_space_id_looper(con, func, userdata);
}
static int translike_get_tars(bConstraint *con, ListBase *list)
@@ -2095,7 +2200,7 @@ static int translike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
+ return 1 + get_space_tar(con, list);
}
return 0;
@@ -2109,6 +2214,7 @@ static void translike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ flush_space_tar(con, list, no_copy);
}
}
@@ -2212,11 +2318,11 @@ static bConstraintTypeInfo CTI_SAMEVOL = {
"Maintain Volume", /* name */
"bSameVolumeConstraint", /* struct name */
NULL, /* free data */
- NULL, /* id looper */
+ custom_space_id_looper, /* id looper */
NULL, /* copy data */
samevolume_new_data, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
+ get_space_tar, /* get constraint targets */
+ flush_space_tar, /* flush constraint targets */
NULL, /* get target matrix */
samevolume_evaluate, /* evaluate */
};
@@ -2282,7 +2388,7 @@ static void pycon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userd
/* Whether this approach is maintained remains to be seen (aligorith) */
static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
bConstraint *con,
- bConstraintOb *UNUSED(cob),
+ bConstraintOb *cob,
bConstraintTarget *ct,
float UNUSED(ctime))
{
@@ -2301,6 +2407,7 @@ static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
*/
constraint_target_to_mat4(ct->tar,
ct->subtarget,
+ cob,
ct->matrix,
CONSTRAINT_SPACE_WORLD,
ct->space,
@@ -2608,6 +2715,8 @@ static void actcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *user
/* action */
func(con, (ID **)&data->act, true, userdata);
+
+ custom_space_id_looper(con, func, userdata);
}
static int actcon_get_tars(bConstraint *con, ListBase *list)
@@ -2619,7 +2728,7 @@ static int actcon_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
+ return 1 + get_space_tar(con, list);
}
return 0;
@@ -2633,6 +2742,7 @@ static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ flush_space_tar(con, list, no_copy);
}
}
@@ -2660,6 +2770,7 @@ static void actcon_get_tarmat(struct Depsgraph *depsgraph,
/* get the transform matrix of the target */
constraint_target_to_mat4(ct->tar,
ct->subtarget,
+ cob,
tempmat,
CONSTRAINT_SPACE_WORLD,
ct->space,
@@ -3117,6 +3228,8 @@ static void distlimit_id_looper(bConstraint *con, ConstraintIDFunc func, void *u
/* target only */
func(con, (ID **)&data->tar, false, userdata);
+
+ custom_space_id_looper(con, func, userdata);
}
static int distlimit_get_tars(bConstraint *con, ListBase *list)
@@ -3128,7 +3241,7 @@ static int distlimit_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
+ return 1 + get_space_tar(con, list);
}
return 0;
@@ -3142,6 +3255,7 @@ static void distlimit_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ flush_space_tar(con, list, no_copy);
}
}
@@ -3470,6 +3584,8 @@ static void minmax_id_looper(bConstraint *con, ConstraintIDFunc func, void *user
/* target only */
func(con, (ID **)&data->tar, false, userdata);
+
+ custom_space_id_looper(con, func, userdata);
}
static int minmax_get_tars(bConstraint *con, ListBase *list)
@@ -3481,7 +3597,7 @@ static int minmax_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
+ return 1 + get_space_tar(con, list);
}
return 0;
@@ -3495,6 +3611,7 @@ static void minmax_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ flush_space_tar(con, list, no_copy);
}
}
@@ -3789,6 +3906,8 @@ static void transform_id_looper(bConstraint *con, ConstraintIDFunc func, void *u
/* target only */
func(con, (ID **)&data->tar, false, userdata);
+
+ custom_space_id_looper(con, func, userdata);
}
static int transform_get_tars(bConstraint *con, ListBase *list)
@@ -3800,7 +3919,7 @@ static int transform_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
+ return 1 + get_space_tar(con, list);
}
return 0;
@@ -3814,6 +3933,7 @@ static void transform_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ flush_space_tar(con, list, no_copy);
}
}
@@ -4122,7 +4242,7 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
* See T42447. */
unit_m4(mat);
BKE_constraint_mat_convertspace(
- cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true);
+ cob->ob, cob->pchan, cob, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true);
invert_m4(mat);
mul_mat3_m4_v3(mat, no);
@@ -6000,6 +6120,35 @@ void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
}
}
+void BKE_constraint_custom_object_space_get(float r_mat[4][4], bConstraint *con)
+{
+ if (!con ||
+ (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) {
+ return;
+ }
+ bConstraintTarget *ct;
+ ListBase target = {NULL, NULL};
+ SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, &target);
+
+ /* Basically default_get_tarmat but without the unused parameters. */
+ if (VALID_CONS_TARGET(ct)) {
+ constraint_target_to_mat4(ct->tar,
+ ct->subtarget,
+ NULL,
+ ct->matrix,
+ CONSTRAINT_SPACE_WORLD,
+ CONSTRAINT_SPACE_WORLD,
+ 0,
+ 0);
+ copy_m4_m4(r_mat, ct->matrix);
+ }
+ else {
+ unit_m4(r_mat);
+ }
+
+ SINGLETARGET_FLUSH_TARS(con, con->space_object, con->space_subtarget, ct, &target, true);
+}
+
/* ---------- Evaluation ----------- */
/* This function is called whenever constraints need to be evaluated. Currently, all
@@ -6048,12 +6197,15 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph,
*/
enf = con->enforce;
+ /* Get custom space matrix. */
+ BKE_constraint_custom_object_space_get(cob->space_obj_world_matrix, con);
+
/* make copy of world-space matrix pre-constraint for use with blending later */
copy_m4_m4(oldmat, cob->matrix);
/* move owner matrix into right space */
BKE_constraint_mat_convertspace(
- cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false);
+ cob->ob, cob->pchan, cob, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false);
/* prepare targets for constraint solving */
BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime);
@@ -6072,7 +6224,7 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph,
/* move owner back into world-space for next constraint/other business */
if ((con->flag & CONSTRAINT_SPACEONCE) == 0) {
BKE_constraint_mat_convertspace(
- cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false);
+ cob->ob, cob->pchan, cob, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false);
}
/* Interpolate the enforcement, to blend result of constraint into final owner transform
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index b11a3cb9457..1bce9ad8e35 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -411,7 +411,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
/* Extract transform just like how the constraints do it! */
copy_m4_m4(mat, pchan->pose_mat);
BKE_constraint_mat_convertspace(
- ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
+ ob, pchan, NULL, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
/* ... and from that, we get our transform. */
copy_v3_v3(tmp_loc, mat[3]);
@@ -437,7 +437,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
/* Extract transform just like how the constraints do it! */
copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace(
- ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
+ ob, NULL, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
/* ... and from that, we get our transform. */
copy_v3_v3(tmp_loc, mat[3]);
@@ -514,7 +514,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
/* Just like how the constraints do it! */
copy_m4_m4(mat, pchan->pose_mat);
BKE_constraint_mat_convertspace(
- ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
+ ob, pchan, NULL, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
}
else {
/* Specially calculate local matrix, since chan_mat is not valid
@@ -541,7 +541,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
/* Just like how the constraints do it! */
copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace(
- ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
+ ob, NULL, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
}
else {
/* Transforms to matrix. */
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index fde062b8454..af323bf91e4 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -453,10 +453,13 @@ static void updateDuplicateActionConstraintSettings(EditBone *dup_bone,
float mat[4][4];
+ bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = NULL};
+ BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon);
+
unit_m4(mat);
bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget);
BKE_constraint_mat_convertspace(
- ob, target_pchan, mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
+ ob, target_pchan, &cob, mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
float max_axis_val = 0;
int max_axis = 0;
@@ -605,8 +608,11 @@ static void updateDuplicateLocRotConstraintSettings(Object *ob,
unit_m4(local_mat);
+ bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
+ BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon);
+
BKE_constraint_mat_convertspace(
- ob, pchan, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
+ ob, pchan, &cob, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) {
/* Zero out any location translation */
@@ -657,9 +663,12 @@ static void updateDuplicateTransformConstraintSettings(Object *ob,
float target_mat[4][4], own_mat[4][4], imat[4][4];
+ bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
+ BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon);
+
unit_m4(own_mat);
BKE_constraint_mat_convertspace(
- ob, pchan, own_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
+ ob, pchan, &cob, own_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
/* ###Source map mirroring### */
float old_min, old_max;
@@ -717,7 +726,7 @@ static void updateDuplicateTransformConstraintSettings(Object *ob,
bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, trans->subtarget);
unit_m4(target_mat);
BKE_constraint_mat_convertspace(
- ob, target_pchan, target_mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
+ ob, target_pchan, &cob, target_mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
invert_m4_m4(imat, target_mat);
/* convert values into local object space */
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 70d33d9ff94..ddc1b3bd9d7 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -61,12 +61,17 @@ typedef struct bConstraint {
/** Space that target should be evaluated in (only used if 1 target). */
char tarspace;
- /** Constraint name, MAX_NAME. */
- char name[64];
-
/* An "expand" bit for each of the constraint's (sub)panels (uiPanelDataExpansion). */
short ui_expand_flag;
+ /** Object to use as target for Custom Space of owner. */
+ struct Object *space_object;
+ /** Subtarget for Custom Space of owner - pchan or vgroup name, MAX_ID_NAME-2. */
+ char space_subtarget[64];
+
+ /** Constraint name, MAX_NAME. */
+ char name[64];
+
/** Amount of influence exherted by constraint (0.0-1.0). */
float enforce;
/** Point along subtarget bone where the actual target is. 0=head (default for all), 1=tail. */
@@ -722,6 +727,8 @@ typedef enum eBConstraint_Flags {
typedef enum eBConstraint_SpaceTypes {
/** Default for all - worldspace. */
CONSTRAINT_SPACE_WORLD = 0,
+ /** For all - custom space. */
+ CONSTRAINT_SPACE_CUSTOM = 5,
/**
* For objects (relative to parent/without parent influence),
* for bones (along normals of bone, without parent/rest-positions).
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 1c84be5907b..170de68a038 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -200,6 +200,12 @@ static const EnumPropertyItem target_space_pchan_items[] = {
"World Space",
"The transformation of the target is evaluated relative to the world "
"coordinate system"},
+ {CONSTRAINT_SPACE_CUSTOM,
+ "CUSTOM",
+ 0,
+ "Custom Space",
+ "The transformation of the target is evaluated relative to a custom object/bone/vertex "
+ "group"},
{CONSTRAINT_SPACE_POSE,
"POSE",
0,
@@ -227,6 +233,11 @@ static const EnumPropertyItem owner_space_pchan_items[] = {
0,
"World Space",
"The constraint is applied relative to the world coordinate system"},
+ {CONSTRAINT_SPACE_CUSTOM,
+ "CUSTOM",
+ 0,
+ "Custom Space",
+ "The constraint is applied in local space of a custom object/bone/vertex group"},
{CONSTRAINT_SPACE_POSE,
"POSE",
0,
@@ -275,6 +286,12 @@ static const EnumPropertyItem space_object_items[] = {
0,
"World Space",
"The transformation of the target is evaluated relative to the world coordinate system"},
+ {CONSTRAINT_SPACE_CUSTOM,
+ "CUSTOM",
+ 0,
+ "Custom Space",
+ "The transformation of the target is evaluated relative to a custom object/bone/vertex "
+ "group"},
{CONSTRAINT_SPACE_LOCAL,
"LOCAL",
0,
@@ -3398,6 +3415,18 @@ void RNA_def_constraint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Target Space", "Space that target is evaluated in");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "space_object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "space_object");
+ RNA_def_property_ui_text(prop, "Object", "Object for Custom Space");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
+
+ prop = RNA_def_property(srna, "space_subtarget", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "space_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_Constraint_dependency_update");
+
/* flags */
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_OFF);
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index a04ad28f9c3..9fb883568c9 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -324,8 +324,27 @@ static void rna_Object_mat_convert_space(Object *ob,
return;
}
}
+ /* These checks are extra security, they should never occur. */
+ if (from == CONSTRAINT_SPACE_CUSTOM) {
+ const char *identifier = NULL;
+ RNA_enum_identifier(space_items, from, &identifier);
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "'from_space' '%s' is invalid when no custom space is given!",
+ identifier);
+ return;
+ }
+ if (to == CONSTRAINT_SPACE_CUSTOM) {
+ const char *identifier = NULL;
+ RNA_enum_identifier(space_items, to, &identifier);
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "'to_space' '%s' is invalid when no custom space is given!",
+ identifier);
+ return;
+ }
- BKE_constraint_mat_convertspace(ob, pchan, (float(*)[4])mat_ret, from, to, false);
+ BKE_constraint_mat_convertspace(ob, pchan, NULL, (float(*)[4])mat_ret, from, to, false);
}
static void rna_Object_calc_matrix_camera(Object *ob,
diff --git a/tests/python/bl_constraints.py b/tests/python/bl_constraints.py
index 4deabc5f541..279c896c6af 100644
--- a/tests/python/bl_constraints.py
+++ b/tests/python/bl_constraints.py
@@ -301,6 +301,80 @@ class ObjectSolverTest(AbstractConstraintTests):
self.matrix_test('Object Solver.owner', initial_matrix)
+class CustomSpaceTest(AbstractConstraintTests):
+ layer_collection = 'Custom Space'
+
+ def test_loc_like_object(self):
+ """Custom Space: basic custom space evaluation for objects"""
+ loc_like_constraint = bpy.data.objects["Custom Space.object.owner"].constraints["Copy Location"]
+ loc_like_constraint.use_x = True
+ loc_like_constraint.use_y = True
+ loc_like_constraint.use_z = True
+ self.matrix_test('Custom Space.object.owner', Matrix((
+ (1.0, 0.0, -2.9802322387695312e-08, -0.01753106713294983),
+ (0.0, 1.0, 0.0, -0.08039519190788269),
+ (-2.9802322387695312e-08, 5.960464477539063e-08, 1.0, 0.1584688425064087),
+ (0.0, 0.0, 0.0, 1.0),
+ )))
+ loc_like_constraint.use_x = False
+ self.matrix_test('Custom Space.object.owner', Matrix((
+ (1.0, 0.0, -2.9802322387695312e-08, 0.18370598554611206),
+ (0.0, 1.0, 0.0, 0.47120195627212524),
+ (-2.9802322387695312e-08, 5.960464477539063e-08, 1.0, -0.16521614789962769),
+ (0.0, 0.0, 0.0, 1.0),
+ )))
+ loc_like_constraint.use_y = False
+ self.matrix_test('Custom Space.object.owner', Matrix((
+ (1.0, 0.0, -2.9802322387695312e-08, -0.46946945786476135),
+ (0.0, 1.0, 0.0, 0.423120379447937),
+ (-2.9802322387695312e-08, 5.960464477539063e-08, 1.0, -0.6532361507415771),
+ (0.0, 0.0, 0.0, 1.0),
+ )))
+ loc_like_constraint.use_z = False
+ loc_like_constraint.use_y = True
+ self.matrix_test('Custom Space.object.owner', Matrix((
+ (1.0, 0.0, -2.9802322387695312e-08, -0.346824586391449),
+ (0.0, 1.0, 0.0, 1.0480815172195435),
+ (-2.9802322387695312e-08, 5.960464477539063e-08, 1.0, 0.48802000284194946),
+ (0.0, 0.0, 0.0, 1.0),
+ )))
+
+ def test_loc_like_armature(self):
+ """Custom Space: basic custom space evaluation for bones"""
+ loc_like_constraint = bpy.data.objects["Custom Space.armature.owner"].pose.bones["Bone"].constraints["Copy Location"]
+ loc_like_constraint.use_x = True
+ loc_like_constraint.use_y = True
+ loc_like_constraint.use_z = True
+ self.bone_matrix_test('Custom Space.armature.owner', 'Bone', Matrix((
+ (0.4556015729904175, -0.03673229366540909, -0.8894257545471191, -0.01753103733062744),
+ (-0.45956411957740784, -0.8654094934463501, -0.19966775178909302, -0.08039522171020508),
+ (-0.762383222579956, 0.49971696734428406, -0.4111628830432892, 0.1584688425064087),
+ (0.0, 0.0, 0.0, 1.0),
+ )))
+ loc_like_constraint.use_x = False
+ self.bone_matrix_test('Custom Space.armature.owner', 'Bone', Matrix((
+ (0.4556015729904175, -0.03673229366540909, -0.8894257545471191, -0.310153603553772),
+ (-0.45956411957740784, -0.8654094934463501, -0.19966775178909302, -0.8824828863143921),
+ (-0.762383222579956, 0.49971696734428406, -0.4111628830432892, 0.629145085811615),
+ (0.0, 0.0, 0.0, 1.0),
+ )))
+ loc_like_constraint.use_y = False
+ self.bone_matrix_test('Custom Space.armature.owner', 'Bone', Matrix((
+ (0.4556015729904175, -0.03673229366540909, -0.8894257545471191, -1.0574829578399658),
+ (-0.45956411957740784, -0.8654094934463501, -0.19966775178909302, -0.937495231628418),
+ (-0.762383222579956, 0.49971696734428406, -0.4111628830432892, 0.07077804207801819),
+ (0.0, 0.0, 0.0, 1.0),
+ )))
+ loc_like_constraint.use_z = False
+ loc_like_constraint.use_y = True
+ self.bone_matrix_test('Custom Space.armature.owner', 'Bone', Matrix((
+ (0.4556015729904175, -0.03673229366540909, -0.8894257545471191, -0.25267064571380615),
+ (-0.45956411957740784, -0.8654094934463501, -0.19966775178909302, -0.9449876546859741),
+ (-0.762383222579956, 0.49971696734428406, -0.4111628830432892, 0.5583670735359192),
+ (0.0, 0.0, 0.0, 1.0),
+ )))
+
+
def main():
global args
import argparse