From ea58918171e7135e146e6bb90d988908d7c1540f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Feb 2014 10:00:16 +1100 Subject: NDOF: define 2 default navigation modes: free & orbit After some discussion it seems both are valid defaults but useful for very different purposes. - 'free' lets you explore the scene with full 6dof (like fly mode) - 'orbit' is closer to typical mouse view orbit, constraining to orbiting about a central location. This doesn't effect orbit/pan which are available with modifier keys. --- release/scripts/startup/bl_ui/space_userpref.py | 12 ++-- source/blender/editors/include/ED_view3d.h | 1 + .../editors/space_view3d/view3d_camera_control.c | 16 ++--- source/blender/editors/space_view3d/view3d_edit.c | 81 +++++++++++++++++----- source/blender/makesdna/DNA_userdef_types.h | 9 +-- source/blender/makesrna/intern/rna_userdef.c | 15 +++- 6 files changed, 94 insertions(+), 40 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 57485604cdc..b44b45e118d 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -950,18 +950,22 @@ class USERPREF_MT_ndof_settings(Menu): input_prefs = context.user_preferences.inputs - layout.prop(input_prefs, "ndof_sensitivity") - layout.prop(input_prefs, "ndof_orbit_sensitivity") - is_view3d = context.space_data.type == 'VIEW_3D' + layout.prop(input_prefs, "ndof_sensitivity") + if is_view3d: + layout.prop(input_prefs, "ndof_orbit_sensitivity") + if is_view3d: layout.separator() layout.prop(input_prefs, "ndof_show_guide") layout.separator() - layout.label(text="Orbit options") + layout.label(text="Orbit style") + layout.row().prop(input_prefs, "ndof_view_navigate_method", text="") layout.row().prop(input_prefs, "ndof_view_rotate_method", text="") + layout.separator() + layout.label(text="Orbit options") layout.prop(input_prefs, "ndof_rotx_invert_axis") layout.prop(input_prefs, "ndof_roty_invert_axis") layout.prop(input_prefs, "ndof_rotz_invert_axis") diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 8fce5e7e7c0..a42b352ad51 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -335,6 +335,7 @@ void ED_view3D_background_image_clear(struct View3D *v3d); #define VIEW3D_MARGIN 1.4f #define VIEW3D_DIST_FALLBACK 1.0f float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float dist_fallback); +void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist); float ED_scene_grid_scale(struct Scene *scene, const char **grid_unit); float ED_view3d_grid_scale(struct Scene *scene, struct View3D *v3d, const char **grid_unit); diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index 2797125485c..230df49f386 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -185,7 +185,6 @@ struct View3DCameraControl *ED_view3d_cameracontrol_aquire( rv3d->dist = 0.0; } else { - float tvec[3]; /* perspective or ortho */ if (rv3d->persp == RV3D_ORTHO) rv3d->persp = RV3D_PERSP; /* if ortho projection, make perspective */ @@ -200,11 +199,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_aquire( * but to correct the dist removal we must * alter offset so the view doesn't jump. */ - rv3d->dist = 0.0f; - - copy_v3_fl3(tvec, 0.0f, 0.0f, vctrl->dist_backup); - mul_mat3_m4_v3(rv3d->viewinv, tvec); - sub_v3_v3(rv3d->ofs, tvec); + ED_view3d_distance_set(rv3d, 0.0f); /* Done with correcting for the dist */ } @@ -316,7 +311,6 @@ void ED_view3d_cameracontrol_release( View3D *v3d = vctrl->ctx_v3d; RegionView3D *rv3d = vctrl->ctx_rv3d; - rv3d->dist = vctrl->dist_backup; if (restore) { /* Revert to original view? */ if (vctrl->persp_backup == RV3D_CAMOB) { /* a camera view */ @@ -334,21 +328,19 @@ void ED_view3d_cameracontrol_release( } /* always, is set to zero otherwise */ copy_v3_v3(rv3d->ofs, vctrl->ofs_backup); + rv3d->dist = vctrl->dist_backup; } else if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */ DAG_id_tag_update((ID *)view3d_cameracontrol_object(vctrl), OB_RECALC_OB); /* always, is set to zero otherwise */ copy_v3_v3(rv3d->ofs, vctrl->ofs_backup); + rv3d->dist = vctrl->dist_backup; } else { /* not camera */ - float tvec[3]; - /* Apply the fly mode view */ /* restore the dist */ - copy_v3_fl3(tvec, 0.0f, 0.0f, vctrl->dist_backup); - mul_mat3_m4_v3(rv3d->viewinv, tvec); - add_v3_v3(rv3d->ofs, tvec); + ED_view3d_distance_set(rv3d, vctrl->dist_backup); /* Done with correcting for the dist */ } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 03c0063babe..faee6514616 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -1219,15 +1219,18 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, ScrArea *s } -static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, RegionView3D *rv3d, const float dt, +static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, /* optional, can be NULL*/ ViewOpsData *vod) { + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + float view_inv[4]; BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); - view3d_ensure_persp(vod->v3d, vod->ar); + view3d_ensure_persp(v3d, ar); rv3d->view = RV3D_VIEW_USER; @@ -1247,13 +1250,13 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, RegionView3D mul_qt_v3(view_inv, xvec); /* Perform the up/down rotation */ - angle = dt * rot[0]; + angle = ndof->dt * rot[0]; quat[0] = cosf(angle); mul_v3_v3fl(quat + 1, xvec, sin(angle)); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); /* Perform the orbital rotation */ - angle = dt * rot[1]; + angle = ndof->dt * rot[1]; /* update the onscreen doo-dad */ rv3d->rot_angle = angle; @@ -1432,7 +1435,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) View3D *v3d; RegionView3D *rv3d; - wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata; + const wmNDOFMotionData *ndof = event->customdata; viewops_data_alloc(C, op); viewops_data_create(C, op, event); @@ -1457,7 +1460,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) } if (has_rotation) { - view3d_ndof_orbit(ndof, rv3d, ndof->dt, vod); + view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod); } } @@ -1497,7 +1500,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev View3D *v3d; RegionView3D *rv3d; - wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata; + const wmNDOFMotionData *ndof = event->customdata; viewops_data_alloc(C, op); viewops_data_create(C, op, event); @@ -1511,21 +1514,49 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev ED_view3d_camera_lock_init(v3d, rv3d); - if (ndof->progress != P_FINISHING) { - const bool has_rotation = NDOF_HAS_ROTATE && (RV3D_VIEW_IS_AXIS(rv3d->view) == false); + if (ndof->progress == P_FINISHING) { + /* pass */ + } + else if (RV3D_VIEW_IS_AXIS(rv3d->view)) { /* if we can't rotate, fallback to translate (locked axis views) */ const bool has_translate = NDOF_HAS_TRANSLATE; - /* always zoom since this is the main purpose of the function */ - const bool has_zoom = true; - if (has_translate || has_zoom) { + if (has_translate) { view3d_ndof_pan_zoom(ndof, vod->sa, vod->ar, has_translate, true); } + } + else if (U.ndof_flag & NDOF_MODE_ORBIT) { + const bool has_rotation = NDOF_HAS_ROTATE; + const bool has_zoom = (ndof->tvec[2] != 0.0f); + + if (has_zoom) { + view3d_ndof_pan_zoom(ndof, vod->sa, vod->ar, false, has_zoom); + } if (has_rotation) { - view3d_ndof_orbit(ndof, rv3d, ndof->dt, vod); + view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod); } } + else { /* free/explore (like fly mode) */ + Scene *scene = CTX_data_scene(C); + const bool has_rotation = NDOF_HAS_ROTATE; + const bool has_translate = NDOF_HAS_TRANSLATE; + + const float dist_backup = rv3d->dist; + + if (has_translate) { + view3d_ndof_pan_zoom(ndof, vod->sa, vod->ar, true, false); + } + + ED_view3d_distance_set(rv3d, 0.0f); + + if (has_rotation) { + view3d_ndof_orbit(ndof, vod->sa, vod->ar, NULL); + } + + ED_view3d_update_viewmat(scene, v3d, vod->ar, NULL, NULL); + ED_view3d_distance_set(rv3d, dist_backup); + } ED_view3d_camera_lock_sync(v3d, rv3d); @@ -1563,7 +1594,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e else { View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); - wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata; + const wmNDOFMotionData *ndof = event->customdata; const bool has_translate = NDOF_HAS_TRANSLATE; const bool has_zoom = !rv3d->is_persp; @@ -1622,7 +1653,7 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, const wmEvent *event) View3D *v3d; RegionView3D *rv3d; - wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata; + const wmNDOFMotionData *ndof = event->customdata; viewops_data_alloc(C, op); viewops_data_create(C, op, event); @@ -1646,7 +1677,7 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, const wmEvent *event) } if (has_rotation) { - view3d_ndof_orbit(ndof, rv3d, ndof->dt, vod); + view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod); } } @@ -4561,6 +4592,24 @@ float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float return dist; } +/** + * Set the dist without moving the view (compensate with #RegionView3D.ofs) + * + * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first. + */ +void ED_view3d_distance_set(RegionView3D *rv3d, const float dist) +{ + float tvec[3]; + + BLI_assert(dist >= 0.0f); + + copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist); + mul_mat3_m4_v3(rv3d->viewinv, tvec); + sub_v3_v3(rv3d->ofs, tvec); + + rv3d->dist = dist; +} + /** * Set the view transformation from a 4x4 matrix. * diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 1705a0d16c5..4248efd0919 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -782,13 +782,10 @@ typedef enum eNdof_Flag { NDOF_SHOULD_ZOOM = (1 << 4), NDOF_SHOULD_ROTATE = (1 << 5), - /* orbit navigation modes - * only two options, so it's sort of a hybrid bool/enum - * if ((U.ndof_flag & NDOF_ORBIT_MODE) == NDOF_OM_OBJECT)... */ + /* orbit navigation modes */ - // NDOF_ORBIT_MODE = (1 << 6), - // #define NDOF_OM_TARGETCAMERA 0 - // #define NDOF_OM_OBJECT NDOF_ORBIT_MODE + /* exposed as Orbit|Explore in the UI */ + NDOF_MODE_ORBIT = (1 << 6), /* actually... users probably don't care about what the mode * is called, just that it feels right */ diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 0910ee65d6b..cca619c1a55 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -3947,19 +3947,25 @@ static void rna_def_userdef_input(BlenderRNA *brna) {0, "RIGHT", 0, "Right", "Use Right Mouse Button for selection"}, {0, NULL, 0, NULL, NULL} }; - + static EnumPropertyItem view_rotation_items[] = { {0, "TURNTABLE", 0, "Turntable", "Use turntable style rotation in the viewport"}, {USER_TRACKBALL, "TRACKBALL", 0, "Trackball", "Use trackball style rotation in the viewport"}, {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem ndof_view_navigation_items[] = { + {0, "FREE", 0, "Free", "Use full 6 degrees of freedom by default"}, + {NDOF_MODE_ORBIT, "ORBIT", 0, "Orbit", "Orbit about the view center by default"}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem ndof_view_rotation_items[] = { {NDOF_TURNTABLE, "TURNTABLE", 0, "Turntable", "Use turntable style rotation in the viewport"}, {0, "TRACKBALL", 0, "Trackball", "Use trackball style rotation in the viewport"}, {0, NULL, 0, NULL, NULL} }; - + static EnumPropertyItem view_zoom_styles[] = { {USER_ZOOM_CONT, "CONTINUE", 0, "Continue", "Old style zoom, continues while moving mouse up or down"}, {USER_ZOOM_DOLLY, "DOLLY", 0, "Dolly", "Zoom in and out based on vertical mouse movement"}, @@ -4062,6 +4068,11 @@ static void rna_def_userdef_input(BlenderRNA *brna) /* TODO: update description when fly-mode visuals are in place ("projected position in fly mode")*/ /* 3D view */ + prop = RNA_def_property(srna, "ndof_view_navigate_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "ndof_flag"); + RNA_def_property_enum_items(prop, ndof_view_navigation_items); + RNA_def_property_ui_text(prop, "NDOF View Navigate", "Navigation style in the viewport"); + prop = RNA_def_property(srna, "ndof_view_rotate_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "ndof_flag"); RNA_def_property_enum_items(prop, ndof_view_rotation_items); -- cgit v1.2.3