Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/constraint.c
| Show First 20 Lines • Show All 249 Lines • ▼ Show 20 Lines | |||||
| /* -------------- Space-Conversion API -------------- */ | /* -------------- Space-Conversion API -------------- */ | ||||
| /* This function is responsible for the correct transformations/conversions | /* This function is responsible for the correct transformations/conversions | ||||
| * of a matrix from one space to another for constraint evaluation. | * of a matrix from one space to another for constraint evaluation. | ||||
| * For now, this is only implemented for Objects and PoseChannels. | * For now, this is only implemented for Objects and PoseChannels. | ||||
| */ | */ | ||||
| void BKE_constraint_mat_convertspace( | void BKE_constraint_mat_convertspace( | ||||
| Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale) | Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to) | ||||
| { | { | ||||
| float diff_mat[4][4]; | float diff_mat[4][4]; | ||||
| float imat[4][4]; | float imat[4][4]; | ||||
| /* prevent crashes in these unlikely events */ | /* prevent crashes in these unlikely events */ | ||||
| if (ob == NULL || mat == NULL) { | if (ob == NULL || mat == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| Show All 10 Lines | switch (from) { | ||||
| { | { | ||||
| /* world to pose */ | /* world to pose */ | ||||
| invert_m4_m4(imat, ob->obmat); | invert_m4_m4(imat, ob->obmat); | ||||
| mul_m4_m4m4(mat, imat, mat); | mul_m4_m4m4(mat, imat, mat); | ||||
| /* use pose-space as stepping stone for other spaces... */ | /* use pose-space as stepping stone for other spaces... */ | ||||
| if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) { | if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) { | ||||
| /* call self with slightly different values */ | /* 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, mat, CONSTRAINT_SPACE_POSE, to); | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CONSTRAINT_SPACE_POSE: /* ---------- FROM POSESPACE ---------- */ | case CONSTRAINT_SPACE_POSE: /* ---------- FROM POSESPACE ---------- */ | ||||
| { | { | ||||
| /* pose to world */ | /* pose to world */ | ||||
| if (to == CONSTRAINT_SPACE_WORLD) { | if (to == CONSTRAINT_SPACE_WORLD) { | ||||
| mul_m4_m4m4(mat, ob->obmat, mat); | mul_m4_m4m4(mat, ob->obmat, mat); | ||||
| Show All 19 Lines | switch (from) { | ||||
| if (pchan->bone) { | if (pchan->bone) { | ||||
| /* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */ | /* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */ | ||||
| BKE_armature_mat_bone_to_pose(pchan, mat, mat); | BKE_armature_mat_bone_to_pose(pchan, mat, mat); | ||||
| } | } | ||||
| /* use pose-space as stepping stone for other spaces */ | /* 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)) { | ||||
| /* call self with slightly different values */ | /* 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, mat, CONSTRAINT_SPACE_POSE, to); | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CONSTRAINT_SPACE_PARLOCAL: /* -------------- FROM LOCAL WITH PARENT ---------- */ | case CONSTRAINT_SPACE_PARLOCAL: /* -------------- FROM LOCAL WITH PARENT ---------- */ | ||||
| { | { | ||||
| /* local + parent to pose */ | /* local + parent to pose */ | ||||
| if (pchan->bone) { | if (pchan->bone) { | ||||
| mul_m4_m4m4(mat, pchan->bone->arm_mat, mat); | mul_m4_m4m4(mat, pchan->bone->arm_mat, mat); | ||||
| } | } | ||||
| /* use pose-space as stepping stone for other spaces */ | /* 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)) { | ||||
| /* call self with slightly different values */ | /* 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, mat, CONSTRAINT_SPACE_POSE, to); | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* objects */ | /* objects */ | ||||
| if (from == CONSTRAINT_SPACE_WORLD && to == CONSTRAINT_SPACE_LOCAL) { | if (from == CONSTRAINT_SPACE_WORLD && to == CONSTRAINT_SPACE_LOCAL) { | ||||
| /* check if object has a parent */ | /* check if object has a parent */ | ||||
| if (ob->parent) { | if (ob->parent) { | ||||
| /* 'subtract' parent's effects from owner */ | /* 'subtract' parent's effects from owner */ | ||||
| mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); | mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); | ||||
| invert_m4_m4_safe(imat, diff_mat); | invert_m4_m4_safe(imat, diff_mat); | ||||
| mul_m4_m4m4(mat, imat, 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); | |||||
| } | |||||
| zero_v3(diff_mat[3]); | |||||
| invert_m4_m4_safe(imat, diff_mat); | |||||
| mul_m4_m4m4(mat, imat, mat); | |||||
| } | |||||
| } | } | ||||
| else if (from == CONSTRAINT_SPACE_LOCAL && to == CONSTRAINT_SPACE_WORLD) { | else if (from == CONSTRAINT_SPACE_LOCAL && to == CONSTRAINT_SPACE_WORLD) { | ||||
| /* check that object has a parent - otherwise this won't work */ | /* check that object has a parent - otherwise this won't work */ | ||||
| if (ob->parent) { | if (ob->parent) { | ||||
| /* 'add' parent's effect back to owner */ | /* 'add' parent's effect back to owner */ | ||||
| mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); | mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); | ||||
| mul_m4_m4m4(mat, diff_mat, mat); | mul_m4_m4m4(mat, diff_mat, mat); | ||||
| } | } | ||||
| else { | |||||
| /* Local space in this case will have to be defined as local to the owner's | |||||
| * transform-property-rotated axes. So add back this rotation component. | |||||
| */ | |||||
| /* XXX See comment above for world->local case... */ | |||||
| BKE_object_to_mat4(ob, diff_mat); | |||||
| if (!keep_scale) { | |||||
| normalize_m4(diff_mat); | |||||
| } | |||||
| zero_v3(diff_mat[3]); | |||||
| mul_m4_m4m4(mat, diff_mat, mat); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* ------------ General Target Matrix Tools ---------- */ | /* ------------ General Target Matrix Tools ---------- */ | ||||
| /* function that sets the given matrix based on given vertex group in mesh */ | /* function that sets the given matrix based on given vertex group in mesh */ | ||||
| static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[4][4]) | static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[4][4]) | ||||
| ▲ Show 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | static void constraint_target_to_mat4(Object *ob, | ||||
| short from, | short from, | ||||
| short to, | short to, | ||||
| short flag, | short flag, | ||||
| float headtail) | float headtail) | ||||
| { | { | ||||
| /* Case OBJECT */ | /* Case OBJECT */ | ||||
| if (substring[0] == '\0') { | if (substring[0] == '\0') { | ||||
| copy_m4_m4(mat, ob->obmat); | copy_m4_m4(mat, ob->obmat); | ||||
| BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); | BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); | ||||
| } | } | ||||
| /* Case VERTEXGROUP */ | /* Case VERTEXGROUP */ | ||||
| /* Current method just takes the average location of all the points in the | /* Current method just takes the average location of all the points in the | ||||
| * VertexGroup, and uses that as the location value of the targets. Where | * VertexGroup, and uses that as the location value of the targets. Where | ||||
| * possible, the orientation will also be calculated, by calculating an | * possible, the orientation will also be calculated, by calculating an | ||||
| * 'average' vertex normal, and deriving the rotation from that. | * 'average' vertex normal, and deriving the rotation from that. | ||||
| * | * | ||||
| * NOTE: EditMode is not currently supported, and will most likely remain that | * NOTE: EditMode is not currently supported, and will most likely remain that | ||||
| * way as constraints can only really affect things on object/bone level. | * way as constraints can only really affect things on object/bone level. | ||||
| */ | */ | ||||
| else if (ob->type == OB_MESH) { | else if (ob->type == OB_MESH) { | ||||
| contarget_get_mesh_mat(ob, substring, mat); | contarget_get_mesh_mat(ob, substring, mat); | ||||
| BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); | BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); | ||||
| } | } | ||||
| else if (ob->type == OB_LATTICE) { | else if (ob->type == OB_LATTICE) { | ||||
| contarget_get_lattice_mat(ob, substring, mat); | contarget_get_lattice_mat(ob, substring, mat); | ||||
| BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); | BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); | ||||
| } | } | ||||
| /* Case BONE */ | /* Case BONE */ | ||||
| else { | else { | ||||
| bPoseChannel *pchan; | bPoseChannel *pchan; | ||||
| pchan = BKE_pose_channel_find_name(ob->pose, substring); | pchan = BKE_pose_channel_find_name(ob->pose, substring); | ||||
| if (pchan) { | if (pchan) { | ||||
| /* Multiply the PoseSpace accumulation/final matrix for this | /* Multiply the PoseSpace accumulation/final matrix for this | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | if (pchan) { | ||||
| mul_m4_m4m4(mat, ob->obmat, tempmat); | mul_m4_m4m4(mat, ob->obmat, tempmat); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| copy_m4_m4(mat, ob->obmat); | copy_m4_m4(mat, ob->obmat); | ||||
| } | } | ||||
| /* convert matrix space as required */ | /* convert matrix space as required */ | ||||
| BKE_constraint_mat_convertspace(ob, pchan, mat, from, to, false); | BKE_constraint_mat_convertspace(ob, pchan, mat, from, to); | ||||
| } | } | ||||
| } | } | ||||
| /* ************************* Specific Constraints ***************************** */ | /* ************************* Specific Constraints ***************************** */ | ||||
| /* Each constraint defines a set of functions, which will be called at the appropriate | /* Each constraint defines a set of functions, which will be called at the appropriate | ||||
| * times. In addition to this, each constraint should have a type-info struct, where | * times. In addition to this, each constraint should have a type-info struct, where | ||||
| * its functions are attached for use. | * its functions are attached for use. | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 3,422 Lines • ▼ Show 20 Lines | if (BKE_shrinkwrap_init_tree( | ||||
| case OB_NEGX: | case OB_NEGX: | ||||
| case OB_NEGY: | case OB_NEGY: | ||||
| case OB_NEGZ: | case OB_NEGZ: | ||||
| no[scon->projAxis - OB_NEGX] = -1.0f; | no[scon->projAxis - OB_NEGX] = -1.0f; | ||||
| break; | break; | ||||
| } | } | ||||
| /* Transform normal into requested space */ | /* Transform normal into requested space */ | ||||
| /* Note that in this specific case, we need to keep scaling in non-parented 'local2world' | |||||
| * object case, because SpaceTransform also takes it into account when handling normals. | |||||
| * See T42447. */ | |||||
| unit_m4(mat); | unit_m4(mat); | ||||
| BKE_constraint_mat_convertspace( | BKE_constraint_mat_convertspace( | ||||
| cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true); | cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace); | ||||
| invert_m4(mat); | invert_m4(mat); | ||||
| mul_mat3_m4_v3(mat, no); | mul_mat3_m4_v3(mat, no); | ||||
| if (normalize_v3(no) < FLT_EPSILON) { | if (normalize_v3(no) < FLT_EPSILON) { | ||||
| fail = true; | fail = true; | ||||
| break; | break; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 1,717 Lines • ▼ Show 20 Lines | for (con = conlist->first; con; con = con->next) { | ||||
| */ | */ | ||||
| enf = con->enforce; | enf = con->enforce; | ||||
| /* make copy of worldspace matrix pre-constraint for use with blending later */ | /* make copy of worldspace matrix pre-constraint for use with blending later */ | ||||
| copy_m4_m4(oldmat, cob->matrix); | copy_m4_m4(oldmat, cob->matrix); | ||||
| /* move owner matrix into right space */ | /* move owner matrix into right space */ | ||||
| BKE_constraint_mat_convertspace( | BKE_constraint_mat_convertspace( | ||||
| cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false); | cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); | ||||
| /* prepare targets for constraint solving */ | /* prepare targets for constraint solving */ | ||||
| BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime); | BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime); | ||||
| /* Solve the constraint and put result in cob->matrix */ | /* Solve the constraint and put result in cob->matrix */ | ||||
| cti->evaluate_constraint(con, cob, &targets); | cti->evaluate_constraint(con, cob, &targets); | ||||
| /* clear targets after use | /* clear targets after use | ||||
| * - this should free temp targets but no data should be copied back | * - this should free temp targets but no data should be copied back | ||||
| * as constraints may have done some nasty things to it... | * as constraints may have done some nasty things to it... | ||||
| */ | */ | ||||
| if (cti->flush_constraint_targets) { | if (cti->flush_constraint_targets) { | ||||
| cti->flush_constraint_targets(con, &targets, 1); | cti->flush_constraint_targets(con, &targets, 1); | ||||
| } | } | ||||
| /* move owner back into worldspace for next constraint/other business */ | /* move owner back into worldspace for next constraint/other business */ | ||||
| if ((con->flag & CONSTRAINT_SPACEONCE) == 0) { | if ((con->flag & CONSTRAINT_SPACEONCE) == 0) { | ||||
| BKE_constraint_mat_convertspace( | BKE_constraint_mat_convertspace( | ||||
| cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false); | cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD); | ||||
| } | } | ||||
| /* Interpolate the enforcement, to blend result of constraint into final owner transform | /* Interpolate the enforcement, to blend result of constraint into final owner transform | ||||
| * - all this happens in worldspace to prevent any weirdness creeping in | * - all this happens in worldspace to prevent any weirdness creeping in | ||||
| * (T26014 and T25725), since some constraints may not convert the solution back to the input | * (T26014 and T25725), since some constraints may not convert the solution back to the input | ||||
| * space before blending but all are guaranteed to end up in good "worldspace" result. | * space before blending but all are guaranteed to end up in good "worldspace" result. | ||||
| */ | */ | ||||
| /* Note: all kind of stuff here before (caused trouble), much easier to just interpolate, | /* Note: all kind of stuff here before (caused trouble), much easier to just interpolate, | ||||
| * or did I miss something? -jahka (r.32105) */ | * or did I miss something? -jahka (r.32105) */ | ||||
| if (enf < 1.0f) { | if (enf < 1.0f) { | ||||
| float solution[4][4]; | float solution[4][4]; | ||||
| copy_m4_m4(solution, cob->matrix); | copy_m4_m4(solution, cob->matrix); | ||||
| interp_m4_m4m4(cob->matrix, oldmat, solution, enf); | interp_m4_m4m4(cob->matrix, oldmat, solution, enf); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||