Fix T80077: Objects disappear when joining with a zero scaled axis
Use invert_m4_m4_safe_ortho when joining objects so zero scaled axis doesn't cause all points to be scaled to zero. Instead geometry is left un-scaled on degenerate axes. Report a warning in this case since users may want to adjust the active objects scale.
This commit is contained in:
parent
19fe5529d7
commit
dedab68dcc
Notes:
blender-bot
2023-02-14 11:24:03 +01:00
Referenced by issue #80077, Joining with an object scaled to zero on one axis will make geometry disappear Referenced by issue #77348, Blender LTS: Maintenance Task 2.83
|
@ -304,7 +304,11 @@ int join_armature_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* Get editbones of active armature to add editbones to */
|
||||
/* Inverse transform for all selected armatures in this object,
|
||||
* See #object_join_exec for detailed comment on why the safe version is used. */
|
||||
invert_m4_m4_safe_ortho(oimat, ob_active->obmat);
|
||||
|
||||
/* Get edit-bones of active armature to add edit-bones to */
|
||||
ED_armature_to_edit(arm);
|
||||
|
||||
/* get pose of active object and move it out of posemode */
|
||||
|
@ -334,7 +338,6 @@ int join_armature_exec(bContext *C, wmOperator *op)
|
|||
// BASACT->flag &= ~OB_MODE_POSE;
|
||||
|
||||
/* Find the difference matrix */
|
||||
invert_m4_m4(oimat, ob_active->obmat);
|
||||
mul_m4_m4m4(mat, oimat, ob_iter->obmat);
|
||||
|
||||
/* Copy bones and posechannels from the object to the edit armature */
|
||||
|
|
|
@ -6925,8 +6925,9 @@ int join_curve_exec(bContext *C, wmOperator *op)
|
|||
|
||||
BLI_listbase_clear(&tempbase);
|
||||
|
||||
/* trasnform all selected curves inverse in obact */
|
||||
invert_m4_m4(imat, ob_active->obmat);
|
||||
/* Inverse transform for all selected curves in this object,
|
||||
* See #object_join_exec for detailed comment on why the safe version is used. */
|
||||
invert_m4_m4_safe_ortho(imat, ob_active->obmat);
|
||||
|
||||
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
|
||||
if (ob_iter->type == ob_active->type) {
|
||||
|
|
|
@ -2675,7 +2675,10 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
|
|||
|
||||
sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->obmat[3]);
|
||||
copy_m3_m4(bmat, ob_active->obmat);
|
||||
invert_m3_m3(imat, bmat);
|
||||
|
||||
/* Inverse transform for all selected curves in this object,
|
||||
* See #object_join_exec for detailed comment on why the safe version is used. */
|
||||
invert_m3_m3_safe_ortho(imat, bmat);
|
||||
mul_m3_v3(imat, offset_global);
|
||||
mul_v3_m3v3(offset_local, imat, offset_global);
|
||||
|
||||
|
@ -2686,7 +2689,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
|
|||
|
||||
/* recalculate all stroke points */
|
||||
BKE_gpencil_parent_matrix_get(depsgraph, ob_iter, gpl_src, diff_mat);
|
||||
invert_m4_m4(inverse_diff_mat, diff_mat);
|
||||
invert_m4_m4_safe_ortho(inverse_diff_mat, diff_mat);
|
||||
|
||||
Material *ma_src = NULL;
|
||||
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_new->frames) {
|
||||
|
|
|
@ -551,8 +551,9 @@ int join_mesh_exec(bContext *C, wmOperator *op)
|
|||
loopofs = 0;
|
||||
polyofs = 0;
|
||||
|
||||
/* inverse transform for all selected meshes in this object */
|
||||
invert_m4_m4(imat, ob->obmat);
|
||||
/* Inverse transform for all selected meshes in this object,
|
||||
* See #object_join_exec for detailed comment on why the safe version is used. */
|
||||
invert_m4_m4_safe_ortho(imat, ob->obmat);
|
||||
|
||||
/* Add back active mesh first.
|
||||
* This allows to keep things similar as they were, as much as possible
|
||||
|
|
|
@ -2929,20 +2929,45 @@ static int join_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
}
|
||||
|
||||
int ret = OPERATOR_CANCELLED;
|
||||
if (ob->type == OB_MESH) {
|
||||
return join_mesh_exec(C, op);
|
||||
ret = join_mesh_exec(C, op);
|
||||
}
|
||||
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
|
||||
return join_curve_exec(C, op);
|
||||
ret = join_curve_exec(C, op);
|
||||
}
|
||||
else if (ob->type == OB_ARMATURE) {
|
||||
return join_armature_exec(C, op);
|
||||
ret = join_armature_exec(C, op);
|
||||
}
|
||||
else if (ob->type == OB_GPENCIL) {
|
||||
return ED_gpencil_join_objects_exec(C, op);
|
||||
ret = ED_gpencil_join_objects_exec(C, op);
|
||||
}
|
||||
|
||||
return OPERATOR_CANCELLED;
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
/* Even though internally failure to invert is accounted for with a fallback,
|
||||
* show a warning since the result may not be what the user expects. See T80077.
|
||||
*
|
||||
* Failure to invert the matrix is typically caused by zero scaled axes
|
||||
* (which can be caused by constraints, even if the input scale isn't zero).
|
||||
*
|
||||
* Internally the join functions use #invert_m4_m4_safe_ortho which creates
|
||||
* an inevitable matrix from one that has one or more degenerate axes.
|
||||
*
|
||||
* In most cases we don't worry about special handling for non-inevitable matrices however for
|
||||
* joining objects there may be flat 2D objects where it's not obvious the scale is zero.
|
||||
* In this case, using #invert_m4_m4_safe_ortho works as well as we can expect,
|
||||
* joining the contents, flattening on the axis that's zero scaled.
|
||||
* If the zero scale is removed, the data on this axis remains un-scaled
|
||||
* (something that wouldn't work for #invert_m4_m4_safe). */
|
||||
float imat_test[4][4];
|
||||
if (!invert_m4_m4(imat_test, ob->obmat)) {
|
||||
BKE_report(op->reports,
|
||||
RPT_WARNING,
|
||||
"Active object final transform has one or more zero scaled axes");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void OBJECT_OT_join(wmOperatorType *ot)
|
||||
|
|
Loading…
Reference in New Issue