Fix T92867: Gimbal rotation broken when used for multiple objects

Support gimbal orientation for objects & bones.
This commit is contained in:
Campbell Barton 2021-11-11 21:14:10 +11:00
parent bb64155c63
commit b7e2408ea4
Notes: blender-bot 2023-02-13 17:11:52 +01:00
Referenced by issue #93008, Cycles: Huge memory spike when saving tile to disk
Referenced by issue #92867, Gimbal rotation broken when used for multiple objects rotated about individual orgins
7 changed files with 68 additions and 19 deletions

View File

@ -621,6 +621,12 @@ typedef struct TransInfo {
O_SET,
} orient_curr;
/**
* All values from `TransInfo.orient[].type` converted into a flag
* to allow quickly checking which orientation types are used.
*/
int orient_type_mask;
short prop_mode;
/** Value taken as input, either through mouse coordinates or entered as a parameter. */

View File

@ -384,6 +384,29 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3])
add_v3_v3v3(out, in, vec);
}
static short transform_orientation_or_default(const TransInfo *t)
{
short orientation = t->orient[t->orient_curr].type;
if (orientation == V3D_ORIENT_CUSTOM_MATRIX) {
/* Use the real value of the "orient_type". */
orientation = t->orient[O_DEFAULT].type;
}
return orientation;
}
static const float (*transform_object_axismtx_get(const TransInfo *t,
const TransDataContainer *UNUSED(tc),
const TransData *td))[3]
{
if (transform_orientation_or_default(t) == V3D_ORIENT_GIMBAL) {
BLI_assert(t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL));
if (t->options & (CTX_POSE_BONE | CTX_OBJECT)) {
return td->ext->axismtx_gimbal;
}
}
return td->axismtx;
}
/**
* Generic callback for constant spatial constraints applied to linear motion
*
@ -489,7 +512,8 @@ static void applyObjectConstraintVec(const TransInfo *t,
copy_v3_v3(out, in);
if (t->con.mode & CON_APPLY) {
mul_m3_v3(t->spacemtx_inv, out);
mul_m3_v3(td->axismtx, out);
const float(*axismtx)[3] = transform_object_axismtx_get(t, tc, td);
mul_m3_v3(axismtx, out);
if (t->flag & T_EDIT) {
mul_m3_v3(tc->mat3_unit, out);
}
@ -535,7 +559,8 @@ static void applyObjectConstraintSize(const TransInfo *t,
float tmat[3][3];
float imat[3][3];
invert_m3_m3(imat, td->axismtx);
const float(*axismtx)[3] = transform_object_axismtx_get(t, tc, td);
invert_m3_m3(imat, axismtx);
if (!(t->con.mode & CON_AXIS0)) {
r_smat[0][0] = 1.0f;
@ -551,7 +576,7 @@ static void applyObjectConstraintSize(const TransInfo *t,
if (t->flag & T_EDIT) {
mul_m3_m3m3(r_smat, tc->mat3_unit, r_smat);
}
mul_m3_m3m3(r_smat, td->axismtx, tmat);
mul_m3_m3m3(r_smat, axismtx, tmat);
}
}
@ -647,7 +672,7 @@ static void applyObjectConstraintRot(const TransInfo *t,
axismtx = tmp_axismtx;
}
else {
axismtx = td->axismtx;
axismtx = transform_object_axismtx_get(t, tc, td);
}
constraints_rotation_impl(t, axismtx, r_axis, r_angle);
@ -712,17 +737,13 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
void setUserConstraint(TransInfo *t, int mode, const char ftext[])
{
char text[256];
short orientation = t->orient[t->orient_curr].type;
if (orientation == V3D_ORIENT_CUSTOM_MATRIX) {
/* Use the real value of the "orient_type". */
orientation = t->orient[0].type;
}
const short orientation = transform_orientation_or_default(t);
const char *spacename = transform_orientations_spacename_get(t, orientation);
BLI_snprintf(text, sizeof(text), ftext, spacename);
switch (orientation) {
case V3D_ORIENT_LOCAL:
case V3D_ORIENT_GIMBAL:
setLocalConstraint(t, mode, text);
break;
case V3D_ORIENT_NORMAL:
@ -734,7 +755,6 @@ void setUserConstraint(TransInfo *t, int mode, const char ftext[])
case V3D_ORIENT_GLOBAL:
case V3D_ORIENT_VIEW:
case V3D_ORIENT_CURSOR:
case V3D_ORIENT_GIMBAL:
case V3D_ORIENT_CUSTOM_MATRIX:
case V3D_ORIENT_CUSTOM:
default: {
@ -905,7 +925,7 @@ static void drawObjectConstraint(TransInfo *t)
TransData *td = tc->data;
for (int i = 0; i < tc->data_len; i++, td++) {
float co[3];
float(*axismtx)[3];
const float(*axismtx)[3];
if (t->flag & T_PROP_EDIT) {
/* we're sorted, so skip the rest */
@ -937,13 +957,14 @@ static void drawObjectConstraint(TransInfo *t)
mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx);
axismtx = tmp_axismtx;
}
else if (t->options & CTX_POSE_BONE) {
mul_v3_m4v3(co, tc->mat, td->center);
axismtx = td->axismtx;
}
else {
copy_v3_v3(co, td->center);
axismtx = td->axismtx;
if (t->options & CTX_POSE_BONE) {
mul_v3_m4v3(co, tc->mat, td->center);
}
else {
copy_v3_v3(co, td->center);
}
axismtx = transform_object_axismtx_get(t, tc, td);
}
if (t->con.mode & CON_AXIS0) {

View File

@ -662,6 +662,12 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
mul_m3_m3m3(td->axismtx, omat, pmat);
normalize_m3(td->axismtx);
if (t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL)) {
if (!gimbal_axis_pose(ob, pchan, td->ext->axismtx_gimbal)) {
copy_m3_m3(td->ext->axismtx_gimbal, td->axismtx);
}
}
if (t->mode == TFM_BONE_ENVELOPE_DIST) {
td->loc = NULL;
td->val = &bone->dist;

View File

@ -181,6 +181,11 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
/* axismtx has the real orientation */
transform_orientations_create_from_axis(td->axismtx, UNPACK3(ob->obmat));
if (t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL)) {
if (!gimbal_axis_object(ob, td->ext->axismtx_gimbal)) {
copy_m3_m3(td->ext->axismtx_gimbal, td->axismtx);
}
}
td->con = ob->constraints.first;

View File

@ -85,6 +85,8 @@ typedef struct TransDataExtension {
float isize[3];
/** Object matrix. */
float obmat[4][4];
/** Use for #V3D_ORIENT_GIMBAL orientation. */
float axismtx_gimbal[3][3];
/** Use instead of #TransData.smtx,
* It is the same but without the #Bone.bone_mat, see #TD_PBONE_LOCAL_MTX_C. */
float l_smtx[3][3];

View File

@ -512,6 +512,15 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
t->orient_type_mask = 0;
for (int i = 0; i < 3; i++) {
const int type = t->orient[i].type;
if (type < V3D_ORIENT_CUSTOM_MATRIX) {
BLI_assert(type < 32);
t->orient_type_mask |= (1 << type);
}
}
transform_orientations_current_set(t, (t->con.mode & CON_APPLY) ? 2 : 0);
}

View File

@ -515,7 +515,7 @@ static void protectflag_to_drawflags_pchan(RegionView3D *rv3d,
{
/* Protect-flags apply to local space in pose mode, so only let them influence axis
* visibility if we show the global orientation, otherwise it's confusing. */
if (orientation_index == V3D_ORIENT_LOCAL) {
if (ELEM(orientation_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) {
protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
}
}