Compare commits
2 Commits
tmp-ocio-v
...
temp-angav
Author | SHA1 | Date | |
---|---|---|---|
0c25ee9f26 | |||
![]() |
b5a32ee650 |
@@ -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")
|
||||
|
@@ -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,11 +205,14 @@ 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,
|
||||
const bool keep_scale);
|
||||
|
||||
int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *list);
|
||||
void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *list, bool no_copy);
|
||||
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct bConstraint *con,
|
||||
@@ -221,6 +226,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_init(struct bConstraintOb *cob, struct bConstraint *con);
|
||||
void BKE_constraints_solve(struct Depsgraph *depsgraph,
|
||||
struct ListBase *conlist,
|
||||
struct bConstraintOb *cob,
|
||||
|
@@ -992,13 +992,10 @@ void BKE_pose_channels_remove(Object *ob,
|
||||
else {
|
||||
/* Maybe something the bone references is being removed instead? */
|
||||
for (con = pchan->constraints.first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
if (ct->tar == ob) {
|
||||
if (ct->subtarget[0]) {
|
||||
@@ -1010,9 +1007,7 @@ void BKE_pose_channels_remove(Object *ob,
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2381,22 +2381,17 @@ static void pose_proxy_sync(Object *ob, Object *from, int layer_protected)
|
||||
|
||||
/* constraints - set target ob pointer to own object */
|
||||
for (con = pchanw.constraints.first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
if (ct->tar == from) {
|
||||
ct->tar = ob;
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
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, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
|
||||
/* 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,11 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
|
||||
} \
|
||||
(void)0
|
||||
|
||||
static bool is_custom_space_needed(bConstraint *con)
|
||||
{
|
||||
return con->ownspace == CONSTRAINT_SPACE_CUSTOM || con->tarspace == CONSTRAINT_SPACE_CUSTOM;
|
||||
}
|
||||
|
||||
/* --------- ChildOf Constraint ------------ */
|
||||
|
||||
static void childof_new_data(void *cdata)
|
||||
@@ -1262,6 +1331,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,
|
||||
@@ -2276,7 +2346,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))
|
||||
{
|
||||
@@ -2295,6 +2365,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,
|
||||
@@ -2654,6 +2725,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,
|
||||
@@ -4116,7 +4188,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);
|
||||
|
||||
@@ -5333,6 +5405,19 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con),
|
||||
}
|
||||
}
|
||||
|
||||
/** Helper function to invoke the id_looper callback, including custom space. */
|
||||
static void con_invoke_id_looper(const bConstraintTypeInfo *cti,
|
||||
bConstraint *con,
|
||||
ConstraintIDFunc func,
|
||||
void *userdata)
|
||||
{
|
||||
if (cti->id_looper) {
|
||||
cti->id_looper(con, func, userdata);
|
||||
}
|
||||
|
||||
func(con, (ID **)&con->space_object, false, userdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free data of a specific constraint if it has any info.
|
||||
* be sure to run #BIK_clear_data() when freeing an IK constraint,
|
||||
@@ -5350,8 +5435,8 @@ void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
|
||||
}
|
||||
|
||||
/* unlink the referenced resources it uses */
|
||||
if (do_id_user && cti->id_looper) {
|
||||
cti->id_looper(con, con_unlink_refs_cb, NULL);
|
||||
if (do_id_user) {
|
||||
con_invoke_id_looper(cti, con, con_unlink_refs_cb, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5518,9 +5603,12 @@ static bConstraint *add_new_constraint(Object *ob,
|
||||
return con;
|
||||
}
|
||||
|
||||
bool BKE_constraint_target_uses_bbone(struct bConstraint *con,
|
||||
struct bConstraintTarget *UNUSED(ct))
|
||||
bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *ct)
|
||||
{
|
||||
if (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (con->flag & CONSTRAINT_BBONE_SHAPE) || (con->type == CONSTRAINT_TYPE_ARMATURE);
|
||||
}
|
||||
|
||||
@@ -5554,9 +5642,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
|
||||
if (cti) {
|
||||
if (cti->id_looper) {
|
||||
cti->id_looper(con, func, userdata);
|
||||
}
|
||||
con_invoke_id_looper(cti, con, func, userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5608,16 +5694,14 @@ static void constraint_copy_data_ex(bConstraint *dst,
|
||||
}
|
||||
|
||||
/* Fix usercounts for all referenced data that need it. */
|
||||
if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
||||
cti->id_looper(dst, con_fix_copied_refs_cb, NULL);
|
||||
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
||||
con_invoke_id_looper(cti, dst, con_fix_copied_refs_cb, NULL);
|
||||
}
|
||||
|
||||
/* for proxies we don't want to make extern */
|
||||
if (do_extern) {
|
||||
/* go over used ID-links for this constraint to ensure that they are valid for proxies */
|
||||
if (cti->id_looper) {
|
||||
cti->id_looper(dst, con_extern_cb, NULL);
|
||||
}
|
||||
con_invoke_id_looper(cti, dst, con_extern_cb, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5872,6 +5956,61 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
|
||||
|
||||
/* -------- Target-Matrix Stuff ------- */
|
||||
|
||||
/** Retrieves the list of all constraint targets, including the custom space target.
|
||||
* Must be followed by a call to BKE_constraint_targets_flush to free memory. */
|
||||
int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *list)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (con && list) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
|
||||
if (cti) {
|
||||
if (cti->get_constraint_targets) {
|
||||
count = cti->get_constraint_targets(con, list);
|
||||
}
|
||||
|
||||
/* Add the custom target. */
|
||||
if (is_custom_space_needed(con)) {
|
||||
bConstraintTarget *ct;
|
||||
SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, list);
|
||||
ct->space = CONSTRAINT_SPACE_WORLD;
|
||||
ct->flag |= CONSTRAINT_TAR_CUSTOM_SPACE;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/** Copies data from the list produced by BKE_constraint_targets_get back and frees memory. */
|
||||
void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *list, bool no_copy)
|
||||
{
|
||||
if (con && list) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
|
||||
if (cti) {
|
||||
/* Remove the custom target. */
|
||||
if (is_custom_space_needed(con)) {
|
||||
bConstraintTarget *ct = (bConstraintTarget *)list->last;
|
||||
BLI_assert(ct && (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE));
|
||||
|
||||
if (!no_copy) {
|
||||
con->space_object = ct->tar;
|
||||
BLI_strncpy(con->space_subtarget, ct->subtarget, sizeof(con->space_subtarget));
|
||||
}
|
||||
|
||||
BLI_freelinkN(list, ct);
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, list, no_copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is a relic from the prior implementations of the constraints system, when all
|
||||
* constraints either had one or no targets. It used to be called during the main constraint
|
||||
* solving loop, but is now only used for the remaining cases for a few constraints.
|
||||
@@ -5930,6 +6069,9 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the custom space for use in calculating the matrices. */
|
||||
BKE_constraint_custom_object_space_init(cob, con);
|
||||
|
||||
/* get targets - we only need the first one though (and there should only be one) */
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
@@ -5994,6 +6136,26 @@ void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize the Custom Space matrix inside cob. */
|
||||
void BKE_constraint_custom_object_space_init(bConstraintOb *cob, bConstraint *con)
|
||||
{
|
||||
if (con && con->space_object && is_custom_space_needed(con)) {
|
||||
/* Basically default_get_tarmat but without the unused parameters. */
|
||||
constraint_target_to_mat4(con->space_object,
|
||||
con->space_subtarget,
|
||||
NULL,
|
||||
cob->space_obj_world_matrix,
|
||||
CONSTRAINT_SPACE_WORLD,
|
||||
CONSTRAINT_SPACE_WORLD,
|
||||
0,
|
||||
0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unit_m4(cob->space_obj_world_matrix);
|
||||
}
|
||||
|
||||
/* ---------- Evaluation ----------- */
|
||||
|
||||
/* This function is called whenever constraints need to be evaluated. Currently, all
|
||||
@@ -6042,12 +6204,15 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph,
|
||||
*/
|
||||
enf = con->enforce;
|
||||
|
||||
/* Initialize the custom space for use in calculating the matrices. */
|
||||
BKE_constraint_custom_object_space_init(cob, 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);
|
||||
@@ -6066,7 +6231,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
|
||||
|
@@ -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. */
|
||||
|
@@ -2242,22 +2242,17 @@ static void copy_object_pose(Object *obn, const Object *ob, const int flag)
|
||||
* BKE_library_remap stuff, but...
|
||||
* the flush_constraint_targets callback am not sure about, so will delay that for now. */
|
||||
for (con = chan->constraints.first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
if (ct->tar == ob) {
|
||||
ct->tar = obn;
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5337,12 +5332,10 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
|
||||
|
||||
/* also update constraint targets */
|
||||
for (con = ob->constraints.first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
bConstraintTarget *ct;
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
if (ct->tar) {
|
||||
BKE_object_modifier_update_subframe(
|
||||
@@ -5350,9 +5343,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
|
||||
}
|
||||
}
|
||||
/* free temp targets */
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1072,6 +1072,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
|
||||
/* Add dependencies for each constraint in turn. */
|
||||
for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {nullptr, nullptr};
|
||||
/* Invalid constraint type. */
|
||||
if (cti == nullptr) {
|
||||
continue;
|
||||
@@ -1120,9 +1121,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
|
||||
add_relation(cache_key, constraint_op_key, cti->name);
|
||||
}
|
||||
}
|
||||
else if (cti->get_constraint_targets) {
|
||||
ListBase targets = {nullptr, nullptr};
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
else if (BKE_constraint_targets_get(con, &targets)) {
|
||||
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
|
||||
if (ct->tar == nullptr) {
|
||||
continue;
|
||||
@@ -1232,9 +1231,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
|
||||
add_relation(target_transform_key, constraint_op_key, cti->name);
|
||||
}
|
||||
}
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, true);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1335,16 +1335,19 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
|
||||
}
|
||||
else {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
|
||||
ListBase targets = {NULL, NULL};
|
||||
|
||||
if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag & (1 << 0))) {
|
||||
ListBase targets = {NULL, NULL};
|
||||
if ((curcon->ui_expand_flag & (1 << 0)) && BKE_constraint_targets_get(curcon, &targets)) {
|
||||
bConstraintTarget *ct;
|
||||
|
||||
cti->get_constraint_targets(curcon, &targets);
|
||||
BKE_constraint_custom_object_space_init(cob, curcon);
|
||||
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
/* calculate target's matrix */
|
||||
if (cti->get_target_matrix) {
|
||||
if (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE) {
|
||||
copy_m4_m4(ct->matrix, cob->space_obj_world_matrix);
|
||||
}
|
||||
else if (cti->get_target_matrix) {
|
||||
cti->get_target_matrix(depsgraph, curcon, cob, ct, DEG_get_ctime(depsgraph));
|
||||
}
|
||||
else {
|
||||
@@ -1353,9 +1356,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
|
||||
OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->obmat[3], constraint_color);
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(curcon, &targets, 1);
|
||||
}
|
||||
BKE_constraint_targets_flush(curcon, &targets, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -400,13 +400,10 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
|
||||
/* does this constraint have a subtarget in
|
||||
* this armature?
|
||||
*/
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(curcon, &targets);
|
||||
|
||||
if (BKE_constraint_targets_get(curcon, &targets)) {
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
if ((ct->tar == ob) && (ct->subtarget[0])) {
|
||||
oldtarget = get_named_editbone(editbones, ct->subtarget);
|
||||
@@ -434,9 +431,7 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(curcon, &targets, 0);
|
||||
}
|
||||
BKE_constraint_targets_flush(curcon, &targets, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -453,10 +448,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_init(&cob, 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 +603,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_init(&cob, 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 +658,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_init(&cob, 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 +721,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 */
|
||||
|
@@ -126,13 +126,10 @@ static void constraint_bone_name_fix(Object *ob,
|
||||
bConstraintTarget *ct;
|
||||
|
||||
for (curcon = conlist->first; curcon; curcon = curcon->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
|
||||
ListBase targets = {NULL, NULL};
|
||||
|
||||
/* constraint targets */
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(curcon, &targets);
|
||||
|
||||
if (BKE_constraint_targets_get(curcon, &targets)) {
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
if (ct->tar == ob) {
|
||||
if (STREQ(ct->subtarget, oldname)) {
|
||||
@@ -141,9 +138,7 @@ static void constraint_bone_name_fix(Object *ob,
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(curcon, &targets, 0);
|
||||
}
|
||||
BKE_constraint_targets_flush(curcon, &targets, 0);
|
||||
}
|
||||
|
||||
/* action constraints */
|
||||
|
@@ -84,14 +84,11 @@ static void joined_armature_fix_links_constraints(Main *bmain,
|
||||
bool changed = false;
|
||||
|
||||
for (con = lb->first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
/* constraint targets */
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
if (ct->tar == srcArm) {
|
||||
if (ct->subtarget[0] == '\0') {
|
||||
@@ -106,9 +103,7 @@ static void joined_armature_fix_links_constraints(Main *bmain,
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, 0);
|
||||
}
|
||||
|
||||
/* action constraint? (pose constraints only) */
|
||||
@@ -467,14 +462,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
|
||||
if (ob->type == OB_ARMATURE) {
|
||||
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
for (con = pchan->constraints.first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
/* constraint targets */
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
/* Any targets which point to original armature
|
||||
* are redirected to the new one only if:
|
||||
@@ -495,9 +487,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -506,14 +496,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
|
||||
/* fix object-level constraints */
|
||||
if (ob != origArm) {
|
||||
for (con = ob->constraints.first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
/* constraint targets */
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
/* any targets which point to original armature are redirected to the new one only if:
|
||||
* - the target isn't origArm/newArm itself
|
||||
@@ -533,9 +520,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -673,13 +673,10 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
|
||||
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
|
||||
if (pchan->bone->flag & BONE_SELECTED) {
|
||||
for (con = pchan->constraints.first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
Object *ob = ct->tar;
|
||||
|
||||
@@ -695,9 +692,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 1);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -271,13 +271,11 @@ static void set_constraint_nth_target(bConstraint *con,
|
||||
const char subtarget[],
|
||||
int index)
|
||||
{
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
int num_targets, i;
|
||||
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
num_targets = BLI_listbase_count(&targets);
|
||||
|
||||
if (index < 0) {
|
||||
@@ -300,9 +298,7 @@ static void set_constraint_nth_target(bConstraint *con,
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +311,6 @@ static void set_constraint_nth_target(bConstraint *con,
|
||||
static void test_constraint(
|
||||
Main *bmain, Object *owner, bPoseChannel *pchan, bConstraint *con, int type)
|
||||
{
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
bool check_targets = true;
|
||||
@@ -494,14 +489,7 @@ static void test_constraint(
|
||||
}
|
||||
|
||||
/* Check targets for constraints */
|
||||
if (check_targets && cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
/* constraints with empty target list that actually require targets */
|
||||
if (!targets.first && ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
|
||||
con->flag |= CONSTRAINT_DISABLE;
|
||||
}
|
||||
|
||||
if (check_targets && BKE_constraint_targets_get(con, &targets)) {
|
||||
/* disable and clear constraints targets that are incorrect */
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
/* general validity checks (for those constraints that need this) */
|
||||
@@ -572,8 +560,12 @@ static void test_constraint(
|
||||
}
|
||||
|
||||
/* free any temporary targets */
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
BKE_constraint_targets_flush(con, &targets, 0);
|
||||
}
|
||||
else if (check_targets) {
|
||||
/* constraints with empty target list that actually require targets */
|
||||
if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
|
||||
con->flag |= CONSTRAINT_DISABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -239,24 +239,26 @@ bool BCAnimationSampler::is_animated_by_constraint(Object *ob,
|
||||
for (con = (bConstraint *)conlist->first; con; con = con->next) {
|
||||
ListBase targets = {nullptr, nullptr};
|
||||
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
|
||||
if (!bc_validateConstraints(con)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
bConstraintTarget *ct;
|
||||
Object *obtar;
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
bool found = false;
|
||||
|
||||
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
|
||||
obtar = ct->tar;
|
||||
if (obtar) {
|
||||
if (animated_objects.find(obtar) != animated_objects.end()) {
|
||||
return true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, true);
|
||||
return found;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@@ -206,24 +206,19 @@ void SceneExporter::writeNode(Object *ob)
|
||||
/* not ideal: add the target object name as another parameter.
|
||||
* No real mapping in the .dae
|
||||
* Need support for multiple target objects also. */
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {nullptr, nullptr};
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
|
||||
ListBase targets = {nullptr, nullptr};
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
bConstraintTarget *ct;
|
||||
Object *obtar;
|
||||
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
|
||||
obtar = ct->tar;
|
||||
std::string tar_id((obtar) ? id_name(obtar) : "");
|
||||
colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "target_id", tar_id);
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, true);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, true);
|
||||
}
|
||||
|
||||
con = con->next;
|
||||
|
@@ -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. */
|
||||
@@ -118,6 +123,8 @@ typedef struct bConstraintTarget {
|
||||
typedef enum eConstraintTargetFlag {
|
||||
/** temporary target-struct that needs to be freed after use */
|
||||
CONSTRAINT_TAR_TEMP = (1 << 0),
|
||||
/** temporary target for the custom space reference */
|
||||
CONSTRAINT_TAR_CUSTOM_SPACE = (1 << 1),
|
||||
} eConstraintTargetFlag;
|
||||
|
||||
/* bConstraintTarget/bConstraintOb -> type */
|
||||
@@ -722,6 +729,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).
|
||||
|
@@ -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,
|
||||
@@ -582,22 +599,17 @@ static const EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSE
|
||||
bool *UNUSED(r_free))
|
||||
{
|
||||
bConstraint *con = (bConstraint *)ptr->data;
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
if (ct->tar && ct->tar->type == OB_ARMATURE) {
|
||||
if (ct->tar && ct->tar->type == OB_ARMATURE && !(ct->type & CONSTRAINT_TAR_CUSTOM_SPACE)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 1);
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, 1);
|
||||
|
||||
if (ct) {
|
||||
return target_space_pchan_items;
|
||||
@@ -3398,6 +3410,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);
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user