Fix T78691: Fly/Walk navigation ignores object channel locks

master
Campbell Barton 4 years ago
parent 70d7805fa9
commit f349a53c08

@ -197,6 +197,56 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph
return vctrl;
}
/**
* A version of #BKE_object_apply_mat4 that respects #Object.protectflag,
* applying the locking back to the view to avoid the view.
* This is needed so the view doesn't get out of sync with the object,
* causing visible jittering when in fly/walk mode for e.g.
*
* \note This could be exposed as an API option, as we might not want the view
* to be constrained by the thing it's controlling.
*/
static bool object_apply_mat4_with_protect(Object *ob,
const float obmat[4][4],
const bool use_parent,
/* Only use when applying lock. */
RegionView3D *rv3d,
const float view_mat[4][4])
{
const bool use_protect = (ob->protectflag != 0);
bool view_changed = false;
ObjectTfmProtectedChannels obtfm;
if (use_protect) {
BKE_object_tfm_protected_backup(ob, &obtfm);
}
BKE_object_apply_mat4(ob, obmat, true, use_parent);
if (use_protect) {
float obmat_noprotect[4][4], obmat_protect[4][4];
BKE_object_to_mat4(ob, obmat_noprotect);
BKE_object_tfm_protected_restore(ob, &obtfm, ob->protectflag);
BKE_object_to_mat4(ob, obmat_protect);
if (!equals_m4m4(obmat_noprotect, obmat_protect)) {
/* Apply the lock protection back to the view, without this the view
* keeps moving, ignoring the object locking, causing jittering in some cases. */
float diff_mat[4][4];
float view_mat_protect[4][4];
float obmat_noprotect_inv[4][4];
invert_m4_m4(obmat_noprotect_inv, obmat_noprotect);
mul_m4_m4m4(diff_mat, obmat_protect, obmat_noprotect_inv);
mul_m4_m4m4(view_mat_protect, diff_mat, view_mat);
ED_view3d_from_m4(view_mat_protect, rv3d->ofs, rv3d->viewquat, &rv3d->dist);
view_changed = true;
}
}
return view_changed;
}
/**
* Updates cameras from the ``rv3d`` values, optionally auto-keyframing.
*/
@ -216,21 +266,25 @@ void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
ID *id_key;
float view_mat[4][4];
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
/* transform the parent or the camera? */
if (vctrl->root_parent) {
Object *ob_update;
float view_mat[4][4];
float prev_view_imat[4][4];
float diff_mat[4][4];
float parent_mat[4][4];
invert_m4_m4(prev_view_imat, vctrl->view_mat_prev);
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
mul_m4_m4m4(diff_mat, view_mat, prev_view_imat);
mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->obmat);
BKE_object_apply_mat4(vctrl->root_parent, parent_mat, true, false);
if (object_apply_mat4_with_protect(vctrl->root_parent, parent_mat, false, rv3d, view_mat)) {
/* Calculate again since the view locking changes the matrix. */
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
}
ob_update = v3d->camera->parent;
while (ob_update) {
@ -243,18 +297,16 @@ void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
id_key = &vctrl->root_parent->id;
}
else {
float view_mat[4][4];
float scale_mat[4][4];
float scale_back[3];
/* even though we handle the scale matrix, this still changes over time */
copy_v3_v3(scale_back, v3d->camera->scale);
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
size_to_mat4(scale_mat, v3d->camera->scale);
mul_m4_m4m4(view_mat, view_mat, scale_mat);
BKE_object_apply_mat4(v3d->camera, view_mat, true, true);
object_apply_mat4_with_protect(v3d->camera, view_mat, true, rv3d, view_mat);
DEG_id_tag_update(&v3d->camera->id, ID_RECALC_TRANSFORM);

@ -16,6 +16,10 @@
/** \file
* \ingroup spview3d
*
* Interactive fly navigation modal operator (flying around in space).
*
* \note Similar logic to `view3d_walk.c` changes here may apply there too.
*/
/* defines VIEW3D_OT_fly modal operator */
@ -998,19 +1002,6 @@ static int flyApply(bContext *C, FlyInfo *fly, bool is_confirm)
interp_v3_v3v3(
dvec, dvec_tmp, fly->dvec_prev, (1.0f / (1.0f + (time_redraw * FLY_SMOOTH_FAC))));
if (rv3d->persp == RV3D_CAMOB) {
Object *lock_ob = ED_view3d_cameracontrol_object_get(fly->v3d_camera_control);
if (lock_ob->protectflag & OB_LOCK_LOCX) {
dvec[0] = 0.0;
}
if (lock_ob->protectflag & OB_LOCK_LOCY) {
dvec[1] = 0.0;
}
if (lock_ob->protectflag & OB_LOCK_LOCZ) {
dvec[2] = 0.0;
}
}
add_v3_v3(rv3d->ofs, dvec);
if (rv3d->persp == RV3D_CAMOB) {

@ -16,6 +16,11 @@
/** \file
* \ingroup spview3d
*
* Interactive walk navigation modal operator
* (similar to walking around in a first person game).
*
* \note Similar logic to `view3d_fly.c` changes here may apply there too.
*/
/* defines VIEW3D_OT_navigate - walk modal operator */
@ -1295,19 +1300,6 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
sub_v3_v3v3(dvec, cur_loc, new_loc);
}
if (rv3d->persp == RV3D_CAMOB) {
Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control);
if (lock_ob->protectflag & OB_LOCK_LOCX) {
dvec[0] = 0.0f;
}
if (lock_ob->protectflag & OB_LOCK_LOCY) {
dvec[1] = 0.0f;
}
if (lock_ob->protectflag & OB_LOCK_LOCZ) {
dvec[2] = 0.0f;
}
}
/* scale the movement to the scene size */
mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
add_v3_v3(rv3d->ofs, dvec_tmp);

Loading…
Cancel
Save