Walk Navigation: Z axis correction

Fly navigation has always had this option. They is particularly useful
when users use "Trackball" as their orbit method.

For walk navigation this works as a one off option. Not as a toggle like
for fly navigation.

Differential Revision: https://developer.blender.org/D11863
This commit is contained in:
Dalai Felinto 2021-07-09 10:59:18 +02:00
parent c04cceb40e
commit c749c24682
2 changed files with 65 additions and 3 deletions

View File

@ -5551,6 +5551,7 @@ def km_view3d_walk_modal(_params):
("DECELERATE", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "any": True, "repeat": True}, None),
("ACCELERATE", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "any": True}, None),
("DECELERATE", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "any": True}, None),
("AXIS_LOCK_Z", {"type": 'Z', "value": 'PRESS'}, None),
])
return keymap

View File

@ -101,6 +101,7 @@ enum {
WALK_MODAL_GRAVITY_TOGGLE,
WALK_MODAL_ACCELERATE,
WALK_MODAL_DECELERATE,
WALK_MODAL_AXIS_LOCK_Z,
};
enum {
@ -129,6 +130,18 @@ typedef enum eWalkGravityState {
WALK_GRAVITY_STATE_ON,
} eWalkGravityState;
/* Relative view axis z axis locking. */
typedef enum eWalkLockState {
/* Disabled. */
WALK_AXISLOCK_STATE_OFF = 0,
/* Moving. */
WALK_AXISLOCK_STATE_ACTIVE = 2,
/* Done moving, it cannot be activated again. */
WALK_AXISLOCK_STATE_DONE = 3,
} eWalkLockState;
/* Called in transform_ops.c, on each regeneration of key-maps. */
void walk_modal_keymap(wmKeyConfig *keyconf)
{
@ -166,6 +179,8 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
{WALK_MODAL_GRAVITY_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"},
{WALK_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "Z Axis Correction", "Z axis correction"},
{0, NULL, 0, NULL, NULL},
};
@ -292,6 +307,10 @@ typedef struct WalkInfo {
/** To use for fast/slow speeds. */
float speed_factor;
eWalkLockState zlock;
/** Nicer dynamics. */
float zlock_momentum;
struct SnapObjectContext *snap_context;
struct View3DCameraControl *v3d_camera_control;
@ -540,6 +559,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->jump_height = U.walk_navigation.jump_height;
walk->speed = U.walk_navigation.walk_speed;
walk->speed_factor = U.walk_navigation.walk_speed_factor;
walk->zlock = WALK_AXISLOCK_STATE_OFF;
walk->gravity_state = WALK_GRAVITY_STATE_OFF;
@ -947,6 +967,13 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
walk_navigation_mode_set(walk, WALK_MODE_GRAVITY);
}
break;
case WALK_MODAL_AXIS_LOCK_Z:
if (walk->zlock != WALK_AXISLOCK_STATE_DONE) {
walk->zlock = WALK_AXISLOCK_STATE_ACTIVE;
walk->zlock_momentum = 0.0f;
}
break;
}
}
}
@ -986,6 +1013,8 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
#define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f)
#define WALK_MOVE_SPEED base_speed
#define WALK_BOOST_FACTOR ((void)0, walk->speed_factor)
#define WALK_ZUP_CORRECT_FAC 0.1f /* Amount to correct per step. */
#define WALK_ZUP_CORRECT_ACCEL 0.05f /* Increase upright momentum each step. */
RegionView3D *rv3d = walk->rv3d;
ARegion *region = walk->region;
@ -1020,20 +1049,25 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
/* Should we redraw? */
if ((walk->active_directions) || moffset[0] || moffset[1] ||
walk->teleport.state == WALK_TELEPORT_STATE_ON ||
walk->gravity_state != WALK_GRAVITY_STATE_OFF || is_confirm) {
walk->zlock == WALK_AXISLOCK_STATE_ACTIVE ||
walk->gravity_state != WALK_GRAVITY_STATE_OFF ||
walk->teleport.state == WALK_TELEPORT_STATE_ON || is_confirm) {
float dvec_tmp[3];
/* time how fast it takes for us to redraw,
* this is so simple scenes don't walk too fast */
double time_current;
float time_redraw;
float time_redraw_clamped;
#ifdef NDOF_WALK_DRAW_TOOMUCH
walk->redraw = 1;
#endif
time_current = PIL_check_seconds_timer();
time_redraw = (float)(time_current - walk->time_lastdraw);
/* Clamp redraw time to avoid jitter in roll correction. */
time_redraw_clamped = min_ff(0.05f, time_redraw);
walk->time_lastdraw = time_current;
/* base speed in m/s */
@ -1126,6 +1160,32 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
axis_angle_to_quat_single(tmp_quat, 'Z', x);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
}
if (walk->zlock == WALK_AXISLOCK_STATE_ACTIVE) {
float upvec[3];
copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
mul_m3_v3(mat, upvec);
/* Make sure we have some z rolling. */
if (fabsf(upvec[2]) > 0.00001f) {
float roll = upvec[2] * 5.0f;
/* Rotate the view about this axis. */
copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f);
mul_m3_v3(mat, upvec);
/* Rotate about the relative up vec. */
axis_angle_to_quat(tmp_quat,
upvec,
roll * time_redraw_clamped * walk->zlock_momentum *
WALK_ZUP_CORRECT_FAC);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
walk->zlock_momentum += WALK_ZUP_CORRECT_ACCEL;
}
else {
/* Lock fixed, don't need to check it ever again. */
walk->zlock = WALK_AXISLOCK_STATE_DONE;
}
}
}
/* WASD - 'move' translation code */
@ -1316,7 +1376,8 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
add_v3_v3(rv3d->ofs, dvec_tmp);
if (rv3d->persp == RV3D_CAMOB) {
walk->need_rotation_keyframe |= (moffset[0] || moffset[1]);
walk->need_rotation_keyframe |= (moffset[0] || moffset[1] ||
walk->zlock == WALK_AXISLOCK_STATE_ACTIVE);
walk->need_translation_keyframe |= (len_squared_v3(dvec_tmp) > FLT_EPSILON);
walkMoveCamera(
C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm);