Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_object.h11
-rw-r--r--source/blender/blenkernel/intern/object.cc49
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_relations.c36
-rw-r--r--source/blender/editors/object/object_transform.cc32
6 files changed, 124 insertions, 6 deletions
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index eaeb6e6a2e4..faf878dfc2a 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -270,6 +270,17 @@ void BKE_object_apply_mat4(struct Object *ob,
const float mat[4][4],
bool use_compat,
bool use_parent);
+
+/**
+ * Use parent's world location and rotation as the child's origin. The parent inverse will
+ * become identity when the parent has no shearing. Otherwise, it is non-identity and contains the
+ * object's local matrix data that cannot be decomposed into location, rotation and scale.
+ *
+ * Assumes the object's world matrix has no shear.
+ * Assumes parent exists.
+ */
+void BKE_object_apply_parent_inverse(struct Object *ob);
+
void BKE_object_matrix_local_get(struct Object *ob, float r_mat[4][4]);
bool BKE_object_pose_context_check(const struct Object *ob);
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 92c350c5208..5ff1f6b950f 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -3558,6 +3558,55 @@ void BKE_object_apply_mat4(Object *ob,
BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : nullptr, ob->parentinv, use_compat);
}
+void BKE_object_apply_parent_inverse(struct Object *ob)
+{
+ /*
+ * Use parent's world transform as the child's origin.
+ *
+ * Let:
+ * local = identity
+ * world = orthonormalized(parent)
+ *
+ * Then:
+ * world = parent @ parentinv @ local
+ * inv(parent) @ world = parentinv
+ * parentinv = inv(parent) @ world
+ *
+ * NOTE: If ob->obmat has shear, then this `parentinv` is insufficient because
+ * parent @ parentinv => shearless result
+ *
+ * Thus, local will have shear which cannot be decomposed into TRS:
+ * local = inv(parent @ parentinv) @ world
+ *
+ * This is currently not supported for consistency in the handling of shear during the other
+ * parenting ops: Parent (Keep Transform), Clear [Parent] and Keep Transform.
+ */
+ float par_locrot[4][4], par_imat[4][4];
+ BKE_object_get_parent_matrix(ob, ob->parent, par_locrot);
+ invert_m4_m4(par_imat, par_locrot);
+
+ orthogonalize_m4_stable(par_locrot, 0, true);
+
+ mul_m4_m4m4(ob->parentinv, par_imat, par_locrot);
+
+ /* Now, preserve `world` given the new `parentinv`.
+ *
+ * world = parent @ parentinv @ local
+ * inv(parent) @ world = parentinv @ local
+ * inv(parentinv) @ inv(parent) @ world = local
+ *
+ * local = inv(parentinv) @ inv(parent) @ world
+ */
+ float ob_local[4][4];
+ copy_m4_m4(ob_local, ob->parentinv);
+ invert_m4(ob_local);
+ mul_m4_m4_post(ob_local, par_imat);
+ mul_m4_m4_post(ob_local, ob->obmat);
+
+ /* Send use_compat=False so the rotation is predictable. */
+ BKE_object_apply_mat4(ob, ob_local, false, false);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index dd6e11abbf9..eae08e89104 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -36,6 +36,7 @@ void OBJECT_OT_scale_clear(struct wmOperatorType *ot);
void OBJECT_OT_origin_clear(struct wmOperatorType *ot);
void OBJECT_OT_visual_transform_apply(struct wmOperatorType *ot);
void OBJECT_OT_transform_apply(struct wmOperatorType *ot);
+void OBJECT_OT_parent_inverse_apply(wmOperatorType *ot);
void OBJECT_OT_transform_axis_target(struct wmOperatorType *ot);
void OBJECT_OT_origin_set(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index cf5c349228f..ad0d6b88123 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -33,6 +33,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_origin_clear);
WM_operatortype_append(OBJECT_OT_visual_transform_apply);
WM_operatortype_append(OBJECT_OT_transform_apply);
+ WM_operatortype_append(OBJECT_OT_parent_inverse_apply);
WM_operatortype_append(OBJECT_OT_transform_axis_target);
WM_operatortype_append(OBJECT_OT_origin_set);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 7be46bdb24b..5ef8e573e27 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -936,8 +936,19 @@ static int parent_set_invoke_menu(bContext *C, wmOperatorType *ot)
RNA_boolean_set(&opptr, "keep_transform", true);
#endif
- uiItemO(
- layout, IFACE_("Object (Without Inverse)"), ICON_NONE, "OBJECT_OT_parent_no_inverse_set");
+ uiItemBooleanO(layout,
+ IFACE_("Object (Without Inverse)"),
+ ICON_NONE,
+ "OBJECT_OT_parent_no_inverse_set",
+ "keep_transform",
+ 0);
+
+ uiItemBooleanO(layout,
+ IFACE_("Object (Keep Transform Without Inverse)"),
+ ICON_NONE,
+ "OBJECT_OT_parent_no_inverse_set",
+ "keep_transform",
+ 1);
struct {
bool mesh, gpencil;
@@ -1055,6 +1066,8 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Object *par = ED_object_active_context(C);
+ const bool keep_transform = RNA_boolean_get(op->ptr, "keep_transform");
+
DEG_id_tag_update(&par->id, ID_RECALC_TRANSFORM);
/* context iterator */
@@ -1064,16 +1077,21 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Loop in parents");
}
else {
- /* clear inverse matrix and also the object location */
- unit_m4(ob->parentinv);
- memset(ob->loc, 0, sizeof(float[3]));
-
/* set recalc flags */
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
/* set parenting type for object - object only... */
ob->parent = par;
ob->partype = PAROBJECT; /* NOTE: DNA define, not operator property. */
+
+ if (keep_transform) {
+ BKE_object_apply_parent_inverse(ob);
+ continue;
+ }
+
+ /* clear inverse matrix and also the object location */
+ unit_m4(ob->parentinv);
+ memset(ob->loc, 0, sizeof(float[3]));
}
}
}
@@ -1100,6 +1118,12 @@ void OBJECT_OT_parent_no_inverse_set(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna,
+ "keep_transform",
+ false,
+ "Keep Transform",
+ "Preserve the world transform throughout parenting");
}
/** \} */
diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc
index 3d4d543012d..c0ec6c6678e 100644
--- a/source/blender/editors/object/object_transform.cc
+++ b/source/blender/editors/object/object_transform.cc
@@ -1173,6 +1173,38 @@ void OBJECT_OT_transform_apply(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+static int object_parent_inverse_apply_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
+ if (ob->parent == NULL) {
+ continue;
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ BKE_object_apply_parent_inverse(ob);
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_parent_inverse_apply(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Parent Inverse";
+ ot->description = "Apply the object's parent inverse to the its data";
+ ot->idname = "OBJECT_OT_parent_inverse_apply";
+
+ /* api callbacks */
+ ot->exec = object_parent_inverse_apply_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/** \} */
/* -------------------------------------------------------------------- */