Adds “align” option to snap to verts/edges/faces, for bones in Pose mode.

Have to use a ugly hack, as for pose bones, rotscale transform matrix is not always the same as translate one... :/

Adresses feature request [#30979] snapping: "align rotation with the snapping target" and pose-mode.
This commit is contained in:
Bastien Montagne 2012-05-13 16:01:59 +00:00
parent c8ebfe1d12
commit 800bc74a8f
4 changed files with 36 additions and 11 deletions

@ -93,7 +93,7 @@ class VIEW3D_HT_header(Header):
if snap_element != 'INCREMENT': if snap_element != 'INCREMENT':
row.prop(toolsettings, "snap_target", text="") row.prop(toolsettings, "snap_target", text="")
if obj: if obj:
if obj.mode == 'OBJECT' and snap_element != 'VOLUME': if obj.mode in {'OBJECT','POSE'} and snap_element != 'VOLUME':
row.prop(toolsettings, "use_snap_align_rotation", text="") row.prop(toolsettings, "use_snap_align_rotation", text="")
elif obj.mode == 'EDIT': elif obj.mode == 'EDIT':
row.prop(toolsettings, "use_snap_self", text="") row.prop(toolsettings, "use_snap_self", text="")

@ -3035,12 +3035,16 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
} }
/* rotation */ /* rotation */
if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself /* MORE HACK: as in some cases the matrix to apply location and rot/scale is not the same,
* and ElementRotation() might be called in Translation context (with align snapping),
* we need to be sure to actually use the *rotation* matrix here...
* So no other way than storing it in some dedicated members of td->ext! */
if ((t->flag & T_V3D_ALIGN)==0) { /* align mode doesn't rotate objects itself */
/* euler or quaternion/axis-angle? */ /* euler or quaternion/axis-angle? */
if (td->ext->rotOrder == ROT_MODE_QUAT) { if (td->ext->rotOrder == ROT_MODE_QUAT) {
mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL);
mat3_to_quat(quat, fmat); // Actual transform mat3_to_quat(quat, fmat); /* Actual transform */
mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
/* this function works on end result */ /* this function works on end result */
@ -3053,8 +3057,8 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL);
mat3_to_quat(quat, fmat); // Actual transform mat3_to_quat(quat, fmat); /* Actual transform */
mul_qt_qtqt(tquat, quat, iquat); mul_qt_qtqt(tquat, quat, iquat);
quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat); quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
@ -3065,8 +3069,8 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
else { else {
float eulmat[3][3]; float eulmat[3][3];
mul_m3_m3m3(totmat, mat, td->mtx); mul_m3_m3m3(totmat, mat, td->ext->r_mtx);
mul_m3_m3m3(smat, td->smtx, totmat); mul_m3_m3m3(smat, td->ext->r_smtx, totmat);
/* calculate the total rotatation in eulers */ /* calculate the total rotatation in eulers */
copy_v3_v3(eul, td->ext->irot); copy_v3_v3(eul, td->ext->irot);
@ -3472,12 +3476,18 @@ static void applyTranslation(TransInfo *t, float vec[3])
/* handle snapping rotation before doing the translation */ /* handle snapping rotation before doing the translation */
if (usingSnappingNormal(t)) { if (usingSnappingNormal(t)) {
if (validSnappingNormal(t)) { if (validSnappingNormal(t)) {
float *original_normal = td->axismtx[2]; float *original_normal;
float axis[3]; float axis[3];
float quat[4]; float quat[4];
float mat[3][3]; float mat[3][3];
float angle; float angle;
/* In pose mode, we want to align normals with Y axis of bones... */
if (t->flag & T_POSE)
original_normal = td->axismtx[1];
else
original_normal = td->axismtx[2];
cross_v3_v3v3(axis, original_normal, t->tsnap.snapNormal); cross_v3_v3v3(axis, original_normal, t->tsnap.snapNormal);
angle = saacos(dot_v3v3(original_normal, t->tsnap.snapNormal)); angle = saacos(dot_v3v3(original_normal, t->tsnap.snapNormal));

@ -137,6 +137,10 @@ typedef struct TransDataExtension {
float isize[3]; /* Initial size */ float isize[3]; /* Initial size */
float obmat[4][4]; /* Object matrix */ float obmat[4][4]; /* Object matrix */
float l_smtx[3][3]; /* use instead of td->smtx, It is the same but without the 'bone->bone_mat', see TD_PBONE_LOCAL_MTX_C */ float l_smtx[3][3]; /* use instead of td->smtx, It is the same but without the 'bone->bone_mat', see TD_PBONE_LOCAL_MTX_C */
float r_mtx[3][3]; /* The rotscale matrix of pose bone, to allow using snap-align in translation mode,
* when td->mtx is the loc pose bone matrix (and hence can't be used to apply rotation in some cases,
* namely when a bone is in "NoLocal" or "Hinge" mode)... */
float r_smtx[3][3]; /* Invers of previous one. */
int rotOrder; /* rotation mode, as defined in eRotationModes (DNA_action_types.h) */ int rotOrder; /* rotation mode, as defined in eRotationModes (DNA_action_types.h) */
} TransDataExtension; } TransDataExtension;

@ -538,6 +538,7 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
/* New code, using "generic" BKE_pchan_to_pose_mat(). */ /* New code, using "generic" BKE_pchan_to_pose_mat(). */
{ {
float rotscale_mat[4][4], loc_mat[4][4]; float rotscale_mat[4][4], loc_mat[4][4];
float rpmat[3][3];
BKE_pchan_to_pose_mat(pchan, rotscale_mat, loc_mat); BKE_pchan_to_pose_mat(pchan, rotscale_mat, loc_mat);
if (t->mode == TFM_TRANSLATION) if (t->mode == TFM_TRANSLATION)
@ -545,13 +546,23 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
else else
copy_m3_m4(pmat, rotscale_mat); copy_m3_m4(pmat, rotscale_mat);
/* Grrr! Exceptional case: When translating pose bones that are either Hinge or NoLocal,
* and want align snapping, we just need both loc_mat and rotscale_mat.
* So simply always store rotscale mat in td->ext, and always use it to apply rotations...
* Ugly to need such hacks! :/ */
copy_m3_m4(rpmat, rotscale_mat);
if (constraints_list_needinv(t, &pchan->constraints)) { if (constraints_list_needinv(t, &pchan->constraints)) {
copy_m3_m4(tmat, pchan->constinv); copy_m3_m4(tmat, pchan->constinv);
invert_m3_m3(cmat, tmat); invert_m3_m3(cmat, tmat);
mul_serie_m3(td->mtx, pmat, omat, cmat, NULL, NULL, NULL, NULL, NULL); mul_serie_m3(td->mtx, pmat, omat, cmat, NULL, NULL, NULL, NULL, NULL);
mul_serie_m3(td->ext->r_mtx, rpmat, omat, cmat, NULL,NULL,NULL,NULL,NULL);
} }
else else {
mul_serie_m3(td->mtx, pmat, omat, NULL, NULL, NULL, NULL, NULL, NULL); mul_serie_m3(td->mtx, pmat, omat, NULL, NULL,NULL,NULL,NULL,NULL);
mul_serie_m3(td->ext->r_mtx, rpmat, omat, NULL, NULL,NULL,NULL,NULL,NULL);
}
invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx);
} }
invert_m3_m3(td->smtx, td->mtx); invert_m3_m3(td->smtx, td->mtx);