Compare commits
6 Commits
experiment
...
temp-angav
Author | SHA1 | Date | |
---|---|---|---|
6f1e5b632e | |||
f38454bf9e | |||
b52d792f29 | |||
9b73791d8d | |||
76dece2e0b | |||
![]() |
f1190ff6c5 |
@@ -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()
|
||||
@@ -236,8 +245,9 @@ class ConstraintButtonsPanel(Panel):
|
||||
sub.prop(con, "max_z", text="Max")
|
||||
row.label(icon="BLANK1")
|
||||
|
||||
layout.prop(con, "euler_order", text="Order")
|
||||
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 +316,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 +385,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 +493,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)
|
||||
|
||||
@@ -495,6 +505,8 @@ class ConstraintButtonsPanel(Panel):
|
||||
|
||||
self.target_template(layout, con)
|
||||
|
||||
layout.prop(con, "fix_target_shear")
|
||||
layout.prop(con, "invert")
|
||||
layout.prop(con, "mix_mode", text="Mix")
|
||||
|
||||
self.space_template(layout, con)
|
||||
@@ -1117,7 +1129,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,27 +287,45 @@ 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 (to != CONSTRAINT_SPACE_POSE) {
|
||||
/* 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 (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_OWNLOCAL)) {
|
||||
if (pchan->bone) {
|
||||
BKE_armature_mat_pose_to_bone(pchan, mat, mat);
|
||||
|
||||
if (to == CONSTRAINT_SPACE_OWNLOCAL) {
|
||||
copy_m4_m4(diff_mat, pchan->bone->arm_mat);
|
||||
|
||||
if (cob && cob->pchan && cob->pchan->bone) {
|
||||
invert_m4_m4(imat, cob->pchan->bone->arm_mat);
|
||||
mul_m4_m4m4(diff_mat, imat, diff_mat);
|
||||
}
|
||||
|
||||
zero_v3(diff_mat[3]);
|
||||
invert_m4_m4(imat, diff_mat);
|
||||
mul_m4_series(mat, diff_mat, mat, imat);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* pose to local with parent */
|
||||
@@ -312,20 +335,44 @@ 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 --------- */
|
||||
{
|
||||
case CONSTRAINT_SPACE_OWNLOCAL: {
|
||||
/* local to pose - do inverse procedure that was done for pose to local */
|
||||
if (pchan->bone) {
|
||||
if (from == CONSTRAINT_SPACE_OWNLOCAL) {
|
||||
copy_m4_m4(diff_mat, pchan->bone->arm_mat);
|
||||
|
||||
if (cob && cob->pchan && cob->pchan->bone) {
|
||||
invert_m4_m4(imat, cob->pchan->bone->arm_mat);
|
||||
mul_m4_m4m4(diff_mat, imat, diff_mat);
|
||||
}
|
||||
|
||||
zero_v3(diff_mat[3]);
|
||||
invert_m4_m4(imat, diff_mat);
|
||||
mul_m4_series(mat, imat, mat, diff_mat);
|
||||
}
|
||||
|
||||
/* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */
|
||||
BKE_armature_mat_bone_to_pose(pchan, mat, mat);
|
||||
}
|
||||
|
||||
/* use pose-space as stepping stone for other spaces */
|
||||
if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) {
|
||||
if (to != CONSTRAINT_SPACE_POSE) {
|
||||
/* 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 +384,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 (to != CONSTRAINT_SPACE_POSE) {
|
||||
/* 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 +409,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 +466,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 +660,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 +670,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 +683,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 +750,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 +793,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 +816,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 +934,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 +1357,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,
|
||||
@@ -1551,10 +1647,28 @@ static void rotlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UN
|
||||
float eul[3];
|
||||
float size[3];
|
||||
|
||||
/* This constraint is based on euler rotation math, which doesn't work well with shear.
|
||||
* The Y axis is chosen as the main one because constraints are most commonly used on bones.
|
||||
* This also allows using the constraint to simply remove shear. */
|
||||
orthogonalize_m4_stable(cob->matrix, 1, false);
|
||||
|
||||
/* Only do the complex processing if some limits are actually enabled. */
|
||||
if (!(data->flag & (LIMIT_XROT | LIMIT_YROT | LIMIT_ZROT))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Select the Euler rotation order, defaulting to the owner value. */
|
||||
short rot_order = cob->rotOrder;
|
||||
|
||||
if (data->euler_order != CONSTRAINT_EULER_AUTO) {
|
||||
rot_order = data->euler_order;
|
||||
}
|
||||
|
||||
/* Decompose the matrix using the specified order. */
|
||||
copy_v3_v3(loc, cob->matrix[3]);
|
||||
mat4_to_size(size, cob->matrix);
|
||||
|
||||
mat4_to_eulO(eul, cob->rotOrder, cob->matrix);
|
||||
mat4_to_eulO(eul, rot_order, cob->matrix);
|
||||
|
||||
/* constraint data uses radians internally */
|
||||
|
||||
@@ -1587,7 +1701,7 @@ static void rotlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UN
|
||||
}
|
||||
}
|
||||
|
||||
loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
|
||||
loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, rot_order);
|
||||
}
|
||||
|
||||
static bConstraintTypeInfo CTI_ROTLIMIT = {
|
||||
@@ -2118,17 +2232,62 @@ static void translike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
|
||||
bConstraintTarget *ct = targets->first;
|
||||
|
||||
if (VALID_CONS_TARGET(ct)) {
|
||||
float target_mat[4][4];
|
||||
|
||||
copy_m4_m4(target_mat, ct->matrix);
|
||||
|
||||
/* Fix the shear of the target matrix if enabled.
|
||||
* Use Y as the axis since it's the natural default for bones. */
|
||||
if (data->flag & TRANSLIKE_FIX_TARGET_SHEAR) {
|
||||
orthogonalize_m4_stable(target_mat, 1, false);
|
||||
}
|
||||
|
||||
/* Invert the transformation. */
|
||||
if (data->flag & TRANSLIKE_INVERT) {
|
||||
/* For modes that split channels, split during invert too. */
|
||||
if (ELEM(data->mix_mode,
|
||||
TRANSLIKE_MIX_BEFORE,
|
||||
TRANSLIKE_MIX_AFTER,
|
||||
TRANSLIKE_MIX_BEFORE_SPLIT,
|
||||
TRANSLIKE_MIX_AFTER_SPLIT)) {
|
||||
invert_m4_m4_split_channels(target_mat, target_mat);
|
||||
}
|
||||
else {
|
||||
invert_m4(target_mat);
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, combine the matrices. */
|
||||
switch (data->mix_mode) {
|
||||
case TRANSLIKE_MIX_REPLACE:
|
||||
copy_m4_m4(cob->matrix, ct->matrix);
|
||||
copy_m4_m4(cob->matrix, target_mat);
|
||||
break;
|
||||
|
||||
/* Simple matrix multiplication. */
|
||||
case TRANSLIKE_MIX_BEFORE_FULL:
|
||||
mul_m4_m4m4(cob->matrix, target_mat, cob->matrix);
|
||||
break;
|
||||
|
||||
case TRANSLIKE_MIX_AFTER_FULL:
|
||||
mul_m4_m4m4(cob->matrix, cob->matrix, target_mat);
|
||||
break;
|
||||
|
||||
/* Aligned Inherit Scale emulation. */
|
||||
case TRANSLIKE_MIX_BEFORE:
|
||||
mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix);
|
||||
mul_m4_m4m4_aligned_scale(cob->matrix, target_mat, cob->matrix);
|
||||
break;
|
||||
|
||||
case TRANSLIKE_MIX_AFTER:
|
||||
mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, ct->matrix);
|
||||
mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, target_mat);
|
||||
break;
|
||||
|
||||
/* Fully separate handling of channels. */
|
||||
case TRANSLIKE_MIX_BEFORE_SPLIT:
|
||||
mul_m4_m4m4_split_channels(cob->matrix, target_mat, cob->matrix);
|
||||
break;
|
||||
|
||||
case TRANSLIKE_MIX_AFTER_SPLIT:
|
||||
mul_m4_m4m4_split_channels(cob->matrix, cob->matrix, target_mat);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2282,7 +2441,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 +2460,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,
|
||||
@@ -2660,6 +2820,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,
|
||||
@@ -4122,7 +4283,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);
|
||||
|
||||
@@ -5339,6 +5500,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,
|
||||
@@ -5356,8 +5530,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5524,9 +5698,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);
|
||||
}
|
||||
|
||||
@@ -5560,9 +5737,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5614,16 +5789,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5878,6 +6051,62 @@ 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. */
|
||||
bConstraintTarget *ct = (bConstraintTarget *)list->last;
|
||||
|
||||
if (ct && (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE)) {
|
||||
BLI_assert(is_custom_space_needed(con));
|
||||
|
||||
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.
|
||||
@@ -5936,6 +6165,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);
|
||||
|
||||
@@ -6000,6 +6232,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
|
||||
@@ -6048,12 +6300,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);
|
||||
@@ -6072,7 +6327,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5341,12 +5336,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(
|
||||
@@ -5354,9 +5347,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -211,6 +211,7 @@ void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]);
|
||||
void mul_m3_v3_double(const float M[3][3], double r[3]);
|
||||
|
||||
void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4]);
|
||||
void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4]);
|
||||
|
||||
void mul_m3_fl(float R[3][3], float f);
|
||||
void mul_m4_fl(float R[4][4], float f);
|
||||
@@ -229,6 +230,8 @@ bool invert_m4(float R[4][4]);
|
||||
bool invert_m4_m4(float R[4][4], const float A[4][4]);
|
||||
bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]);
|
||||
|
||||
bool invert_m4_m4_split_channels(float R[4][4], const float A[4][4]);
|
||||
|
||||
/* double arithmetic (mixed float/double) */
|
||||
void mul_m4_v4d(const float M[4][4], double r[4]);
|
||||
void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]);
|
||||
|
@@ -1286,10 +1286,32 @@ bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Separately inverts location, rotation and scale of the input matrix.
|
||||
*
|
||||
* This produces a true inversion for mul_m4_m4m4_split_channels.
|
||||
*/
|
||||
bool invert_m4_m4_split_channels(float R[4][4], const float A[4][4])
|
||||
{
|
||||
float loc[3], rot[3][3], size[3];
|
||||
|
||||
mat4_to_loc_rot_size(loc, rot, size, A);
|
||||
|
||||
negate_v3(loc);
|
||||
bool success = invert_m3(rot);
|
||||
invert_v3(size);
|
||||
|
||||
loc_rot_size_to_mat4(R, loc, rot, size);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines transformations, handling scale separately in a manner equivalent
|
||||
* to the Aligned Inherit Scale mode, in order to avoid creating shear.
|
||||
* If A scale is uniform, the result is equivalent to ordinary multiplication.
|
||||
*
|
||||
* Note: this effectively takes output location from simple multiplication,
|
||||
* and uses mul_m4_m4m4_split_channels for rotation and scale.
|
||||
*/
|
||||
void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4])
|
||||
{
|
||||
@@ -1307,6 +1329,25 @@ void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B
|
||||
loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Separately combines location, rotation and scale of the input matrices.
|
||||
*/
|
||||
void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4])
|
||||
{
|
||||
float loc_a[3], rot_a[3][3], size_a[3];
|
||||
float loc_b[3], rot_b[3][3], size_b[3];
|
||||
float loc_r[3], rot_r[3][3], size_r[3];
|
||||
|
||||
mat4_to_loc_rot_size(loc_a, rot_a, size_a, A);
|
||||
mat4_to_loc_rot_size(loc_b, rot_b, size_b, B);
|
||||
|
||||
add_v3_v3v3(loc_r, loc_a, loc_b);
|
||||
mul_m3_m3m3_uniq(rot_r, rot_a, rot_b);
|
||||
mul_v3_v3v3(size_r, size_a, size_b);
|
||||
|
||||
loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
|
||||
}
|
||||
|
||||
/****************************** Linear Algebra *******************************/
|
||||
|
||||
void transpose_m3(float R[3][3])
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1334,16 +1334,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 {
|
||||
@@ -1352,9 +1355,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,29 +431,28 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void updateDuplicateActionConstraintSettings(EditBone *dup_bone,
|
||||
EditBone *orig_bone,
|
||||
Object *ob,
|
||||
bConstraint *curcon)
|
||||
static void updateDuplicateActionConstraintSettings(
|
||||
EditBone *dup_bone, EditBone *orig_bone, Object *ob, bPoseChannel *pchan, bConstraint *curcon)
|
||||
{
|
||||
bActionConstraint *act_con = (bActionConstraint *)curcon->data;
|
||||
bAction *act = (bAction *)act_con->act;
|
||||
|
||||
float mat[4][4];
|
||||
|
||||
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
|
||||
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 +601,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 +656,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 +719,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 */
|
||||
@@ -827,7 +829,7 @@ static void updateDuplicateConstraintSettings(EditBone *dup_bone, EditBone *orig
|
||||
for (curcon = conlist->first; curcon; curcon = curcon->next) {
|
||||
switch (curcon->type) {
|
||||
case CONSTRAINT_TYPE_ACTION:
|
||||
updateDuplicateActionConstraintSettings(dup_bone, orig_bone, ob, curcon);
|
||||
updateDuplicateActionConstraintSettings(dup_bone, orig_bone, ob, pchan, curcon);
|
||||
break;
|
||||
case CONSTRAINT_TYPE_KINEMATIC:
|
||||
updateDuplicateKinematicConstraintSettings(curcon);
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -815,10 +815,13 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list)
|
||||
/* Copy Transforms constraint only does this in the Before mode. */
|
||||
bTransLikeConstraint *data = (bTransLikeConstraint *)con->data;
|
||||
|
||||
if (ELEM(data->mix_mode, TRANSLIKE_MIX_BEFORE) &&
|
||||
if (ELEM(data->mix_mode, TRANSLIKE_MIX_BEFORE, TRANSLIKE_MIX_BEFORE_FULL) &&
|
||||
ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION)) {
|
||||
return true;
|
||||
}
|
||||
if (ELEM(data->mix_mode, TRANSLIKE_MIX_BEFORE_SPLIT) && ELEM(t->mode, TFM_ROTATION)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (con->type == CONSTRAINT_TYPE_ACTION) {
|
||||
/* The Action constraint only does this in the Before mode. */
|
||||
|
@@ -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 */
|
||||
@@ -311,8 +318,9 @@ typedef struct bSameVolumeConstraint {
|
||||
/* Copy Transform Constraint */
|
||||
typedef struct bTransLikeConstraint {
|
||||
struct Object *tar;
|
||||
int flag;
|
||||
char mix_mode;
|
||||
char _pad[7];
|
||||
char _pad[3];
|
||||
/** MAX_ID_NAME-2. */
|
||||
char subtarget[64];
|
||||
} bTransLikeConstraint;
|
||||
@@ -529,6 +537,8 @@ typedef struct bRotLimitConstraint {
|
||||
float zmin, zmax;
|
||||
short flag;
|
||||
short flag2;
|
||||
char euler_order;
|
||||
char _pad[3];
|
||||
} bRotLimitConstraint;
|
||||
|
||||
/* Limit Scale Constraint */
|
||||
@@ -722,6 +732,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).
|
||||
@@ -731,6 +743,8 @@ typedef enum eBConstraint_SpaceTypes {
|
||||
CONSTRAINT_SPACE_POSE = 2,
|
||||
/** For posechannels - local with parent. */
|
||||
CONSTRAINT_SPACE_PARLOCAL = 3,
|
||||
/** For posechannels - local converted to the owner bone orientation. */
|
||||
CONSTRAINT_SPACE_OWNLOCAL = 6,
|
||||
/** For files from between 2.43-2.46 (should have been parlocal). */
|
||||
CONSTRAINT_SPACE_INVALID = 4, /* do not exchange for anything! */
|
||||
} eBConstraint_SpaceTypes;
|
||||
@@ -801,6 +815,14 @@ typedef enum eCopyScale_Flags {
|
||||
SIZELIKE_UNIFORM = (1 << 5),
|
||||
} eCopyScale_Flags;
|
||||
|
||||
/* bTransLikeConstraint.flag */
|
||||
typedef enum eCopyTransforms_Flags {
|
||||
/* Invert the transformation matrix. */
|
||||
TRANSLIKE_INVERT = (1 << 0),
|
||||
/* Remove shear from the target matrix. */
|
||||
TRANSLIKE_FIX_TARGET_SHEAR = (1 << 1),
|
||||
} eCopyTransforms_Flags;
|
||||
|
||||
/* bTransLikeConstraint.mix_mode */
|
||||
typedef enum eCopyTransforms_MixMode {
|
||||
/* Replace rotation channel values. */
|
||||
@@ -809,6 +831,14 @@ typedef enum eCopyTransforms_MixMode {
|
||||
TRANSLIKE_MIX_BEFORE = 1,
|
||||
/* Multiply the copied transformation on the right, with anti-shear scale handling. */
|
||||
TRANSLIKE_MIX_AFTER = 2,
|
||||
/* Multiply the copied transformation on the left, handling loc/rot/scale separately. */
|
||||
TRANSLIKE_MIX_BEFORE_SPLIT = 3,
|
||||
/* Multiply the copied transformation on the right, handling loc/rot/scale separately. */
|
||||
TRANSLIKE_MIX_AFTER_SPLIT = 4,
|
||||
/* Multiply the copied transformation on the left, using simple matrix multiplication. */
|
||||
TRANSLIKE_MIX_BEFORE_FULL = 5,
|
||||
/* Multiply the copied transformation on the right, using simple matrix multiplication. */
|
||||
TRANSLIKE_MIX_AFTER_FULL = 6,
|
||||
} eCopyTransforms_MixMode;
|
||||
|
||||
/* bTransformConstraint.to/from */
|
||||
|
@@ -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,
|
||||
@@ -218,6 +224,12 @@ static const EnumPropertyItem target_space_pchan_items[] = {
|
||||
"Local Space",
|
||||
"The transformation of the target is evaluated relative to its local "
|
||||
"coordinate system"},
|
||||
{CONSTRAINT_SPACE_OWNLOCAL,
|
||||
"OWNER_LOCAL",
|
||||
0,
|
||||
"Owner Local Space",
|
||||
"The local transformation of the target bone is evaluated relative to its local coordinate "
|
||||
"system, as if the target and owner bones had the same orientation in their rest pose"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -227,6 +239,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 +292,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 +605,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->flag & 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;
|
||||
@@ -1607,18 +1625,49 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
|
||||
0,
|
||||
"Replace",
|
||||
"Replace the original transformation with copied"},
|
||||
{0, "", 0, NULL, NULL},
|
||||
{TRANSLIKE_MIX_BEFORE_FULL,
|
||||
"BEFORE_FULL",
|
||||
0,
|
||||
"Before Original (Full)",
|
||||
"Apply copied transformation before original, using simple matrix multiplication as if "
|
||||
"the constraint target is a parent in Full Inherit Scale mode. "
|
||||
"Will create shear when combining rotation and non-uniform scale"},
|
||||
{TRANSLIKE_MIX_AFTER_FULL,
|
||||
"AFTER_FULL",
|
||||
0,
|
||||
"After Original (Full)",
|
||||
"Apply copied transformation after original, using simple matrix multiplication as if "
|
||||
"the constraint target is a child in Full Inherit Scale mode. "
|
||||
"Will create shear when combining rotation and non-uniform scale"},
|
||||
{0, "", 0, NULL, NULL},
|
||||
{TRANSLIKE_MIX_BEFORE,
|
||||
"BEFORE",
|
||||
0,
|
||||
"Before Original",
|
||||
"Apply copied transformation before original, as if the constraint target is a parent. "
|
||||
"Scale is handled specially to avoid creating shear"},
|
||||
"Before Original (Aligned)",
|
||||
"Apply copied transformation before original, as if the constraint target is a parent in "
|
||||
"Aligned Inherit Scale mode. This effectively uses Full for location and Split Channels "
|
||||
"for rotation and scale"},
|
||||
{TRANSLIKE_MIX_AFTER,
|
||||
"AFTER",
|
||||
0,
|
||||
"After Original",
|
||||
"Apply copied transformation after original, as if the constraint target is a child. "
|
||||
"Scale is handled specially to avoid creating shear"},
|
||||
"After Original (Aligned)",
|
||||
"Apply copied transformation after original, as if the constraint target is a child in "
|
||||
"Aligned Inherit Scale mode. This effectively uses Full for location and Split Channels "
|
||||
"for rotation and scale"},
|
||||
{0, "", 0, NULL, NULL},
|
||||
{TRANSLIKE_MIX_BEFORE_SPLIT,
|
||||
"BEFORE_SPLIT",
|
||||
0,
|
||||
"Before Original (Split Channels)",
|
||||
"Apply copied transformation before original, handling location, rotation and scale "
|
||||
"separately, similar to a sequence of three Copy constraints"},
|
||||
{TRANSLIKE_MIX_AFTER_SPLIT,
|
||||
"AFTER_SPLIT",
|
||||
0,
|
||||
"After Original (Split Channels)",
|
||||
"Apply copied transformation after original, handling location, rotation and scale "
|
||||
"separately, similar to a sequence of three Copy constraints"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -1636,6 +1685,20 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
|
||||
|
||||
RNA_define_lib_overridable(true);
|
||||
|
||||
prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRANSLIKE_INVERT);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Invert",
|
||||
"Invert the target transformation. In Aligned or Split Channels mix "
|
||||
"modes channels are inverted separately");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
|
||||
|
||||
prop = RNA_def_property(srna, "fix_target_shear", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRANSLIKE_FIX_TARGET_SHEAR);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Fix Target Shear", "Remove shear from the target transformation");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
|
||||
|
||||
prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "mix_mode");
|
||||
RNA_def_property_enum_items(prop, mix_mode_items);
|
||||
@@ -2580,6 +2643,12 @@ static void rna_def_constraint_rotation_limit(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Maximum Z", "Highest Z value to allow");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
|
||||
|
||||
prop = RNA_def_property(srna, "euler_order", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "euler_order");
|
||||
RNA_def_property_enum_items(prop, euler_order_items);
|
||||
RNA_def_property_ui_text(prop, "Euler Order", "Explicitly specify the euler rotation order");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag2", LIMIT_TRANSFORM);
|
||||
RNA_def_property_ui_text(
|
||||
@@ -3398,6 +3467,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);
|
||||
|
@@ -303,6 +303,9 @@ static void rna_Object_mat_convert_space(Object *ob,
|
||||
{
|
||||
copy_m4_m4((float(*)[4])mat_ret, (float(*)[4])mat);
|
||||
|
||||
BLI_assert(!ELEM(from, CONSTRAINT_SPACE_OWNLOCAL));
|
||||
BLI_assert(!ELEM(to, CONSTRAINT_SPACE_OWNLOCAL));
|
||||
|
||||
/* Error in case of invalid from/to values when pchan is NULL */
|
||||
if (pchan == NULL) {
|
||||
if (ELEM(from, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL)) {
|
||||
@@ -324,8 +327,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