2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2008-12-19 12:14:58 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
2008-12-26 10:31:44 +00:00
|
|
|
* of the License, or (at your option) any later version.
|
2008-12-19 12:14:58 +00:00
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2008-12-19 12:14:58 +00:00
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup spview3d
|
2018-01-23 19:48:49 +11:00
|
|
|
*
|
|
|
|
|
* 3D view manipulation/operators.
|
2011-02-27 20:29:51 +00:00
|
|
|
*/
|
|
|
|
|
|
2008-12-19 12:14:58 +00:00
|
|
|
#include <float.h>
|
2020-03-19 09:33:03 +01:00
|
|
|
#include <math.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
2008-12-19 12:14:58 +00:00
|
|
|
|
2008-12-20 11:33:16 +00:00
|
|
|
#include "DNA_armature_types.h"
|
2017-10-26 21:40:37 +11:00
|
|
|
#include "DNA_camera_types.h"
|
2014-05-12 11:19:55 +10:00
|
|
|
#include "DNA_curve_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_gpencil_types.h"
|
2008-12-19 12:14:58 +00:00
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2008-12-19 12:14:58 +00:00
|
|
|
|
2018-11-07 18:00:24 +01:00
|
|
|
#include "BKE_action.h"
|
2015-09-04 04:18:49 +10:00
|
|
|
#include "BKE_armature.h"
|
2011-11-18 23:32:17 +00:00
|
|
|
#include "BKE_camera.h"
|
2008-12-19 17:14:02 +00:00
|
|
|
#include "BKE_context.h"
|
2014-05-12 11:19:55 +10:00
|
|
|
#include "BKE_font.h"
|
2020-03-19 11:35:17 +01:00
|
|
|
#include "BKE_gpencil_geom.h"
|
2017-11-08 12:16:49 -02:00
|
|
|
#include "BKE_layer.h"
|
2020-02-10 12:58:59 +01:00
|
|
|
#include "BKE_lib_id.h"
|
2018-05-31 12:27:47 +02:00
|
|
|
#include "BKE_main.h"
|
2008-12-19 12:14:58 +00:00
|
|
|
#include "BKE_object.h"
|
2009-08-15 19:48:50 +00:00
|
|
|
#include "BKE_paint.h"
|
2009-01-21 02:24:12 +00:00
|
|
|
#include "BKE_report.h"
|
2008-12-19 12:14:58 +00:00
|
|
|
#include "BKE_scene.h"
|
2011-05-20 04:14:29 +00:00
|
|
|
#include "BKE_screen.h"
|
2017-06-08 10:14:53 +02:00
|
|
|
|
|
|
|
|
#include "DEG_depsgraph.h"
|
2018-05-20 19:10:16 +02:00
|
|
|
#include "DEG_depsgraph_query.h"
|
2008-12-19 12:14:58 +00:00
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
2018-05-06 16:41:32 +02:00
|
|
|
#include "WM_message.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "WM_types.h"
|
2008-12-19 12:14:58 +00:00
|
|
|
|
2008-12-19 19:27:41 +00:00
|
|
|
#include "RNA_access.h"
|
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
|
2012-05-05 16:38:23 +00:00
|
|
|
#include "ED_armature.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "ED_mesh.h"
|
2009-02-20 20:39:27 +00:00
|
|
|
#include "ED_particle.h"
|
2008-12-19 12:14:58 +00:00
|
|
|
#include "ED_screen.h"
|
2009-07-08 16:17:47 +00:00
|
|
|
#include "ED_transform.h"
|
2018-05-08 14:18:09 +02:00
|
|
|
#include "ED_transform_snap_object_context.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "ED_view3d.h"
|
2008-12-19 12:14:58 +00:00
|
|
|
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
#include "UI_resources.h"
|
2008-12-19 12:14:58 +00:00
|
|
|
|
2018-01-28 18:22:54 +11:00
|
|
|
#include "PIL_time.h"
|
2008-12-19 12:14:58 +00:00
|
|
|
|
2012-07-08 20:36:00 +00:00
|
|
|
#include "view3d_intern.h" /* own include */
|
2019-03-20 18:05:35 +11:00
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
HAS_TRANSLATE = (1 << 0),
|
|
|
|
|
HAS_ROTATE = (1 << 0),
|
|
|
|
|
};
|
|
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
/* test for unlocked camera view in quad view */
|
|
|
|
|
static bool view3d_camera_user_poll(bContext *C)
|
|
|
|
|
{
|
|
|
|
|
View3D *v3d;
|
|
|
|
|
ARegion *region;
|
|
|
|
|
|
|
|
|
|
if (ED_view3d_context_user_region(C, &v3d, ®ion)) {
|
|
|
|
|
RegionView3D *rv3d = region->regiondata;
|
|
|
|
|
if ((rv3d->persp == RV3D_CAMOB) && !(RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM)) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool view3d_lock_poll(bContext *C)
|
|
|
|
|
{
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
if (v3d) {
|
|
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
|
|
|
|
if (rv3d) {
|
|
|
|
|
return ED_view3d_offset_lock_check(v3d, rv3d);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool view3d_pan_poll(bContext *C)
|
|
|
|
|
{
|
|
|
|
|
if (ED_operator_region_view3d_active(C)) {
|
|
|
|
|
const RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
|
|
|
|
return !(RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_LOCATION);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool view3d_zoom_or_dolly_poll(bContext *C)
|
|
|
|
|
{
|
|
|
|
|
if (ED_operator_region_view3d_active(C)) {
|
|
|
|
|
const RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
|
|
|
|
return !(RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ZOOM_AND_DOLLY);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-28 18:22:54 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Generic View Operator Properties
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
enum eV3D_OpPropFlag {
|
|
|
|
|
V3D_OP_PROP_MOUSE_CO = (1 << 0),
|
|
|
|
|
V3D_OP_PROP_DELTA = (1 << 1),
|
|
|
|
|
V3D_OP_PROP_USE_ALL_REGIONS = (1 << 2),
|
2018-01-29 13:46:18 +11:00
|
|
|
V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3),
|
2018-01-28 18:22:54 +11:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPropFlag flag)
|
|
|
|
|
{
|
|
|
|
|
if (flag & V3D_OP_PROP_MOUSE_CO) {
|
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Region Position X", "", 0, INT_MAX);
|
|
|
|
|
RNA_def_property_flag(prop, PROP_HIDDEN);
|
|
|
|
|
prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Region Position Y", "", 0, INT_MAX);
|
|
|
|
|
RNA_def_property_flag(prop, PROP_HIDDEN);
|
|
|
|
|
}
|
|
|
|
|
if (flag & V3D_OP_PROP_DELTA) {
|
|
|
|
|
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
|
|
|
|
|
}
|
|
|
|
|
if (flag & V3D_OP_PROP_USE_ALL_REGIONS) {
|
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
prop = RNA_def_boolean(
|
|
|
|
|
ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions");
|
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
}
|
2018-01-29 13:46:18 +11:00
|
|
|
if (flag & V3D_OP_PROP_USE_MOUSE_INIT) {
|
2019-05-31 19:53:24 +10:00
|
|
|
WM_operator_properties_use_cursor_init(ot);
|
2018-01-29 13:46:18 +11:00
|
|
|
}
|
2018-01-28 18:22:54 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Generic View Operator Custom-Data
|
|
|
|
|
* \{ */
|
2008-12-19 12:14:58 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
typedef struct ViewOpsData {
|
2018-01-29 14:36:40 +11:00
|
|
|
/** Context pointers (assigned by #viewops_data_alloc). */
|
2018-06-08 12:16:37 +02:00
|
|
|
Main *bmain;
|
2015-04-24 00:12:16 +10:00
|
|
|
Scene *scene;
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area;
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2011-05-14 05:42:58 +00:00
|
|
|
View3D *v3d;
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
RegionView3D *rv3d;
|
2018-01-29 17:32:20 +11:00
|
|
|
Depsgraph *depsgraph;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
/** Needed for continuous zoom. */
|
2009-12-16 23:05:59 +00:00
|
|
|
wmTimer *timer;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
/** Viewport state on initialization, don't change afterwards. */
|
|
|
|
|
struct {
|
|
|
|
|
float dist;
|
|
|
|
|
float camzoom;
|
|
|
|
|
float quat[4];
|
|
|
|
|
/** #wmEvent.x, y. */
|
|
|
|
|
int event_xy[2];
|
2018-01-29 16:17:47 +11:00
|
|
|
/** Offset to use when #VIEWOPS_FLAG_USE_MOUSE_INIT is not set.
|
|
|
|
|
* so we can simulate pressing in the middle of the screen. */
|
|
|
|
|
int event_xy_offset[2];
|
2018-01-29 14:36:40 +11:00
|
|
|
/** #wmEvent.type that triggered the operator. */
|
|
|
|
|
int event_type;
|
|
|
|
|
float ofs[3];
|
|
|
|
|
/** Initial distance to 'ofs'. */
|
|
|
|
|
float zfac;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
/** Trackball rotation only. */
|
|
|
|
|
float trackvec[3];
|
|
|
|
|
/** Dolly only. */
|
|
|
|
|
float mousevec[3];
|
2020-01-22 07:57:25 +11:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* #RegionView3D.persp set after auto-perspective is applied.
|
|
|
|
|
* If we want the value before running the operator, add a separate member.
|
|
|
|
|
*/
|
|
|
|
|
char persp;
|
2018-01-29 14:36:40 +11:00
|
|
|
} init;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
/** Previous state (previous modal event handled). */
|
|
|
|
|
struct {
|
|
|
|
|
int event_xy[2];
|
|
|
|
|
/** For operators that use time-steps (continuous zoom). */
|
|
|
|
|
double time;
|
|
|
|
|
} prev;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
/** Current state. */
|
|
|
|
|
struct {
|
|
|
|
|
/** Working copy of #RegionView3D.viewquat, needed for rotation calculation
|
2020-12-02 18:16:04 -05:00
|
|
|
* so we can apply snap to the 3D Viewport while keeping the unsnapped rotation
|
2018-01-29 14:36:40 +11:00
|
|
|
* here to use when snap is disabled and for continued calculation. */
|
|
|
|
|
float viewquat[4];
|
|
|
|
|
} curr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-04-04 04:22:38 +00:00
|
|
|
float reverse;
|
2013-03-20 23:14:18 +00:00
|
|
|
bool axis_snap; /* view rotate only */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
/** Use for orbit selection and auto-dist. */
|
|
|
|
|
float dyn_ofs[3];
|
2013-03-22 04:40:45 +00:00
|
|
|
bool use_dyn_ofs;
|
2008-12-19 17:14:02 +00:00
|
|
|
} ViewOpsData;
|
2008-12-19 12:14:58 +00:00
|
|
|
|
2019-08-04 12:52:01 +10:00
|
|
|
/**
|
2020-03-19 20:33:23 +01:00
|
|
|
* Size of the sphere being dragged for trackball rotation within the view bounds.
|
2019-08-04 12:52:01 +10:00
|
|
|
* also affects speed (smaller is faster).
|
|
|
|
|
*/
|
2015-10-13 16:26:00 +11:00
|
|
|
#define TRACKBALLSIZE (1.1f)
|
2008-12-19 12:14:58 +00:00
|
|
|
|
2019-08-04 01:18:23 +10:00
|
|
|
static void calctrackballvec(const rcti *rect, const int event_xy[2], float r_dir[3])
|
2008-12-19 12:14:58 +00:00
|
|
|
{
|
2016-12-17 19:12:07 +11:00
|
|
|
const float radius = TRACKBALLSIZE;
|
|
|
|
|
const float t = radius / (float)M_SQRT2;
|
2019-08-04 01:19:22 +10:00
|
|
|
const float size[2] = {BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)};
|
2019-08-04 12:52:01 +10:00
|
|
|
/* Aspect correct so dragging in a non-square view doesn't squash the direction.
|
|
|
|
|
* So diagonal motion rotates the same direction the cursor is moving. */
|
2019-08-04 01:19:22 +10:00
|
|
|
const float size_min = min_ff(size[0], size[1]);
|
|
|
|
|
const float aspect[2] = {size_min / size[0], size_min / size[1]};
|
2019-08-04 01:18:23 +10:00
|
|
|
|
|
|
|
|
/* Normalize x and y. */
|
2019-08-04 01:19:22 +10:00
|
|
|
r_dir[0] = (event_xy[0] - BLI_rcti_cent_x(rect)) / ((size[0] * aspect[0]) / 2.0);
|
2019-08-07 21:02:19 +10:00
|
|
|
r_dir[1] = (event_xy[1] - BLI_rcti_cent_y(rect)) / ((size[1] * aspect[1]) / 2.0);
|
2019-08-04 01:18:23 +10:00
|
|
|
const float d = len_v2(r_dir);
|
|
|
|
|
if (d < t) {
|
|
|
|
|
/* Inside sphere. */
|
2020-03-06 17:18:10 +01:00
|
|
|
r_dir[2] = sqrtf(square_f(radius) - square_f(d));
|
2011-08-25 15:49:52 +00:00
|
|
|
}
|
2019-08-04 01:18:23 +10:00
|
|
|
else {
|
|
|
|
|
/* On hyperbola. */
|
2020-03-06 17:18:10 +01:00
|
|
|
r_dir[2] = square_f(t) / d;
|
2008-12-19 12:14:58 +00:00
|
|
|
}
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-09-20 01:24:00 +00:00
|
|
|
/**
|
|
|
|
|
* Allocate and fill in context pointers for #ViewOpsData
|
|
|
|
|
*/
|
|
|
|
|
static void viewops_data_alloc(bContext *C, wmOperator *op)
|
2008-12-19 17:14:02 +00:00
|
|
|
{
|
2012-03-25 23:54:33 +00:00
|
|
|
ViewOpsData *vod = MEM_callocN(sizeof(ViewOpsData), "viewops data");
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* store data */
|
2012-03-25 23:54:33 +00:00
|
|
|
op->customdata = vod;
|
2018-06-08 12:16:37 +02:00
|
|
|
vod->bmain = CTX_data_main(C);
|
2019-07-25 16:36:22 +02:00
|
|
|
vod->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2015-04-24 00:12:16 +10:00
|
|
|
vod->scene = CTX_data_scene(C);
|
2020-04-03 13:25:03 +02:00
|
|
|
vod->area = CTX_wm_area(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
vod->region = CTX_wm_region(C);
|
2020-04-03 13:25:03 +02:00
|
|
|
vod->v3d = vod->area->spacedata.first;
|
2020-03-06 16:56:42 +01:00
|
|
|
vod->rv3d = vod->region->regiondata;
|
2013-09-20 01:24:00 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-23 05:04:52 +11:00
|
|
|
void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
|
2020-09-04 20:59:13 +02:00
|
|
|
const float ofs_old[3],
|
2018-01-29 14:36:40 +11:00
|
|
|
const float viewquat_old[4],
|
2015-12-23 05:04:52 +11:00
|
|
|
const float viewquat_new[4],
|
|
|
|
|
const float dyn_ofs[3])
|
2014-04-30 02:16:01 +10:00
|
|
|
{
|
2015-12-23 05:04:52 +11:00
|
|
|
float q[4];
|
|
|
|
|
invert_qt_qt_normalized(q, viewquat_old);
|
|
|
|
|
mul_qt_qtqt(q, q, viewquat_new);
|
2014-04-30 02:16:01 +10:00
|
|
|
|
2015-12-23 05:04:52 +11:00
|
|
|
invert_qt_normalized(q);
|
2014-04-30 02:16:01 +10:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
sub_v3_v3v3(r_ofs, ofs_old, dyn_ofs);
|
2015-12-23 05:04:52 +11:00
|
|
|
mul_qt_v3(q, r_ofs);
|
2014-04-30 02:16:01 +10:00
|
|
|
add_v3_v3(r_ofs, dyn_ofs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
|
|
|
|
|
{
|
|
|
|
|
static float lastofs[3] = {0, 0, 0};
|
|
|
|
|
bool is_set = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-07-25 16:36:22 +02:00
|
|
|
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2014-04-30 02:16:01 +10:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2018-05-21 20:29:00 +02:00
|
|
|
ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
|
2018-11-23 14:41:38 -02:00
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2018-05-21 20:29:00 +02:00
|
|
|
Object *ob_act_eval = OBACT(view_layer_eval);
|
|
|
|
|
Object *ob_act = DEG_get_original_object(ob_act_eval);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-04-05 18:20:27 +02:00
|
|
|
if (ob_act && (ob_act->mode & OB_MODE_ALL_PAINT) &&
|
2015-08-25 23:25:05 +10:00
|
|
|
/* with weight-paint + pose-mode, fall through to using calculateTransformCenter */
|
2018-04-05 18:20:27 +02:00
|
|
|
((ob_act->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(ob_act)) == 0) {
|
2014-04-30 02:16:01 +10:00
|
|
|
/* in case of sculpting use last average stroke position as a rotation
|
|
|
|
|
* center, in other cases it's not clear what rotation center shall be
|
|
|
|
|
* so just rotate around object origin
|
|
|
|
|
*/
|
2018-04-05 18:20:27 +02:00
|
|
|
if (ob_act->mode &
|
|
|
|
|
(OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
|
2014-04-30 02:16:01 +10:00
|
|
|
float stroke[3];
|
2018-05-21 20:29:00 +02:00
|
|
|
BKE_paint_stroke_get_average(scene, ob_act_eval, stroke);
|
2014-04-30 02:16:01 +10:00
|
|
|
copy_v3_v3(lastofs, stroke);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2018-05-21 20:29:00 +02:00
|
|
|
copy_v3_v3(lastofs, ob_act_eval->obmat[3]);
|
2014-04-30 02:16:01 +10:00
|
|
|
}
|
|
|
|
|
is_set = true;
|
|
|
|
|
}
|
2018-04-05 18:20:27 +02:00
|
|
|
else if (ob_act && (ob_act->mode & OB_MODE_EDIT) && (ob_act->type == OB_FONT)) {
|
2018-05-21 20:29:00 +02:00
|
|
|
Curve *cu = ob_act_eval->data;
|
2014-05-12 11:19:55 +10:00
|
|
|
EditFont *ef = cu->editfont;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-05-12 11:19:55 +10:00
|
|
|
zero_v3(lastofs);
|
2020-09-09 18:41:07 +02:00
|
|
|
for (int i = 0; i < 4; i++) {
|
2014-05-12 11:19:55 +10:00
|
|
|
add_v2_v2(lastofs, ef->textcurs[i]);
|
|
|
|
|
}
|
|
|
|
|
mul_v2_fl(lastofs, 1.0f / 4.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
mul_m4_v3(ob_act_eval->obmat, lastofs);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-05-12 11:19:55 +10:00
|
|
|
is_set = true;
|
|
|
|
|
}
|
2018-04-05 18:20:27 +02:00
|
|
|
else if (ob_act == NULL || ob_act->mode == OB_MODE_OBJECT) {
|
2014-08-11 13:34:28 +10:00
|
|
|
/* object mode use boundbox centers */
|
2018-05-21 20:29:00 +02:00
|
|
|
Base *base_eval;
|
2019-03-01 23:43:34 +11:00
|
|
|
uint tot = 0;
|
2014-08-11 13:34:28 +10:00
|
|
|
float select_center[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-08-11 13:34:28 +10:00
|
|
|
zero_v3(select_center);
|
2018-05-21 20:29:00 +02:00
|
|
|
for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) {
|
2019-01-08 18:19:12 +01:00
|
|
|
if (BASE_SELECTED(v3d, base_eval)) {
|
2014-08-11 13:34:28 +10:00
|
|
|
/* use the boundbox if we can */
|
2018-05-21 20:29:00 +02:00
|
|
|
Object *ob_eval = base_eval->object;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-02-17 12:24:08 +11:00
|
|
|
if (ob_eval->runtime.bb && !(ob_eval->runtime.bb->flag & BOUNDBOX_DIRTY)) {
|
2014-08-11 13:34:28 +10:00
|
|
|
float cent[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-02-17 12:24:08 +11:00
|
|
|
BKE_boundbox_calc_center_aabb(ob_eval->runtime.bb, cent);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
mul_m4_v3(ob_eval->obmat, cent);
|
2014-08-11 13:34:28 +10:00
|
|
|
add_v3_v3(select_center, cent);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2018-05-21 20:29:00 +02:00
|
|
|
add_v3_v3(select_center, ob_eval->obmat[3]);
|
2014-08-11 13:34:28 +10:00
|
|
|
}
|
|
|
|
|
tot++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (tot) {
|
|
|
|
|
mul_v3_fl(select_center, 1.0f / (float)tot);
|
|
|
|
|
copy_v3_v3(lastofs, select_center);
|
|
|
|
|
is_set = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-04-30 02:16:01 +10:00
|
|
|
else {
|
|
|
|
|
/* If there's no selection, lastofs is unmodified and last value since static */
|
2018-12-14 11:01:01 +11:00
|
|
|
is_set = calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, lastofs, NULL);
|
2014-04-30 02:16:01 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-30 02:16:01 +10:00
|
|
|
copy_v3_v3(r_dyn_ofs, lastofs);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-30 02:16:01 +10:00
|
|
|
return is_set;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-29 15:34:39 +11:00
|
|
|
enum eViewOpsFlag {
|
|
|
|
|
/** When enabled, rotate around the selection. */
|
|
|
|
|
VIEWOPS_FLAG_ORBIT_SELECT = (1 << 0),
|
|
|
|
|
/** When enabled, use the depth under the cursor for navigation. */
|
|
|
|
|
VIEWOPS_FLAG_DEPTH_NAVIGATE = (1 << 1),
|
|
|
|
|
/**
|
|
|
|
|
* When enabled run #ED_view3d_persp_ensure this may switch out of
|
|
|
|
|
* camera view when orbiting or switch from ortho to perspective when auto-persp is enabled.
|
|
|
|
|
* Some operations don't require this (view zoom/pan or ndof where subtle rotation is common
|
|
|
|
|
* so we don't want it to trigger auto-perspective). */
|
|
|
|
|
VIEWOPS_FLAG_PERSP_ENSURE = (1 << 2),
|
|
|
|
|
/** When set, ignore any options that depend on initial cursor location. */
|
|
|
|
|
VIEWOPS_FLAG_USE_MOUSE_INIT = (1 << 3),
|
2017-04-29 03:13:49 +10:00
|
|
|
};
|
|
|
|
|
|
2018-01-29 15:34:39 +11:00
|
|
|
static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth)
|
2017-04-29 03:13:49 +10:00
|
|
|
{
|
2018-01-29 15:34:39 +11:00
|
|
|
enum eViewOpsFlag flag = 0;
|
2017-04-29 03:13:49 +10:00
|
|
|
if (use_select) {
|
2018-01-29 15:34:39 +11:00
|
|
|
flag |= VIEWOPS_FLAG_ORBIT_SELECT;
|
2017-04-29 03:13:49 +10:00
|
|
|
}
|
2017-04-30 02:38:38 +10:00
|
|
|
if (use_depth) {
|
2018-01-29 15:34:39 +11:00
|
|
|
flag |= VIEWOPS_FLAG_DEPTH_NAVIGATE;
|
2017-04-29 03:13:49 +10:00
|
|
|
}
|
2017-04-30 02:38:38 +10:00
|
|
|
|
|
|
|
|
return flag;
|
2017-04-29 03:13:49 +10:00
|
|
|
}
|
|
|
|
|
|
2018-01-29 15:34:39 +11:00
|
|
|
static enum eViewOpsFlag viewops_flag_from_prefs(void)
|
2017-04-29 03:13:49 +10:00
|
|
|
{
|
|
|
|
|
return viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0,
|
2018-01-29 15:06:23 +11:00
|
|
|
(U.uiflag & USER_DEPTH_NAVIGATE) != 0);
|
2017-04-29 03:13:49 +10:00
|
|
|
}
|
|
|
|
|
|
2013-09-20 01:24:00 +00:00
|
|
|
/**
|
|
|
|
|
* Calculate the values for #ViewOpsData
|
|
|
|
|
*/
|
2018-01-29 15:34:39 +11:00
|
|
|
static void viewops_data_create(bContext *C,
|
2017-04-29 03:13:49 +10:00
|
|
|
wmOperator *op,
|
|
|
|
|
const wmEvent *event,
|
2018-01-29 15:34:39 +11:00
|
|
|
enum eViewOpsFlag viewops_flag)
|
2013-09-20 01:24:00 +00:00
|
|
|
{
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2013-09-20 01:24:00 +00:00
|
|
|
ViewOpsData *vod = op->customdata;
|
|
|
|
|
RegionView3D *rv3d = vod->rv3d;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 13:46:18 +11:00
|
|
|
/* Could do this more nicely. */
|
2018-01-29 16:17:47 +11:00
|
|
|
if ((viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) == 0) {
|
2018-01-29 15:34:39 +11:00
|
|
|
viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE;
|
2018-01-29 13:46:18 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-29 03:13:49 +10:00
|
|
|
/* we need the depth info before changing any viewport options */
|
2018-01-29 15:34:39 +11:00
|
|
|
if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) {
|
2017-04-29 03:13:49 +10:00
|
|
|
float fallback_depth_pt[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-29 03:13:49 +10:00
|
|
|
view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-29 03:13:49 +10:00
|
|
|
negate_v3_v3(fallback_depth_pt, rv3d->ofs);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-29 03:13:49 +10:00
|
|
|
vod->use_dyn_ofs = ED_view3d_autodist(
|
2020-03-06 16:56:42 +01:00
|
|
|
depsgraph, vod->region, vod->v3d, event->mval, vod->dyn_ofs, true, fallback_depth_pt);
|
2017-04-29 03:13:49 +10:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
vod->use_dyn_ofs = false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 15:34:39 +11:00
|
|
|
if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) {
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_persp_ensure(depsgraph, vod->v3d, vod->region)) {
|
2017-04-29 03:13:49 +10:00
|
|
|
/* If we're switching from camera view to the perspective one,
|
2019-08-17 00:54:22 +10:00
|
|
|
* need to tag viewport update, so camera view and borders are properly updated. */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(vod->region);
|
2017-04-29 03:13:49 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2011-05-15 03:07:07 +00:00
|
|
|
/* set the view from the camera, if view locking is enabled.
|
|
|
|
|
* we may want to make this optional but for now its needed always */
|
2018-11-30 12:16:19 +01:00
|
|
|
ED_view3d_camera_lock_init(depsgraph, vod->v3d, vod->rv3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-01-22 07:57:25 +11:00
|
|
|
vod->init.persp = rv3d->persp;
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->init.dist = rv3d->dist;
|
|
|
|
|
vod->init.camzoom = rv3d->camzoom;
|
|
|
|
|
copy_qt_qt(vod->init.quat, rv3d->viewquat);
|
|
|
|
|
vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
|
|
|
|
|
vod->init.event_xy[1] = vod->prev.event_xy[1] = event->y;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 16:17:47 +11:00
|
|
|
if (viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) {
|
|
|
|
|
vod->init.event_xy_offset[0] = 0;
|
|
|
|
|
vod->init.event_xy_offset[1] = 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Simulate the event starting in the middle of the region. */
|
2020-03-06 16:56:42 +01:00
|
|
|
vod->init.event_xy_offset[0] = BLI_rcti_cent_x(&vod->region->winrct) - event->x;
|
|
|
|
|
vod->init.event_xy_offset[1] = BLI_rcti_cent_y(&vod->region->winrct) - event->y;
|
2018-01-29 16:17:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->init.event_type = event->type;
|
|
|
|
|
copy_v3_v3(vod->init.ofs, rv3d->ofs);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
copy_qt_qt(vod->curr.viewquat, rv3d->viewquat);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 15:34:39 +11:00
|
|
|
if (viewops_flag & VIEWOPS_FLAG_ORBIT_SELECT) {
|
2017-04-30 02:38:38 +10:00
|
|
|
float ofs[3];
|
|
|
|
|
if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) {
|
|
|
|
|
vod->use_dyn_ofs = true;
|
|
|
|
|
negate_v3_v3(vod->dyn_ofs, ofs);
|
2018-01-29 15:34:39 +11:00
|
|
|
viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE;
|
2009-12-09 00:45:50 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-29 15:34:39 +11:00
|
|
|
if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) {
|
2017-04-29 03:13:49 +10:00
|
|
|
if (vod->use_dyn_ofs) {
|
2011-05-18 17:52:26 +00:00
|
|
|
if (rv3d->is_persp) {
|
2009-12-09 00:45:50 +00:00
|
|
|
float my_origin[3]; /* original G.vd->ofs */
|
|
|
|
|
float my_pivot[3]; /* view */
|
|
|
|
|
float dvec[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-07-08 20:36:00 +00:00
|
|
|
/* locals for dist correction */
|
2009-12-09 00:45:50 +00:00
|
|
|
float mat[3][3];
|
|
|
|
|
float upvec[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
negate_v3_v3(my_origin, rv3d->ofs); /* ofs is flipped */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-07-07 12:44:47 +10:00
|
|
|
/* Set the dist value to be the distance from this 3d point this means you'll
|
|
|
|
|
* always be able to zoom into it and panning wont go bad when dist was zero. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-12-09 00:45:50 +00:00
|
|
|
/* remove dist value */
|
|
|
|
|
upvec[0] = upvec[1] = 0;
|
|
|
|
|
upvec[2] = rv3d->dist;
|
|
|
|
|
copy_m3_m4(mat, rv3d->viewinv);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-12-09 00:45:50 +00:00
|
|
|
mul_m3_v3(mat, upvec);
|
|
|
|
|
sub_v3_v3v3(my_pivot, rv3d->ofs, upvec);
|
2012-03-25 23:54:33 +00:00
|
|
|
negate_v3(my_pivot); /* ofs is flipped */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-15 23:24:20 +11:00
|
|
|
/* find a new ofs value that is along the view axis
|
|
|
|
|
* (rather than the mouse location) */
|
2009-12-09 00:45:50 +00:00
|
|
|
closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin);
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->init.dist = rv3d->dist = len_v3v3(my_pivot, dvec);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-02-25 20:26:38 +00:00
|
|
|
negate_v3_v3(rv3d->ofs, dvec);
|
2009-12-09 00:45:50 +00:00
|
|
|
}
|
2013-09-16 08:59:54 +00:00
|
|
|
else {
|
2020-04-03 12:51:03 +02:00
|
|
|
const float mval_region_mid[2] = {(float)vod->region->winx / 2.0f,
|
|
|
|
|
(float)vod->region->winy / 2.0f};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-03 12:51:03 +02:00
|
|
|
ED_view3d_win_to_3d(vod->v3d, vod->region, vod->dyn_ofs, mval_region_mid, rv3d->ofs);
|
2013-09-16 08:59:54 +00:00
|
|
|
negate_v3(rv3d->ofs);
|
|
|
|
|
}
|
2009-12-09 00:45:50 +00:00
|
|
|
negate_v3(vod->dyn_ofs);
|
2018-01-29 14:36:40 +11:00
|
|
|
copy_v3_v3(vod->init.ofs, rv3d->ofs);
|
2009-12-09 00:45:50 +00:00
|
|
|
}
|
2009-10-15 15:58:12 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 16:17:47 +11:00
|
|
|
/* For dolly */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_win_to_vector(vod->region, (const float[2]){UNPACK2(event->mval)}, vod->init.mousevec);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-05-20 13:50:41 +00:00
|
|
|
{
|
2018-01-29 16:17:47 +11:00
|
|
|
const int event_xy_offset[2] = {
|
|
|
|
|
event->x + vod->init.event_xy_offset[0],
|
|
|
|
|
event->y + vod->init.event_xy_offset[1],
|
|
|
|
|
};
|
|
|
|
|
/* For rotation with trackball rotation. */
|
2020-03-06 16:56:42 +01:00
|
|
|
calctrackballvec(&vod->region->winrct, event_xy_offset, vod->init.trackvec);
|
2011-05-20 13:50:41 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-09 11:40:42 +00:00
|
|
|
{
|
|
|
|
|
float tvec[3];
|
|
|
|
|
negate_v3_v3(tvec, rv3d->ofs);
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->init.zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL);
|
2013-03-09 11:40:42 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
vod->reverse = 1.0f;
|
2019-03-26 21:16:47 +11:00
|
|
|
if (rv3d->persmat[2][1] < 0.0f) {
|
2012-03-25 23:54:33 +00:00
|
|
|
vod->reverse = -1.0f;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 14:13:43 +00:00
|
|
|
rv3d->rflag |= RV3D_NAVIGATING;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void viewops_data_free(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2012-02-22 16:52:06 +00:00
|
|
|
if (op->customdata) {
|
2012-03-25 23:54:33 +00:00
|
|
|
ViewOpsData *vod = op->customdata;
|
2020-03-06 16:56:42 +01:00
|
|
|
region = vod->region;
|
2011-01-03 01:26:54 +00:00
|
|
|
vod->rv3d->rflag &= ~RV3D_NAVIGATING;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (vod->timer) {
|
2011-01-03 01:26:54 +00:00
|
|
|
WM_event_remove_timer(CTX_wm_manager(C), vod->timer->win, vod->timer);
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-01-03 01:26:54 +00:00
|
|
|
MEM_freeN(vod);
|
2012-03-25 23:54:33 +00:00
|
|
|
op->customdata = NULL;
|
2011-01-03 01:26:54 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2020-03-06 16:56:42 +01:00
|
|
|
region = CTX_wm_region(C);
|
2011-01-03 01:26:54 +00:00
|
|
|
}
|
2009-12-16 23:05:59 +00:00
|
|
|
|
2019-08-15 11:24:19 +02:00
|
|
|
/* Need to redraw because drawing code uses RV3D_NAVIGATING to draw
|
|
|
|
|
* faster while navigation operator runs. */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(region);
|
2008-12-26 10:31:44 +00:00
|
|
|
}
|
2013-09-20 01:24:00 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
2008-12-19 17:14:02 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
2018-01-28 14:44:42 +11:00
|
|
|
/** \name View Rotate Operator
|
2018-01-23 19:48:49 +11:00
|
|
|
* \{ */
|
2008-12-19 17:14:02 +00:00
|
|
|
|
2009-09-25 10:24:42 +00:00
|
|
|
enum {
|
2012-03-25 23:54:33 +00:00
|
|
|
VIEW_PASS = 0,
|
2009-09-25 10:24:42 +00:00
|
|
|
VIEW_APPLY,
|
2019-02-03 14:01:45 +11:00
|
|
|
VIEW_CONFIRM,
|
2009-09-25 10:24:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
|
2018-01-23 19:48:49 +11:00
|
|
|
enum {
|
|
|
|
|
VIEW_MODAL_CONFIRM = 1, /* used for all view operations */
|
|
|
|
|
VIEWROT_MODAL_AXIS_SNAP_ENABLE = 2,
|
|
|
|
|
VIEWROT_MODAL_AXIS_SNAP_DISABLE = 3,
|
|
|
|
|
VIEWROT_MODAL_SWITCH_ZOOM = 4,
|
|
|
|
|
VIEWROT_MODAL_SWITCH_MOVE = 5,
|
|
|
|
|
VIEWROT_MODAL_SWITCH_ROTATE = 6,
|
|
|
|
|
};
|
2009-09-25 10:24:42 +00:00
|
|
|
|
|
|
|
|
/* called in transform_ops.c, on each regeneration of keymaps */
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
void viewrotate_modal_keymap(wmKeyConfig *keyconf)
|
2009-09-25 10:24:42 +00:00
|
|
|
{
|
2017-10-18 15:07:26 +11:00
|
|
|
static const EnumPropertyItem modal_items[] = {
|
2012-03-25 23:54:33 +00:00
|
|
|
{VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2018-07-10 07:41:49 +02:00
|
|
|
{VIEWROT_MODAL_AXIS_SNAP_ENABLE, "AXIS_SNAP_ENABLE", 0, "Axis Snap", ""},
|
|
|
|
|
{VIEWROT_MODAL_AXIS_SNAP_DISABLE, "AXIS_SNAP_DISABLE", 0, "Axis Snap (Off)", ""},
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
{VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"},
|
|
|
|
|
{VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2019-02-03 14:01:45 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2012-03-25 23:54:33 +00:00
|
|
|
};
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Rotate Modal");
|
2009-09-25 10:24:42 +00:00
|
|
|
|
|
|
|
|
/* this function is called for each spacetype, only needs to add map once */
|
2019-03-26 21:16:47 +11:00
|
|
|
if (keymap && keymap->modal_items) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
keymap = WM_modalkeymap_ensure(keyconf, "View3D Rotate Modal", modal_items);
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2012-03-03 16:31:46 +00:00
|
|
|
/* disabled mode switching for now, can re-implement better, later on */
|
|
|
|
|
#if 0
|
2010-01-06 12:22:59 +00:00
|
|
|
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
|
|
|
|
|
WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
|
|
|
|
|
WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
|
2012-03-03 16:31:46 +00:00
|
|
|
#endif
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2009-09-25 10:24:42 +00:00
|
|
|
/* assign map to operators */
|
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate");
|
|
|
|
|
}
|
2008-12-19 17:14:02 +00:00
|
|
|
|
2015-12-23 05:04:52 +11:00
|
|
|
static void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4])
|
2014-03-03 14:58:07 +11:00
|
|
|
{
|
|
|
|
|
if (vod->use_dyn_ofs) {
|
2014-04-30 02:16:01 +10:00
|
|
|
RegionView3D *rv3d = vod->rv3d;
|
2018-01-29 14:36:40 +11:00
|
|
|
view3d_orbit_apply_dyn_ofs(
|
|
|
|
|
rv3d->ofs, vod->init.ofs, vod->init.quat, viewquat_new, vod->dyn_ofs);
|
2014-03-03 14:58:07 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
static void viewrotate_apply_snap(ViewOpsData *vod)
|
|
|
|
|
{
|
|
|
|
|
const float axis_limit = DEG2RADF(45 / 3);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
RegionView3D *rv3d = vod->rv3d;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
float viewquat_inv[4];
|
|
|
|
|
float zaxis[3] = {0, 0, 1};
|
|
|
|
|
float zaxis_best[3];
|
|
|
|
|
int x, y, z;
|
|
|
|
|
bool found = false;
|
2020-01-22 07:57:25 +11:00
|
|
|
bool is_axis_aligned = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
mul_qt_v3(viewquat_inv, zaxis);
|
|
|
|
|
normalize_v3(zaxis);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
for (x = -1; x < 2; x++) {
|
|
|
|
|
for (y = -1; y < 2; y++) {
|
|
|
|
|
for (z = -1; z < 2; z++) {
|
|
|
|
|
if (x || y || z) {
|
|
|
|
|
float zaxis_test[3] = {x, y, z};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
normalize_v3(zaxis_test);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
if (angle_normalized_v3v3(zaxis_test, zaxis) < axis_limit) {
|
|
|
|
|
copy_v3_v3(zaxis_best, zaxis_test);
|
|
|
|
|
found = true;
|
2020-01-22 07:57:25 +11:00
|
|
|
|
|
|
|
|
if (abs(x) + abs(y) + abs(z) == 1) {
|
|
|
|
|
is_axis_aligned = true;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-03-20 15:19:02 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
if (found) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
/* find the best roll */
|
|
|
|
|
float quat_roll[4], quat_final[4], quat_best[4], quat_snap[4];
|
|
|
|
|
float viewquat_align[4]; /* viewquat aligned to zaxis_best */
|
|
|
|
|
float viewquat_align_inv[4]; /* viewquat aligned to zaxis_best */
|
|
|
|
|
float best_angle = axis_limit;
|
|
|
|
|
int j;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
/* viewquat_align is the original viewquat aligned to the snapped axis
|
|
|
|
|
* for testing roll */
|
|
|
|
|
rotation_between_vecs_to_quat(viewquat_align, zaxis_best, zaxis);
|
|
|
|
|
normalize_qt(viewquat_align);
|
2018-01-29 14:36:40 +11:00
|
|
|
mul_qt_qtqt(viewquat_align, vod->curr.viewquat, viewquat_align);
|
2014-03-20 15:19:02 +11:00
|
|
|
normalize_qt(viewquat_align);
|
2015-10-24 03:51:00 +11:00
|
|
|
invert_qt_qt_normalized(viewquat_align_inv, viewquat_align);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
vec_to_quat(quat_snap, zaxis_best, OB_NEGZ, OB_POSY);
|
|
|
|
|
normalize_qt(quat_snap);
|
2015-10-24 03:51:00 +11:00
|
|
|
invert_qt_normalized(quat_snap);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
/* check if we can find the roll */
|
|
|
|
|
found = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
/* find best roll */
|
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
|
|
|
float angle;
|
|
|
|
|
float xaxis1[3] = {1, 0, 0};
|
|
|
|
|
float xaxis2[3] = {1, 0, 0};
|
|
|
|
|
float quat_final_inv[4];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
axis_angle_to_quat(quat_roll, zaxis_best, (float)j * DEG2RADF(45.0f));
|
|
|
|
|
normalize_qt(quat_roll);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
mul_qt_qtqt(quat_final, quat_snap, quat_roll);
|
|
|
|
|
normalize_qt(quat_final);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
/* compare 2 vector angles to find the least roll */
|
2015-10-24 03:51:00 +11:00
|
|
|
invert_qt_qt_normalized(quat_final_inv, quat_final);
|
2014-03-20 15:19:02 +11:00
|
|
|
mul_qt_v3(viewquat_align_inv, xaxis1);
|
|
|
|
|
mul_qt_v3(quat_final_inv, xaxis2);
|
|
|
|
|
angle = angle_v3v3(xaxis1, xaxis2);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
if (angle <= best_angle) {
|
|
|
|
|
found = true;
|
|
|
|
|
best_angle = angle;
|
|
|
|
|
copy_qt_qt(quat_best, quat_final);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
if (found) {
|
|
|
|
|
/* lock 'quat_best' to an axis view if we can */
|
2020-02-09 11:50:25 +11:00
|
|
|
ED_view3d_quat_to_axis_view(quat_best, 0.01f, &rv3d->view, &rv3d->view_axis_roll);
|
2014-03-20 15:19:02 +11:00
|
|
|
if (rv3d->view != RV3D_VIEW_USER) {
|
2020-02-09 11:50:25 +11:00
|
|
|
ED_view3d_quat_from_axis_view(rv3d->view, rv3d->view_axis_roll, quat_best);
|
2014-03-20 15:19:02 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
copy_qt_qt(quat_best, viewquat_align);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
copy_qt_qt(rv3d->viewquat, quat_best);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-20 15:19:02 +11:00
|
|
|
viewrotate_apply_dyn_ofs(vod, rv3d->viewquat);
|
2020-01-22 07:57:25 +11:00
|
|
|
|
|
|
|
|
if (U.uiflag & USER_AUTOPERSP) {
|
|
|
|
|
if (is_axis_aligned) {
|
|
|
|
|
if (rv3d->persp == RV3D_PERSP) {
|
|
|
|
|
rv3d->persp = RV3D_ORTHO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (U.uiflag & USER_AUTOPERSP) {
|
|
|
|
|
rv3d->persp = vod->init.persp;
|
2014-03-20 15:19:02 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2])
|
2008-12-19 17:14:02 +00:00
|
|
|
{
|
2012-03-25 23:54:33 +00:00
|
|
|
RegionView3D *rv3d = vod->rv3d;
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2013-05-26 12:02:29 +00:00
|
|
|
rv3d->view = RV3D_VIEW_USER; /* need to reset every time because of view snapping */
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
if (U.flag & USER_TRACKBALL) {
|
2015-10-13 16:26:00 +11:00
|
|
|
float axis[3], q1[4], dvec[3], newvec[3];
|
|
|
|
|
float angle;
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2018-01-29 16:17:47 +11:00
|
|
|
{
|
|
|
|
|
const int event_xy_offset[2] = {
|
|
|
|
|
event_xy[0] + vod->init.event_xy_offset[0],
|
|
|
|
|
event_xy[1] + vod->init.event_xy_offset[1],
|
|
|
|
|
};
|
2020-03-06 16:56:42 +01:00
|
|
|
calctrackballvec(&vod->region->winrct, event_xy_offset, newvec);
|
2018-01-29 16:17:47 +11:00
|
|
|
}
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
sub_v3_v3v3(dvec, newvec, vod->init.trackvec);
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2015-10-17 16:06:45 +11:00
|
|
|
angle = (len_v3(dvec) / (2.0f * TRACKBALLSIZE)) * (float)M_PI;
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2019-08-04 01:22:38 +10:00
|
|
|
/* Before applying the sensitivity this is rotating 1:1,
|
|
|
|
|
* where the cursor would match the surface of a sphere in the view. */
|
|
|
|
|
angle *= U.view_rotate_sensitivity_trackball;
|
|
|
|
|
|
2012-03-03 16:31:46 +00:00
|
|
|
/* Allow for rotation beyond the interval [-pi, pi] */
|
2015-10-13 16:31:43 +11:00
|
|
|
angle = angle_wrap_rad(angle);
|
2015-10-13 16:26:00 +11:00
|
|
|
|
|
|
|
|
/* This relation is used instead of the actual angle between vectors
|
|
|
|
|
* so that the angle of rotation is linearly proportional to
|
|
|
|
|
* the distance that the mouse is dragged. */
|
|
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
cross_v3_v3v3(axis, vod->init.trackvec, newvec);
|
2015-10-13 16:26:00 +11:00
|
|
|
axis_angle_to_quat(q1, axis, angle);
|
|
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
mul_qt_qtqt(vod->curr.viewquat, q1, vod->init.quat);
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat);
|
2008-12-26 10:31:44 +00:00
|
|
|
}
|
2008-12-19 17:14:02 +00:00
|
|
|
else {
|
|
|
|
|
/* New turntable view code by John Aughey */
|
2014-03-03 14:58:07 +11:00
|
|
|
float quat_local_x[4], quat_global_z[4];
|
2008-12-19 17:14:02 +00:00
|
|
|
float m[3][3];
|
|
|
|
|
float m_inv[3][3];
|
2012-04-13 13:55:55 +00:00
|
|
|
const float zvec_global[3] = {0.0f, 0.0f, 1.0f};
|
2012-04-13 15:15:13 +00:00
|
|
|
float xaxis[3];
|
|
|
|
|
|
2019-08-04 01:22:38 +10:00
|
|
|
/* Radians per-pixel. */
|
2020-08-18 11:23:34 +10:00
|
|
|
const float sensitivity = U.view_rotate_sensitivity_turntable / U.dpi_fac;
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* Get the 3x3 matrix and its inverse from the quaternion */
|
2018-01-29 14:36:40 +11:00
|
|
|
quat_to_mat3(m, vod->curr.viewquat);
|
2012-03-25 23:54:33 +00:00
|
|
|
invert_m3_m3(m_inv, m);
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2021-01-04 11:29:11 +11:00
|
|
|
/* Avoid Gimbal Lock
|
2020-01-22 02:51:01 +11:00
|
|
|
*
|
|
|
|
|
* Even though turn-table mode is in use, this can occur when the user exits the camera view
|
|
|
|
|
* or when aligning the view to a rotated object.
|
|
|
|
|
*
|
2021-01-04 11:29:11 +11:00
|
|
|
* We have gimbal lock when the user's view is rotated +/- 90 degrees along the view axis.
|
2020-01-22 02:51:01 +11:00
|
|
|
* In this case the vertical rotation is the same as the sideways turntable motion.
|
2021-01-04 11:29:11 +11:00
|
|
|
* Making it impossible to get out of the gimbal locked state without resetting the view.
|
2020-01-22 02:51:01 +11:00
|
|
|
*
|
|
|
|
|
* The logic below lets the user exit out of this state without any abrupt 'fix'
|
|
|
|
|
* which would be disorienting.
|
|
|
|
|
*
|
|
|
|
|
* This works by blending two horizons:
|
|
|
|
|
* - Rotated-horizon: `cross_v3_v3v3(xaxis, zvec_global, m_inv[2])`
|
|
|
|
|
* When only this is used, this turntable rotation works - but it's side-ways
|
|
|
|
|
* (as if the entire turn-table has been placed on its side)
|
2021-01-04 11:29:11 +11:00
|
|
|
* While there is no gimbal lock, it's also awkward to use.
|
2020-01-22 02:51:01 +11:00
|
|
|
* - Un-rotated-horizon: `m_inv[0]`
|
|
|
|
|
* When only this is used, the turntable rotation can have gimbal lock.
|
|
|
|
|
*
|
|
|
|
|
* The solution used here is to blend between these two values,
|
|
|
|
|
* so the severity of the gimbal lock is used to blend the rotated horizon.
|
|
|
|
|
* Blending isn't essential, it just makes the transition smoother.
|
|
|
|
|
*
|
|
|
|
|
* This allows sideways turn-table rotation on a Z axis that isn't world-space Z,
|
2021-01-04 11:29:11 +11:00
|
|
|
* While up-down turntable rotation eventually corrects gimbal lock. */
|
2012-04-13 15:15:13 +00:00
|
|
|
#if 1
|
|
|
|
|
if (len_squared_v3v3(zvec_global, m_inv[2]) > 0.001f) {
|
|
|
|
|
float fac;
|
|
|
|
|
cross_v3_v3v3(xaxis, zvec_global, m_inv[2]);
|
|
|
|
|
if (dot_v3v3(xaxis, m_inv[0]) < 0) {
|
|
|
|
|
negate_v3(xaxis);
|
|
|
|
|
}
|
2012-05-03 21:35:04 +00:00
|
|
|
fac = angle_normalized_v3v3(zvec_global, m_inv[2]) / (float)M_PI;
|
2012-04-13 15:15:13 +00:00
|
|
|
fac = fabsf(fac - 0.5f) * 2;
|
|
|
|
|
fac = fac * fac;
|
|
|
|
|
interp_v3_v3v3(xaxis, xaxis, m_inv[0], fac);
|
|
|
|
|
}
|
2012-04-28 06:31:57 +00:00
|
|
|
else {
|
2012-04-13 15:15:13 +00:00
|
|
|
copy_v3_v3(xaxis, m_inv[0]);
|
|
|
|
|
}
|
2012-04-28 06:31:57 +00:00
|
|
|
#else
|
|
|
|
|
copy_v3_v3(xaxis, m_inv[0]);
|
|
|
|
|
#endif
|
2012-04-13 15:15:13 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* Determine the direction of the x vector (for rotating up and down) */
|
2010-01-11 11:14:36 +00:00
|
|
|
/* This can likely be computed directly from the quaternion. */
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* Perform the up/down rotation */
|
2018-01-29 14:36:40 +11:00
|
|
|
axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(event_xy[1] - vod->prev.event_xy[1]));
|
|
|
|
|
mul_qt_qtqt(quat_local_x, vod->curr.viewquat, quat_local_x);
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* Perform the orbital rotation */
|
2018-01-29 14:36:40 +11:00
|
|
|
axis_angle_to_quat_single(
|
|
|
|
|
quat_global_z, 'Z', sensitivity * vod->reverse * (event_xy[0] - vod->prev.event_xy[0]));
|
|
|
|
|
mul_qt_qtqt(vod->curr.viewquat, quat_local_x, quat_global_z);
|
2014-03-03 14:58:07 +11:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat);
|
2008-12-19 12:14:58 +00:00
|
|
|
}
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2014-03-03 14:58:07 +11:00
|
|
|
/* avoid precision loss over time */
|
2018-01-29 14:36:40 +11:00
|
|
|
normalize_qt(vod->curr.viewquat);
|
2014-03-03 14:58:07 +11:00
|
|
|
|
2018-09-27 15:35:22 +02:00
|
|
|
/* use a working copy so view rotation locking doesn't overwrite the locked
|
2014-03-03 14:58:07 +11:00
|
|
|
* rotation back into the view we calculate with */
|
2018-01-29 14:36:40 +11:00
|
|
|
copy_qt_qt(rv3d->viewquat, vod->curr.viewquat);
|
2014-03-03 14:58:07 +11:00
|
|
|
|
|
|
|
|
/* check for view snap,
|
|
|
|
|
* note: don't apply snap to vod->viewquat so the view wont jam up */
|
2012-02-22 16:52:06 +00:00
|
|
|
if (vod->axis_snap) {
|
2014-03-20 15:19:02 +11:00
|
|
|
viewrotate_apply_snap(vod);
|
2008-12-19 12:14:58 +00:00
|
|
|
}
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->prev.event_xy[0] = event_xy[0];
|
|
|
|
|
vod->prev.event_xy[1] = event_xy[1];
|
2008-12-19 17:14:02 +00:00
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, rv3d);
|
2011-05-14 17:50:33 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(vod->region);
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
2008-12-19 17:14:02 +00:00
|
|
|
{
|
2012-03-25 23:54:33 +00:00
|
|
|
ViewOpsData *vod = op->customdata;
|
|
|
|
|
short event_code = VIEW_PASS;
|
2014-11-24 00:27:50 +01:00
|
|
|
bool use_autokey = false;
|
|
|
|
|
int ret = OPERATOR_RUNNING_MODAL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* execute the events */
|
2012-03-25 23:54:33 +00:00
|
|
|
if (event->type == MOUSEMOVE) {
|
|
|
|
|
event_code = VIEW_APPLY;
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else if (event->type == EVT_MODAL_MAP) {
|
2009-09-25 10:24:42 +00:00
|
|
|
switch (event->val) {
|
|
|
|
|
case VIEW_MODAL_CONFIRM:
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2009-09-25 10:24:42 +00:00
|
|
|
break;
|
|
|
|
|
case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
|
2013-03-20 23:14:18 +00:00
|
|
|
vod->axis_snap = true;
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_APPLY;
|
2009-09-25 10:24:42 +00:00
|
|
|
break;
|
|
|
|
|
case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
|
2020-01-22 07:57:25 +11:00
|
|
|
vod->rv3d->persp = vod->init.persp;
|
2013-03-20 23:14:18 +00:00
|
|
|
vod->axis_snap = false;
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_APPLY;
|
2009-09-25 10:24:42 +00:00
|
|
|
break;
|
2010-01-06 12:22:59 +00:00
|
|
|
case VIEWROT_MODAL_SWITCH_ZOOM:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2010-01-06 12:22:59 +00:00
|
|
|
break;
|
|
|
|
|
case VIEWROT_MODAL_SWITCH_MOVE:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2010-01-06 12:22:59 +00:00
|
|
|
break;
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
2018-01-29 14:36:40 +11:00
|
|
|
else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
if (event_code == VIEW_APPLY) {
|
2018-01-29 14:36:40 +11:00
|
|
|
viewrotate_apply(vod, &event->x);
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
|
|
|
|
use_autokey = true;
|
|
|
|
|
}
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else if (event_code == VIEW_CONFIRM) {
|
2011-05-21 08:56:37 +00:00
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
2014-11-24 00:27:50 +01:00
|
|
|
use_autokey = true;
|
|
|
|
|
ret = OPERATOR_FINISHED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (use_autokey) {
|
|
|
|
|
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ret & OPERATOR_FINISHED) {
|
|
|
|
|
viewops_data_free(C, op);
|
2008-12-19 12:14:58 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
return ret;
|
2008-12-19 12:14:58 +00:00
|
|
|
}
|
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2008-12-19 12:14:58 +00:00
|
|
|
{
|
2008-12-19 17:14:02 +00:00
|
|
|
ViewOpsData *vod;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2019-05-31 19:53:24 +10:00
|
|
|
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
2018-01-29 13:46:18 +11:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* makes op->customdata */
|
2013-09-20 01:24:00 +00:00
|
|
|
viewops_data_alloc(C, op);
|
2012-03-25 23:54:33 +00:00
|
|
|
vod = op->customdata;
|
2010-11-16 09:35:58 +00:00
|
|
|
|
2014-02-04 19:45:22 +11:00
|
|
|
/* poll should check but in some cases fails, see poll func for details */
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_LOCK_ROTATION) {
|
2010-11-16 09:35:58 +00:00
|
|
|
viewops_data_free(C, op);
|
2011-02-05 19:07:54 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
2010-11-16 09:35:58 +00:00
|
|
|
}
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
2016-05-05 02:01:18 +10:00
|
|
|
|
2018-01-29 15:34:39 +11:00
|
|
|
viewops_data_create(C,
|
|
|
|
|
op,
|
|
|
|
|
event,
|
|
|
|
|
viewops_flag_from_prefs() | VIEWOPS_FLAG_PERSP_ENSURE |
|
2019-05-31 19:53:24 +10:00
|
|
|
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
|
2015-12-23 04:09:15 +11:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) {
|
2013-02-08 12:12:57 +00:00
|
|
|
/* Rotate direction we keep always same */
|
2018-01-29 14:36:40 +11:00
|
|
|
int event_xy[2];
|
2014-11-24 00:27:50 +01:00
|
|
|
|
|
|
|
|
if (event->type == MOUSEPAN) {
|
2020-11-09 12:26:53 +01:00
|
|
|
if (event->is_direction_inverted) {
|
2018-01-29 14:36:40 +11:00
|
|
|
event_xy[0] = 2 * event->x - event->prevx;
|
|
|
|
|
event_xy[1] = 2 * event->y - event->prevy;
|
2014-11-24 00:27:50 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2018-01-29 14:36:40 +11:00
|
|
|
event_xy[0] = event->prevx;
|
|
|
|
|
event_xy[1] = event->prevy;
|
2014-11-24 00:27:50 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
|
2018-01-29 14:36:40 +11:00
|
|
|
event_xy[0] = event->prevx;
|
|
|
|
|
event_xy[1] = event->y;
|
2014-11-24 00:27:50 +01:00
|
|
|
}
|
|
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
viewrotate_apply(vod, event_xy);
|
2013-09-20 01:24:00 +00:00
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
2014-11-24 00:27:50 +01:00
|
|
|
|
2010-01-11 11:14:36 +00:00
|
|
|
viewops_data_free(C, op);
|
2014-11-24 00:27:50 +01:00
|
|
|
|
2010-01-11 11:14:36 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2020-07-03 17:18:56 +02:00
|
|
|
/* add temp handler */
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-30 23:08:53 +00:00
|
|
|
static void viewrotate_cancel(bContext *C, wmOperator *op)
|
2011-06-06 11:04:54 +00:00
|
|
|
{
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-25 10:24:42 +00:00
|
|
|
void VIEW3D_OT_rotate(wmOperatorType *ot)
|
2008-12-19 17:14:02 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2013-01-27 07:23:58 +00:00
|
|
|
ot->name = "Rotate View";
|
2010-02-10 21:15:44 +00:00
|
|
|
ot->description = "Rotate the view";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_rotate";
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = viewrotate_invoke;
|
|
|
|
|
ot->modal = viewrotate_modal;
|
|
|
|
|
ot->poll = ED_operator_region_view3d_active;
|
|
|
|
|
ot->cancel = viewrotate_cancel;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2019-05-29 00:48:48 +10:00
|
|
|
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
|
2018-01-29 13:46:18 +11:00
|
|
|
|
|
|
|
|
view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT);
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
2016-08-18 00:21:55 -04:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
2014-02-24 12:36:57 +11:00
|
|
|
/** \name NDOF Utility Functions
|
|
|
|
|
* \{ */
|
2014-02-14 17:42:21 +11:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
#ifdef WITH_INPUT_NDOF
|
2019-11-29 18:46:46 +11:00
|
|
|
static bool ndof_has_translate(const wmNDOFMotionData *ndof,
|
|
|
|
|
const View3D *v3d,
|
|
|
|
|
const RegionView3D *rv3d)
|
|
|
|
|
{
|
|
|
|
|
return !is_zero_v3(ndof->tvec) && (!ED_view3d_offset_lock_check(v3d, rv3d));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool ndof_has_rotate(const wmNDOFMotionData *ndof, const RegionView3D *rv3d)
|
|
|
|
|
{
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
return !is_zero_v3(ndof->rvec) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0);
|
2019-11-29 18:46:46 +11:00
|
|
|
}
|
2014-02-14 17:42:21 +11:00
|
|
|
|
2014-03-03 01:08:55 +11:00
|
|
|
/**
|
|
|
|
|
* \param depth_pt: A point to calculate the depth (in perspective mode)
|
|
|
|
|
*/
|
|
|
|
|
static float view3d_ndof_pan_speed_calc_ex(RegionView3D *rv3d, const float depth_pt[3])
|
2014-02-22 16:19:02 +11:00
|
|
|
{
|
|
|
|
|
float speed = rv3d->pixsize * NDOF_PIXELS_PER_SECOND;
|
|
|
|
|
|
|
|
|
|
if (rv3d->is_persp) {
|
2014-03-03 01:08:55 +11:00
|
|
|
speed *= ED_view3d_calc_zfac(rv3d, depth_pt, NULL);
|
2014-02-22 16:19:02 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return speed;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-03 01:08:55 +11:00
|
|
|
static float view3d_ndof_pan_speed_calc_from_dist(RegionView3D *rv3d, const float dist)
|
|
|
|
|
{
|
|
|
|
|
float viewinv[4];
|
|
|
|
|
float tvec[3];
|
|
|
|
|
|
|
|
|
|
BLI_assert(dist >= 0.0f);
|
|
|
|
|
|
|
|
|
|
copy_v3_fl3(tvec, 0.0f, 0.0f, dist);
|
|
|
|
|
/* rv3d->viewinv isn't always valid */
|
|
|
|
|
# if 0
|
|
|
|
|
mul_mat3_m4_v3(rv3d->viewinv, tvec);
|
|
|
|
|
# else
|
2015-10-24 03:51:00 +11:00
|
|
|
invert_qt_qt_normalized(viewinv, rv3d->viewquat);
|
2014-03-03 01:08:55 +11:00
|
|
|
mul_qt_v3(viewinv, tvec);
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
return view3d_ndof_pan_speed_calc_ex(rv3d, tvec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static float view3d_ndof_pan_speed_calc(RegionView3D *rv3d)
|
|
|
|
|
{
|
|
|
|
|
float tvec[3];
|
|
|
|
|
negate_v3_v3(tvec, rv3d->ofs);
|
|
|
|
|
|
|
|
|
|
return view3d_ndof_pan_speed_calc_ex(rv3d, tvec);
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-14 18:38:23 +11:00
|
|
|
/**
|
|
|
|
|
* Zoom and pan in the same function since sometimes zoom is interpreted as dolly (pan forward).
|
|
|
|
|
*
|
2019-04-22 00:18:34 +10:00
|
|
|
* \param has_zoom: zoom, otherwise dolly,
|
|
|
|
|
* often `!rv3d->is_persp` since it doesn't make sense to dolly in ortho.
|
2014-02-14 18:38:23 +11:00
|
|
|
*/
|
2018-01-23 19:48:49 +11:00
|
|
|
static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof,
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area,
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region,
|
2018-01-23 19:48:49 +11:00
|
|
|
const bool has_translate,
|
|
|
|
|
const bool has_zoom)
|
2014-02-12 20:09:36 +11:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2014-02-14 18:38:23 +11:00
|
|
|
float view_inv[4];
|
2014-02-12 20:09:36 +11:00
|
|
|
float pan_vec[3];
|
|
|
|
|
|
2014-02-14 18:38:23 +11:00
|
|
|
if (has_translate == false && has_zoom == false) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-02-14 17:42:21 +11:00
|
|
|
|
2014-02-18 23:51:11 +11:00
|
|
|
WM_event_ndof_pan_get(ndof, pan_vec, false);
|
2014-02-12 20:09:36 +11:00
|
|
|
|
2014-02-14 18:38:23 +11:00
|
|
|
if (has_zoom) {
|
|
|
|
|
/* zoom with Z */
|
2014-02-12 20:09:36 +11:00
|
|
|
|
2014-02-14 18:38:23 +11:00
|
|
|
/* Zoom!
|
2019-04-22 00:18:34 +10:00
|
|
|
* velocity should be proportional to the linear velocity attained by rotational motion
|
|
|
|
|
* of same strength [got that?] proportional to `arclength = radius * angle`.
|
2014-02-14 18:38:23 +11:00
|
|
|
*/
|
2014-02-12 20:09:36 +11:00
|
|
|
|
2014-02-14 18:38:23 +11:00
|
|
|
pan_vec[2] = 0.0f;
|
2014-02-12 20:09:36 +11:00
|
|
|
|
2014-02-14 18:38:23 +11:00
|
|
|
/* "zoom in" or "translate"? depends on zoom mode in user settings? */
|
2014-02-18 23:51:11 +11:00
|
|
|
if (ndof->tvec[2]) {
|
2014-02-22 16:19:02 +11:00
|
|
|
float zoom_distance = rv3d->dist * ndof->dt * ndof->tvec[2];
|
2014-02-14 18:38:23 +11:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (U.ndof_flag & NDOF_ZOOM_INVERT) {
|
2014-02-14 18:38:23 +11:00
|
|
|
zoom_distance = -zoom_distance;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2014-02-14 18:38:23 +11:00
|
|
|
|
|
|
|
|
rv3d->dist += zoom_distance;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* dolly with Z */
|
|
|
|
|
|
|
|
|
|
/* all callers must check */
|
|
|
|
|
if (has_translate) {
|
2020-04-03 13:25:03 +02:00
|
|
|
BLI_assert(ED_view3d_offset_lock_check((View3D *)area->spacedata.first, rv3d) == false);
|
2014-02-14 18:38:23 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (has_translate) {
|
2014-02-22 16:19:02 +11:00
|
|
|
const float speed = view3d_ndof_pan_speed_calc(rv3d);
|
2014-02-14 18:38:23 +11:00
|
|
|
|
2014-02-22 16:19:02 +11:00
|
|
|
mul_v3_fl(pan_vec, speed * ndof->dt);
|
2014-02-14 18:38:23 +11:00
|
|
|
|
|
|
|
|
/* transform motion from view to world coordinates */
|
2015-10-24 03:51:00 +11:00
|
|
|
invert_qt_qt_normalized(view_inv, rv3d->viewquat);
|
2014-02-14 18:38:23 +11:00
|
|
|
mul_qt_v3(view_inv, pan_vec);
|
|
|
|
|
|
|
|
|
|
/* move center of view opposite of hand motion (this is camera mode, not object mode) */
|
|
|
|
|
sub_v3_v3(rv3d->ofs, pan_vec);
|
|
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_boxview_sync(area, region);
|
2014-02-14 18:38:23 +11:00
|
|
|
}
|
2014-02-12 20:09:36 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof,
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area,
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region,
|
2018-05-27 10:34:01 +02:00
|
|
|
ViewOpsData *vod,
|
|
|
|
|
const bool apply_dyn_ofs)
|
2013-03-03 04:54:33 +00:00
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
View3D *v3d = area->spacedata.first;
|
2020-03-06 16:56:42 +01:00
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2014-02-20 10:00:16 +11:00
|
|
|
|
2014-02-12 20:09:36 +11:00
|
|
|
float view_inv[4];
|
|
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
BLI_assert((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0);
|
2014-02-14 17:42:21 +11:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_persp_ensure(vod->depsgraph, v3d, region);
|
2014-02-14 17:42:21 +11:00
|
|
|
|
|
|
|
|
rv3d->view = RV3D_VIEW_USER;
|
|
|
|
|
|
2015-10-24 03:51:00 +11:00
|
|
|
invert_qt_qt_normalized(view_inv, rv3d->viewquat);
|
2014-02-12 20:09:36 +11:00
|
|
|
|
2013-03-03 04:54:33 +00:00
|
|
|
if (U.ndof_flag & NDOF_TURNTABLE) {
|
2014-02-18 23:51:11 +11:00
|
|
|
float rot[3];
|
2013-03-03 04:54:33 +00:00
|
|
|
|
|
|
|
|
/* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
|
2014-02-18 23:51:11 +11:00
|
|
|
float angle, quat[4];
|
2013-03-03 04:54:33 +00:00
|
|
|
float xvec[3] = {1, 0, 0};
|
|
|
|
|
|
2014-02-18 23:51:11 +11:00
|
|
|
/* only use XY, ignore Z */
|
|
|
|
|
WM_event_ndof_rotate_get(ndof, rot);
|
|
|
|
|
|
2013-03-03 04:54:33 +00:00
|
|
|
/* Determine the direction of the x vector (for rotating up and down) */
|
|
|
|
|
mul_qt_v3(view_inv, xvec);
|
|
|
|
|
|
|
|
|
|
/* Perform the up/down rotation */
|
2014-02-20 10:00:16 +11:00
|
|
|
angle = ndof->dt * rot[0];
|
2015-10-23 03:16:21 +11:00
|
|
|
axis_angle_to_quat(quat, xvec, angle);
|
2014-02-18 23:51:11 +11:00
|
|
|
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat);
|
2013-03-03 04:54:33 +00:00
|
|
|
|
|
|
|
|
/* Perform the orbital rotation */
|
2014-02-20 10:00:16 +11:00
|
|
|
angle = ndof->dt * rot[1];
|
2013-03-03 04:54:33 +00:00
|
|
|
|
|
|
|
|
/* update the onscreen doo-dad */
|
|
|
|
|
rv3d->rot_angle = angle;
|
|
|
|
|
rv3d->rot_axis[0] = 0;
|
|
|
|
|
rv3d->rot_axis[1] = 0;
|
|
|
|
|
rv3d->rot_axis[2] = 1;
|
|
|
|
|
|
2015-10-23 03:16:21 +11:00
|
|
|
axis_angle_to_quat_single(quat, 'Z', angle);
|
2014-02-18 23:51:11 +11:00
|
|
|
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat);
|
2013-03-03 04:54:33 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2014-02-18 23:51:11 +11:00
|
|
|
float quat[4];
|
2013-03-03 04:54:33 +00:00
|
|
|
float axis[3];
|
2014-02-18 23:51:11 +11:00
|
|
|
float angle = WM_event_ndof_to_axis_angle(ndof, axis);
|
2013-03-03 04:54:33 +00:00
|
|
|
|
|
|
|
|
/* transform rotation axis from view to world coordinates */
|
|
|
|
|
mul_qt_v3(view_inv, axis);
|
|
|
|
|
|
|
|
|
|
/* update the onscreen doo-dad */
|
|
|
|
|
rv3d->rot_angle = angle;
|
|
|
|
|
copy_v3_v3(rv3d->rot_axis, axis);
|
|
|
|
|
|
2014-02-18 23:51:11 +11:00
|
|
|
axis_angle_to_quat(quat, axis, angle);
|
2013-03-03 04:54:33 +00:00
|
|
|
|
|
|
|
|
/* apply rotation */
|
2014-02-18 23:51:11 +11:00
|
|
|
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat);
|
2013-03-03 04:54:33 +00:00
|
|
|
}
|
|
|
|
|
|
2018-05-27 10:34:01 +02:00
|
|
|
if (apply_dyn_ofs) {
|
2014-03-03 14:58:07 +11:00
|
|
|
viewrotate_apply_dyn_ofs(vod, rv3d->viewquat);
|
2013-03-03 04:54:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
/**
|
|
|
|
|
* Called from both fly mode and walk mode,
|
|
|
|
|
*/
|
|
|
|
|
void view3d_ndof_fly(const wmNDOFMotionData *ndof,
|
|
|
|
|
View3D *v3d,
|
|
|
|
|
RegionView3D *rv3d,
|
|
|
|
|
const bool use_precision,
|
|
|
|
|
const short protectflag,
|
|
|
|
|
bool *r_has_translate,
|
|
|
|
|
bool *r_has_rotate)
|
|
|
|
|
{
|
2019-11-29 18:46:46 +11:00
|
|
|
bool has_translate = ndof_has_translate(ndof, v3d, rv3d);
|
|
|
|
|
bool has_rotate = ndof_has_rotate(ndof, rv3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
float view_inv[4];
|
2015-10-24 03:51:00 +11:00
|
|
|
invert_qt_qt_normalized(view_inv, rv3d->viewquat);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
rv3d->rot_angle = 0.0f; /* disable onscreen rotation doo-dad */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
if (has_translate) {
|
2014-03-03 01:08:55 +11:00
|
|
|
/* ignore real 'dist' since fly has its own speed settings,
|
|
|
|
|
* also its overwritten at this point. */
|
|
|
|
|
float speed = view3d_ndof_pan_speed_calc_from_dist(rv3d, 1.0f);
|
2014-02-19 21:19:13 +11:00
|
|
|
float trans[3], trans_orig_y;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (use_precision) {
|
2014-02-19 21:19:13 +11:00
|
|
|
speed *= 0.2f;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
WM_event_ndof_pan_get(ndof, trans, false);
|
2014-02-22 16:19:02 +11:00
|
|
|
mul_v3_fl(trans, speed * ndof->dt);
|
2014-02-19 21:19:13 +11:00
|
|
|
trans_orig_y = trans[1];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:30:57 +11:00
|
|
|
if (U.ndof_flag & NDOF_FLY_HELICOPTER) {
|
|
|
|
|
trans[1] = 0.0f;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
/* transform motion from view to world coordinates */
|
|
|
|
|
mul_qt_v3(view_inv, trans);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
if (U.ndof_flag & NDOF_FLY_HELICOPTER) {
|
|
|
|
|
/* replace world z component with device y (yes it makes sense) */
|
|
|
|
|
trans[2] = trans_orig_y;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
if (rv3d->persp == RV3D_CAMOB) {
|
|
|
|
|
/* respect camera position locks */
|
2019-03-26 21:16:47 +11:00
|
|
|
if (protectflag & OB_LOCK_LOCX) {
|
|
|
|
|
trans[0] = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_LOCY) {
|
|
|
|
|
trans[1] = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_LOCZ) {
|
|
|
|
|
trans[2] = 0.0f;
|
2014-02-19 21:19:13 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
if (!is_zero_v3(trans)) {
|
2019-01-15 23:24:20 +11:00
|
|
|
/* move center of view opposite of hand motion
|
|
|
|
|
* (this is camera mode, not object mode) */
|
2014-02-19 21:19:13 +11:00
|
|
|
sub_v3_v3(rv3d->ofs, trans);
|
|
|
|
|
has_translate = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
has_translate = false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
if (has_rotate) {
|
|
|
|
|
const float turn_sensitivity = 1.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
float rotation[4];
|
|
|
|
|
float axis[3];
|
|
|
|
|
float angle = turn_sensitivity * WM_event_ndof_to_axis_angle(ndof, axis);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
if (fabsf(angle) > 0.0001f) {
|
|
|
|
|
has_rotate = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (use_precision) {
|
2014-02-19 21:19:13 +11:00
|
|
|
angle *= 0.2f;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
/* transform rotation axis from view to world coordinates */
|
|
|
|
|
mul_qt_v3(view_inv, axis);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
/* apply rotation to view */
|
|
|
|
|
axis_angle_to_quat(rotation, axis, angle);
|
|
|
|
|
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
if (U.ndof_flag & NDOF_LOCK_HORIZON) {
|
|
|
|
|
/* force an upright viewpoint
|
|
|
|
|
* TODO: make this less... sudden */
|
|
|
|
|
float view_horizon[3] = {1.0f, 0.0f, 0.0f}; /* view +x */
|
|
|
|
|
float view_direction[3] = {0.0f, 0.0f, -1.0f}; /* view -z (into screen) */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
/* find new inverse since viewquat has changed */
|
2015-10-24 03:51:00 +11:00
|
|
|
invert_qt_qt_normalized(view_inv, rv3d->viewquat);
|
2014-02-19 21:19:13 +11:00
|
|
|
/* could apply reverse rotation to existing view_inv to save a few cycles */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
/* transform view vectors to world coordinates */
|
|
|
|
|
mul_qt_v3(view_inv, view_horizon);
|
|
|
|
|
mul_qt_v3(view_inv, view_direction);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
/* find difference between view & world horizons
|
|
|
|
|
* true horizon lives in world xy plane, so look only at difference in z */
|
|
|
|
|
angle = -asinf(view_horizon[2]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
/* rotate view so view horizon = world horizon */
|
|
|
|
|
axis_angle_to_quat(rotation, view_direction, angle);
|
|
|
|
|
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
rv3d->view = RV3D_VIEW_USER;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
has_rotate = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
*r_has_translate = has_translate;
|
|
|
|
|
*r_has_rotate = has_rotate;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-24 12:36:57 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
2019-03-20 18:39:38 +11:00
|
|
|
/** \name NDOF Orbit/Translate Operator
|
2018-01-23 19:48:49 +11:00
|
|
|
* \{ */
|
2014-02-24 12:36:57 +11:00
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2010-08-07 10:57:15 +00:00
|
|
|
{
|
2013-09-20 01:43:06 +00:00
|
|
|
if (event->type != NDOF_MOTION) {
|
2011-08-06 22:31:16 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2013-09-20 01:43:06 +00:00
|
|
|
}
|
2010-08-07 10:57:15 +00:00
|
|
|
|
2019-07-25 16:36:22 +02:00
|
|
|
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2019-03-20 18:42:10 +11:00
|
|
|
ViewOpsData *vod;
|
|
|
|
|
View3D *v3d;
|
|
|
|
|
RegionView3D *rv3d;
|
|
|
|
|
char xform_flag = 0;
|
2011-08-27 11:52:59 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
const wmNDOFMotionData *ndof = event->customdata;
|
2014-02-12 20:51:49 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
viewops_data_alloc(C, op);
|
|
|
|
|
viewops_data_create(
|
|
|
|
|
C, op, event, viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false));
|
|
|
|
|
vod = op->customdata;
|
2016-05-05 02:01:18 +10:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
2014-02-12 20:51:49 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
v3d = vod->v3d;
|
|
|
|
|
rv3d = vod->rv3d;
|
2011-06-28 15:59:46 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
/* off by default, until changed later this function */
|
|
|
|
|
rv3d->rot_angle = 0.0f;
|
2014-02-18 08:29:54 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false);
|
2012-01-21 03:37:44 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
if (ndof->progress != P_FINISHING) {
|
2019-11-29 18:46:46 +11:00
|
|
|
const bool has_rotation = ndof_has_rotate(ndof, rv3d);
|
2019-03-20 18:42:10 +11:00
|
|
|
/* if we can't rotate, fallback to translate (locked axis views) */
|
2019-11-29 18:46:46 +11:00
|
|
|
const bool has_translate = ndof_has_translate(ndof, v3d, rv3d) &&
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
(RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION);
|
2019-03-20 18:42:10 +11:00
|
|
|
const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp;
|
2012-01-21 03:37:44 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
if (has_translate || has_zoom) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom);
|
2019-03-20 18:42:10 +11:00
|
|
|
xform_flag |= HAS_TRANSLATE;
|
2011-06-20 01:54:49 +00:00
|
|
|
}
|
2010-08-07 10:57:15 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
if (has_rotation) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_ndof_orbit(ndof, vod->area, vod->region, vod, true);
|
2019-03-20 18:42:10 +11:00
|
|
|
xform_flag |= HAS_ROTATE;
|
2019-03-20 18:05:35 +11:00
|
|
|
}
|
2019-03-20 18:42:10 +11:00
|
|
|
}
|
2014-02-12 20:51:49 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
|
|
|
|
|
if (xform_flag) {
|
|
|
|
|
ED_view3d_camera_lock_autokey(
|
|
|
|
|
v3d, rv3d, C, xform_flag & HAS_ROTATE, xform_flag & HAS_TRANSLATE);
|
|
|
|
|
}
|
2014-02-12 20:51:49 +11:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(vod->region);
|
2011-06-28 15:59:46 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2011-06-20 01:54:49 +00:00
|
|
|
}
|
2011-01-21 09:59:58 +00:00
|
|
|
|
2011-07-26 22:43:07 +00:00
|
|
|
void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot)
|
2010-08-07 10:57:15 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2011-07-26 22:43:07 +00:00
|
|
|
ot->name = "NDOF Orbit View";
|
2013-09-30 05:50:41 +00:00
|
|
|
ot->description = "Orbit the view using the 3D mouse";
|
2011-07-26 22:43:07 +00:00
|
|
|
ot->idname = "VIEW3D_OT_ndof_orbit";
|
2010-08-07 10:57:15 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2011-07-14 03:28:31 +00:00
|
|
|
ot->invoke = ndof_orbit_invoke;
|
2010-08-07 10:57:15 +00:00
|
|
|
ot->poll = ED_operator_view3d_active;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-20 18:39:38 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name NDOF Orbit/Zoom Operator
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2012-12-29 12:33:24 +00:00
|
|
|
{
|
2013-09-20 01:43:06 +00:00
|
|
|
if (event->type != NDOF_MOTION) {
|
2012-12-29 12:33:24 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2013-09-20 01:43:06 +00:00
|
|
|
}
|
2012-12-29 12:33:24 +00:00
|
|
|
|
2019-07-25 16:36:22 +02:00
|
|
|
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2019-03-20 18:42:10 +11:00
|
|
|
ViewOpsData *vod;
|
|
|
|
|
View3D *v3d;
|
|
|
|
|
RegionView3D *rv3d;
|
|
|
|
|
char xform_flag = 0;
|
2012-12-29 12:33:24 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
const wmNDOFMotionData *ndof = event->customdata;
|
2014-02-12 20:51:49 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
viewops_data_alloc(C, op);
|
|
|
|
|
viewops_data_create(
|
|
|
|
|
C, op, event, viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false));
|
2016-05-05 19:58:03 +10:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
vod = op->customdata;
|
2016-05-05 02:01:18 +10:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
2014-02-12 20:51:49 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
v3d = vod->v3d;
|
|
|
|
|
rv3d = vod->rv3d;
|
2012-12-29 15:17:26 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
/* off by default, until changed later this function */
|
|
|
|
|
rv3d->rot_angle = 0.0f;
|
2014-02-18 08:29:54 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false);
|
2014-02-20 10:00:16 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
if (ndof->progress == P_FINISHING) {
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
|
|
|
|
else if ((rv3d->persp == RV3D_ORTHO) && RV3D_VIEW_IS_AXIS(rv3d->view)) {
|
|
|
|
|
/* if we can't rotate, fallback to translate (locked axis views) */
|
2019-11-29 18:46:46 +11:00
|
|
|
const bool has_translate = ndof_has_translate(ndof, v3d, rv3d);
|
2019-03-20 18:42:10 +11:00
|
|
|
const bool has_zoom = (ndof->tvec[2] != 0.0f) && ED_view3d_offset_lock_check(v3d, rv3d);
|
2012-12-29 12:33:24 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
if (has_translate || has_zoom) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, true);
|
2019-03-20 18:42:10 +11:00
|
|
|
xform_flag |= HAS_TRANSLATE;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-11-29 18:32:20 +11:00
|
|
|
else {
|
2019-11-28 15:06:04 +11:00
|
|
|
/* Note: based on feedback from T67579, users want to have pan and orbit enabled at once.
|
|
|
|
|
* It's arguable that orbit shouldn't pan (since we have a pan only operator),
|
2019-11-29 18:32:20 +11:00
|
|
|
* so if there are users who like to separate orbit/pan operations - it can be a preference. */
|
|
|
|
|
const bool is_orbit_around_pivot = (U.ndof_flag & NDOF_MODE_ORBIT) ||
|
|
|
|
|
ED_view3d_offset_lock_check(v3d, rv3d);
|
2019-11-29 18:46:46 +11:00
|
|
|
const bool has_rotation = ndof_has_rotate(ndof, rv3d);
|
2020-01-08 14:20:23 +11:00
|
|
|
bool has_translate, has_zoom;
|
2014-02-20 10:00:16 +11:00
|
|
|
|
2020-01-08 14:20:23 +11:00
|
|
|
if (is_orbit_around_pivot) {
|
|
|
|
|
/* Orbit preference or forced lock (Z zooms). */
|
|
|
|
|
has_translate = !is_zero_v2(ndof->tvec) && ndof_has_translate(ndof, v3d, rv3d);
|
|
|
|
|
has_zoom = (ndof->tvec[2] != 0.0f);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Free preference (Z translates). */
|
|
|
|
|
has_translate = ndof_has_translate(ndof, v3d, rv3d);
|
|
|
|
|
has_zoom = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Rotation first because dynamic offset resets offset otherwise (and disables panning). */
|
2019-03-20 18:42:10 +11:00
|
|
|
if (has_rotation) {
|
2019-11-29 18:32:20 +11:00
|
|
|
const float dist_backup = rv3d->dist;
|
|
|
|
|
if (!is_orbit_around_pivot) {
|
|
|
|
|
ED_view3d_distance_set(rv3d, 0.0f);
|
|
|
|
|
}
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_ndof_orbit(ndof, vod->area, vod->region, vod, is_orbit_around_pivot);
|
2019-03-20 18:42:10 +11:00
|
|
|
xform_flag |= HAS_ROTATE;
|
2019-11-29 18:32:20 +11:00
|
|
|
if (!is_orbit_around_pivot) {
|
|
|
|
|
ED_view3d_distance_set(rv3d, dist_backup);
|
|
|
|
|
}
|
2019-03-20 18:42:10 +11:00
|
|
|
}
|
2014-02-20 10:00:16 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
if (has_translate || has_zoom) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom);
|
2019-03-20 18:42:10 +11:00
|
|
|
xform_flag |= HAS_TRANSLATE;
|
2014-02-20 10:00:16 +11:00
|
|
|
}
|
2019-03-20 18:42:10 +11:00
|
|
|
}
|
2012-12-29 12:33:24 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
|
|
|
|
|
if (xform_flag) {
|
|
|
|
|
ED_view3d_camera_lock_autokey(
|
|
|
|
|
v3d, rv3d, C, xform_flag & HAS_ROTATE, xform_flag & HAS_TRANSLATE);
|
2012-12-29 12:33:24 +00:00
|
|
|
}
|
2019-03-20 18:42:10 +11:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(vod->region);
|
2019-03-20 18:42:10 +11:00
|
|
|
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2012-12-29 12:33:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2013-01-27 07:23:58 +00:00
|
|
|
ot->name = "NDOF Orbit View with Zoom";
|
2013-09-30 05:50:41 +00:00
|
|
|
ot->description = "Orbit and zoom the view using the 3D mouse";
|
2012-12-29 12:33:24 +00:00
|
|
|
ot->idname = "VIEW3D_OT_ndof_orbit_zoom";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->invoke = ndof_orbit_zoom_invoke;
|
|
|
|
|
ot->poll = ED_operator_view3d_active;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-20 18:39:38 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name NDOF Pan/Zoom Operator
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2014-02-19 21:19:13 +11:00
|
|
|
static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
2011-07-26 22:43:07 +00:00
|
|
|
{
|
2013-09-20 01:43:06 +00:00
|
|
|
if (event->type != NDOF_MOTION) {
|
2011-08-06 22:31:16 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2013-09-20 01:43:06 +00:00
|
|
|
}
|
2014-02-14 18:38:23 +11:00
|
|
|
|
2019-07-25 16:36:22 +02:00
|
|
|
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2019-03-20 18:42:10 +11:00
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
|
|
|
|
const wmNDOFMotionData *ndof = event->customdata;
|
|
|
|
|
char xform_flag = 0;
|
2011-07-26 22:43:07 +00:00
|
|
|
|
2019-11-29 18:46:46 +11:00
|
|
|
const bool has_translate = ndof_has_translate(ndof, v3d, rv3d);
|
2019-03-20 18:42:10 +11:00
|
|
|
const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp;
|
2014-02-18 08:29:54 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
/* we're panning here! so erase any leftover rotation from other operators */
|
|
|
|
|
rv3d->rot_angle = 0.0f;
|
2013-05-03 07:29:25 +00:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (!(has_translate || has_zoom)) {
|
2019-03-20 18:42:10 +11:00
|
|
|
return OPERATOR_CANCELLED;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2011-07-26 22:43:07 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false);
|
2011-09-07 10:33:46 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
if (ndof->progress != P_FINISHING) {
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2011-07-26 22:43:07 +00:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
if (has_translate || has_zoom) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_ndof_pan_zoom(ndof, area, region, has_translate, has_zoom);
|
2019-03-20 18:42:10 +11:00
|
|
|
xform_flag |= HAS_TRANSLATE;
|
2019-03-20 18:05:35 +11:00
|
|
|
}
|
2019-03-20 18:42:10 +11:00
|
|
|
}
|
2019-03-20 18:05:35 +11:00
|
|
|
|
2019-03-20 18:42:10 +11:00
|
|
|
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
|
|
|
|
|
if (xform_flag) {
|
|
|
|
|
ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, xform_flag & HAS_TRANSLATE);
|
2011-08-06 22:31:16 +00:00
|
|
|
}
|
2019-03-20 18:42:10 +11:00
|
|
|
|
|
|
|
|
ED_region_tag_redraw(CTX_wm_region(C));
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2011-07-26 22:43:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "NDOF Pan View";
|
2013-09-30 05:50:41 +00:00
|
|
|
ot->description = "Pan the view with the 3D mouse";
|
2011-07-26 22:43:07 +00:00
|
|
|
ot->idname = "VIEW3D_OT_ndof_pan";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->invoke = ndof_pan_invoke;
|
|
|
|
|
ot->poll = ED_operator_view3d_active;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-20 18:39:38 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name NDOF Transform All Operator
|
|
|
|
|
* \{ */
|
2012-08-19 13:52:36 +00:00
|
|
|
|
2014-02-24 15:15:17 +11:00
|
|
|
/**
|
|
|
|
|
* wraps #ndof_orbit_zoom but never restrict to orbit.
|
2012-10-04 13:26:15 +00:00
|
|
|
*/
|
2013-03-13 09:03:46 +00:00
|
|
|
static int ndof_all_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2012-08-19 13:52:36 +00:00
|
|
|
{
|
2014-02-24 15:15:17 +11:00
|
|
|
/* weak!, but it works */
|
|
|
|
|
const int ndof_flag = U.ndof_flag;
|
|
|
|
|
int ret;
|
2012-11-07 16:18:20 +00:00
|
|
|
|
2014-02-24 15:15:17 +11:00
|
|
|
U.ndof_flag &= ~NDOF_MODE_ORBIT;
|
2014-02-12 20:51:49 +11:00
|
|
|
|
2014-02-24 15:15:17 +11:00
|
|
|
ret = ndof_orbit_zoom_invoke(C, op, event);
|
2012-08-19 13:52:36 +00:00
|
|
|
|
2014-02-24 15:15:17 +11:00
|
|
|
U.ndof_flag = ndof_flag;
|
2014-02-12 20:51:49 +11:00
|
|
|
|
2014-02-24 15:15:17 +11:00
|
|
|
return ret;
|
2012-08-19 13:52:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_ndof_all(struct wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2019-03-20 18:39:38 +11:00
|
|
|
ot->name = "NDOF Transform View";
|
2013-09-30 05:50:41 +00:00
|
|
|
ot->description = "Pan and rotate the view with the 3D mouse";
|
2012-08-19 13:52:36 +00:00
|
|
|
ot->idname = "VIEW3D_OT_ndof_all";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->invoke = ndof_all_invoke;
|
|
|
|
|
ot->poll = ED_operator_view3d_active;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-18 00:21:55 -04:00
|
|
|
#endif /* WITH_INPUT_NDOF */
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
2008-12-19 17:14:02 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Move (Pan) Operator
|
|
|
|
|
* \{ */
|
2009-09-25 10:24:42 +00:00
|
|
|
|
|
|
|
|
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
|
|
|
|
|
|
|
|
|
|
/* called in transform_ops.c, on each regeneration of keymaps */
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
void viewmove_modal_keymap(wmKeyConfig *keyconf)
|
2009-09-25 10:24:42 +00:00
|
|
|
{
|
2017-10-18 15:07:26 +11:00
|
|
|
static const EnumPropertyItem modal_items[] = {
|
2012-03-25 23:54:33 +00:00
|
|
|
{VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
{VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"},
|
|
|
|
|
{VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2019-02-03 14:01:45 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2012-03-25 23:54:33 +00:00
|
|
|
};
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Move Modal");
|
2009-09-25 10:24:42 +00:00
|
|
|
|
|
|
|
|
/* this function is called for each spacetype, only needs to add map once */
|
2019-03-26 21:16:47 +11:00
|
|
|
if (keymap && keymap->modal_items) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
keymap = WM_modalkeymap_ensure(keyconf, "View3D Move Modal", modal_items);
|
2009-09-25 10:24:42 +00:00
|
|
|
|
|
|
|
|
/* items for modal map */
|
|
|
|
|
WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
|
2020-03-18 10:38:37 -06:00
|
|
|
WM_modalkeymap_add_item(keymap, EVT_ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2012-03-03 16:31:46 +00:00
|
|
|
/* disabled mode switching for now, can re-implement better, later on */
|
|
|
|
|
#if 0
|
2010-01-06 12:22:59 +00:00
|
|
|
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
|
|
|
|
|
WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
|
2019-04-17 08:24:14 +02:00
|
|
|
WM_modalkeymap_add_item(
|
|
|
|
|
keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
|
2012-03-03 16:31:46 +00:00
|
|
|
#endif
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2009-09-25 10:24:42 +00:00
|
|
|
/* assign map to operators */
|
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW3D_OT_move");
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
static void viewmove_apply(ViewOpsData *vod, int x, int y)
|
|
|
|
|
{
|
2013-07-19 10:54:02 +00:00
|
|
|
if (ED_view3d_offset_lock_check(vod->v3d, vod->rv3d)) {
|
2020-03-06 16:56:42 +01:00
|
|
|
vod->rv3d->ofs_lock[0] -= ((vod->prev.event_xy[0] - x) * 2.0f) / (float)vod->region->winx;
|
|
|
|
|
vod->rv3d->ofs_lock[1] -= ((vod->prev.event_xy[1] - y) * 2.0f) / (float)vod->region->winy;
|
2013-07-19 10:54:02 +00:00
|
|
|
}
|
|
|
|
|
else if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) {
|
2015-03-02 11:00:22 +11:00
|
|
|
const float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f;
|
2020-03-06 16:56:42 +01:00
|
|
|
vod->rv3d->camdx += (vod->prev.event_xy[0] - x) / (vod->region->winx * zoomfac);
|
|
|
|
|
vod->rv3d->camdy += (vod->prev.event_xy[1] - y) / (vod->region->winy * zoomfac);
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
CLAMP(vod->rv3d->camdx, -1.0f, 1.0f);
|
|
|
|
|
CLAMP(vod->rv3d->camdy, -1.0f, 1.0f);
|
2008-12-19 12:14:58 +00:00
|
|
|
}
|
2008-12-19 17:14:02 +00:00
|
|
|
else {
|
|
|
|
|
float dvec[3];
|
2011-05-20 13:50:41 +00:00
|
|
|
float mval_f[2];
|
|
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
mval_f[0] = x - vod->prev.event_xy[0];
|
|
|
|
|
mval_f[1] = y - vod->prev.event_xy[1];
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_win_to_delta(vod->region, mval_f, dvec, vod->init.zfac);
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2010-04-21 12:27:48 +00:00
|
|
|
add_v3_v3(vod->rv3d->ofs, dvec);
|
2009-07-09 02:45:48 +00:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_boxview_sync(vod->area, vod->region);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->prev.event_xy[0] = x;
|
|
|
|
|
vod->prev.event_xy[1] = y;
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
|
2011-05-14 17:50:33 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(vod->region);
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
2008-12-19 12:14:58 +00:00
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
2008-12-26 10:31:44 +00:00
|
|
|
{
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
ViewOpsData *vod = op->customdata;
|
|
|
|
|
short event_code = VIEW_PASS;
|
2014-11-24 00:27:50 +01:00
|
|
|
bool use_autokey = false;
|
|
|
|
|
int ret = OPERATOR_RUNNING_MODAL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* execute the events */
|
2012-03-25 23:54:33 +00:00
|
|
|
if (event->type == MOUSEMOVE) {
|
|
|
|
|
event_code = VIEW_APPLY;
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else if (event->type == EVT_MODAL_MAP) {
|
2009-09-25 10:24:42 +00:00
|
|
|
switch (event->val) {
|
|
|
|
|
case VIEW_MODAL_CONFIRM:
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2009-09-25 10:24:42 +00:00
|
|
|
break;
|
2010-01-06 12:22:59 +00:00
|
|
|
case VIEWROT_MODAL_SWITCH_ZOOM:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2010-01-06 12:22:59 +00:00
|
|
|
break;
|
|
|
|
|
case VIEWROT_MODAL_SWITCH_ROTATE:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2010-01-06 12:22:59 +00:00
|
|
|
break;
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
2018-01-29 14:36:40 +11:00
|
|
|
else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
if (event_code == VIEW_APPLY) {
|
2009-09-25 10:24:42 +00:00
|
|
|
viewmove_apply(vod, event->x, event->y);
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
|
|
|
|
use_autokey = true;
|
|
|
|
|
}
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else if (event_code == VIEW_CONFIRM) {
|
2011-05-21 08:56:37 +00:00
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
2014-11-24 00:27:50 +01:00
|
|
|
use_autokey = true;
|
|
|
|
|
ret = OPERATOR_FINISHED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (use_autokey) {
|
|
|
|
|
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ret & OPERATOR_FINISHED) {
|
|
|
|
|
viewops_data_free(C, op);
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
return ret;
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2008-12-19 17:14:02 +00:00
|
|
|
{
|
2011-05-14 17:50:33 +00:00
|
|
|
ViewOpsData *vod;
|
|
|
|
|
|
2019-05-31 19:53:24 +10:00
|
|
|
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
2018-01-29 13:46:18 +11:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* makes op->customdata */
|
2013-09-20 01:24:00 +00:00
|
|
|
viewops_data_alloc(C, op);
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
vod = op->customdata;
|
|
|
|
|
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_LOCK_LOCATION) {
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-29 15:34:39 +11:00
|
|
|
viewops_data_create(C,
|
|
|
|
|
op,
|
|
|
|
|
event,
|
2019-02-28 15:40:28 +11:00
|
|
|
(viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) |
|
2019-05-31 19:53:24 +10:00
|
|
|
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
|
2011-05-14 17:50:33 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
2016-05-05 02:01:18 +10:00
|
|
|
|
2010-01-11 11:14:36 +00:00
|
|
|
if (event->type == MOUSEPAN) {
|
2012-12-20 14:45:56 +00:00
|
|
|
/* invert it, trackpad scroll follows same principle as 2d windows this way */
|
|
|
|
|
viewmove_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy);
|
2011-05-21 08:56:37 +00:00
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2012-10-21 05:46:41 +00:00
|
|
|
viewops_data_free(C, op);
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2010-01-11 11:14:36 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2020-07-03 17:18:56 +02:00
|
|
|
/* add temp handler */
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-30 23:08:53 +00:00
|
|
|
static void viewmove_cancel(bContext *C, wmOperator *op)
|
2011-06-06 11:04:54 +00:00
|
|
|
{
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-25 10:24:42 +00:00
|
|
|
void VIEW3D_OT_move(wmOperatorType *ot)
|
2008-12-19 17:14:02 +00:00
|
|
|
{
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* identifiers */
|
2018-06-27 17:07:02 +02:00
|
|
|
ot->name = "Pan View";
|
2010-02-10 21:15:44 +00:00
|
|
|
ot->description = "Move the view";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_move";
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = viewmove_invoke;
|
|
|
|
|
ot->modal = viewmove_modal;
|
2019-05-31 18:00:08 +02:00
|
|
|
ot->poll = ED_operator_region_view3d_active;
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->cancel = viewmove_cancel;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2019-05-29 00:48:48 +10:00
|
|
|
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
|
2018-01-29 13:46:18 +11:00
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
|
view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT);
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Zoom Operator
|
|
|
|
|
* \{ */
|
2008-12-19 17:14:02 +00:00
|
|
|
|
2011-05-22 11:36:56 +00:00
|
|
|
/* viewdolly_modal_keymap has an exact copy of this, apply fixes to both */
|
2009-09-25 10:24:42 +00:00
|
|
|
/* called in transform_ops.c, on each regeneration of keymaps */
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
void viewzoom_modal_keymap(wmKeyConfig *keyconf)
|
2009-09-25 10:24:42 +00:00
|
|
|
{
|
2017-10-18 15:07:26 +11:00
|
|
|
static const EnumPropertyItem modal_items[] = {
|
2012-03-25 23:54:33 +00:00
|
|
|
{VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
{VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
|
|
|
|
|
{VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2019-02-03 14:01:45 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2012-05-16 14:30:41 +00:00
|
|
|
};
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Zoom Modal");
|
2009-09-25 10:24:42 +00:00
|
|
|
|
|
|
|
|
/* this function is called for each spacetype, only needs to add map once */
|
2019-03-26 21:16:47 +11:00
|
|
|
if (keymap && keymap->modal_items) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
keymap = WM_modalkeymap_ensure(keyconf, "View3D Zoom Modal", modal_items);
|
2009-09-25 10:24:42 +00:00
|
|
|
|
2012-03-03 16:31:46 +00:00
|
|
|
/* disabled mode switching for now, can re-implement better, later on */
|
|
|
|
|
#if 0
|
2010-01-06 12:22:59 +00:00
|
|
|
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
|
|
|
|
|
WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
|
|
|
|
|
WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
|
2012-03-03 16:31:46 +00:00
|
|
|
#endif
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2009-09-25 10:24:42 +00:00
|
|
|
/* assign map to operators */
|
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-29 14:59:56 +11:00
|
|
|
/**
|
2019-04-22 00:18:34 +10:00
|
|
|
* \param zoom_xy: Optionally zoom to window location
|
|
|
|
|
* (coords compatible w/ #wmEvent.x, y). Use when not NULL.
|
2018-01-29 14:59:56 +11:00
|
|
|
*/
|
2020-03-06 16:56:42 +01:00
|
|
|
static void view_zoom_to_window_xy_camera(Scene *scene,
|
|
|
|
|
Depsgraph *depsgraph,
|
|
|
|
|
View3D *v3d,
|
|
|
|
|
ARegion *region,
|
|
|
|
|
float dfac,
|
|
|
|
|
const int zoom_xy[2])
|
2008-12-19 17:14:02 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2015-04-24 00:12:16 +10:00
|
|
|
const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
|
2018-06-17 11:50:56 +02:00
|
|
|
const float zoomfac_new = clamp_f(
|
|
|
|
|
zoomfac * (1.0f / dfac), RV3D_CAMZOOM_MIN_FACTOR, RV3D_CAMZOOM_MAX_FACTOR);
|
2015-04-24 00:12:16 +10:00
|
|
|
const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new);
|
|
|
|
|
|
2018-01-29 13:42:28 +11:00
|
|
|
if (zoom_xy != NULL) {
|
2015-04-24 00:12:16 +10:00
|
|
|
float zoomfac_px;
|
|
|
|
|
rctf camera_frame_old;
|
|
|
|
|
rctf camera_frame_new;
|
|
|
|
|
|
2018-01-29 13:42:28 +11:00
|
|
|
const float pt_src[2] = {zoom_xy[0], zoom_xy[1]};
|
2015-04-24 00:12:16 +10:00
|
|
|
float pt_dst[2];
|
|
|
|
|
float delta_px[2];
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &camera_frame_old, false);
|
|
|
|
|
BLI_rctf_translate(&camera_frame_old, region->winrct.xmin, region->winrct.ymin);
|
2015-04-24 00:12:16 +10:00
|
|
|
|
|
|
|
|
rv3d->camzoom = camzoom_new;
|
|
|
|
|
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &camera_frame_new, false);
|
|
|
|
|
BLI_rctf_translate(&camera_frame_new, region->winrct.xmin, region->winrct.ymin);
|
2015-04-24 00:12:16 +10:00
|
|
|
|
|
|
|
|
BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src);
|
|
|
|
|
sub_v2_v2v2(delta_px, pt_dst, pt_src);
|
|
|
|
|
|
|
|
|
|
/* translate the camera offset using pixel space delta
|
|
|
|
|
* mapped back to the camera (same logic as panning in camera view) */
|
|
|
|
|
zoomfac_px = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 2.0f;
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
rv3d->camdx += delta_px[0] / (region->winx * zoomfac_px);
|
|
|
|
|
rv3d->camdy += delta_px[1] / (region->winy * zoomfac_px);
|
2015-04-24 00:12:16 +10:00
|
|
|
CLAMP(rv3d->camdx, -1.0f, 1.0f);
|
|
|
|
|
CLAMP(rv3d->camdy, -1.0f, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
rv3d->camzoom = camzoom_new;
|
|
|
|
|
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-29 14:59:56 +11:00
|
|
|
/**
|
2019-04-22 00:18:34 +10:00
|
|
|
* \param zoom_xy: Optionally zoom to window location
|
|
|
|
|
* (coords compatible w/ #wmEvent.x, y). Use when not NULL.
|
2018-01-29 14:59:56 +11:00
|
|
|
*/
|
2020-03-06 16:56:42 +01:00
|
|
|
static void view_zoom_to_window_xy_3d(ARegion *region, float dfac, const int zoom_xy[2])
|
2015-04-24 00:12:16 +10:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2015-04-24 00:12:16 +10:00
|
|
|
const float dist_new = rv3d->dist * dfac;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 13:42:28 +11:00
|
|
|
if (zoom_xy != NULL) {
|
2008-12-19 17:14:02 +00:00
|
|
|
float dvec[3];
|
|
|
|
|
float tvec[3];
|
|
|
|
|
float tpos[3];
|
2011-05-20 13:50:41 +00:00
|
|
|
float mval_f[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-09 11:40:42 +00:00
|
|
|
float zfac;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-02-25 20:26:38 +00:00
|
|
|
negate_v3_v3(tpos, rv3d->ofs);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
mval_f[0] = (float)(((zoom_xy[0] - region->winrct.xmin) * 2) - region->winx) / 2.0f;
|
|
|
|
|
mval_f[1] = (float)(((zoom_xy[1] - region->winrct.ymin) * 2) - region->winy) / 2.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-09 11:40:42 +00:00
|
|
|
/* Project cursor position into 3D space */
|
|
|
|
|
zfac = ED_view3d_calc_zfac(rv3d, tpos, NULL);
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_win_to_delta(region, mval_f, dvec, zfac);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* Calculate view target position for dolly */
|
2010-02-25 20:26:38 +00:00
|
|
|
add_v3_v3v3(tvec, tpos, dvec);
|
|
|
|
|
negate_v3(tvec);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* Offset to target position and dolly */
|
2010-07-26 06:34:56 +00:00
|
|
|
copy_v3_v3(rv3d->ofs, tvec);
|
2015-04-24 00:12:16 +10:00
|
|
|
rv3d->dist = dist_new;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* Calculate final offset */
|
2010-02-25 20:26:38 +00:00
|
|
|
madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac);
|
2012-02-22 16:52:06 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2015-04-24 00:12:16 +10:00
|
|
|
rv3d->dist = dist_new;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
static float viewzoom_scale_value(const rcti *winrct,
|
2020-08-18 12:30:10 +10:00
|
|
|
const eViewZoom_Style viewzoom,
|
2015-04-24 00:12:16 +10:00
|
|
|
const bool zoom_invert,
|
|
|
|
|
const bool zoom_invert_force,
|
2018-01-29 16:17:47 +11:00
|
|
|
const int xy_curr[2],
|
|
|
|
|
const int xy_init[2],
|
2015-04-24 00:12:16 +10:00
|
|
|
const float val,
|
|
|
|
|
const float val_orig,
|
|
|
|
|
double *r_timer_lastdraw)
|
2008-12-19 17:14:02 +00:00
|
|
|
{
|
2015-04-24 00:12:16 +10:00
|
|
|
float zfac;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
if (viewzoom == USER_ZOOM_CONT) {
|
|
|
|
|
double time = PIL_check_seconds_timer();
|
2015-04-24 00:12:16 +10:00
|
|
|
float time_step = (float)(time - *r_timer_lastdraw);
|
2011-04-22 14:47:35 +00:00
|
|
|
float fac;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-22 14:47:35 +00:00
|
|
|
if (U.uiflag & USER_ZOOM_HORIZ) {
|
2018-01-29 16:17:47 +11:00
|
|
|
fac = (float)(xy_init[0] - xy_curr[0]);
|
2011-04-22 14:47:35 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2018-01-29 16:17:47 +11:00
|
|
|
fac = (float)(xy_init[1] - xy_curr[1]);
|
2011-04-22 14:47:35 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-18 11:23:34 +10:00
|
|
|
fac /= U.dpi_fac;
|
2019-08-08 22:08:10 +10:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
if (zoom_invert != zoom_invert_force) {
|
2012-03-25 23:54:33 +00:00
|
|
|
fac = -fac;
|
2011-04-22 14:47:35 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-07-08 20:36:00 +00:00
|
|
|
/* oldstyle zoom */
|
2011-04-22 14:47:35 +00:00
|
|
|
zfac = 1.0f + ((fac / 20.0f) * time_step);
|
2015-04-24 00:12:16 +10:00
|
|
|
*r_timer_lastdraw = time;
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else if (viewzoom == USER_ZOOM_SCALE) {
|
2012-07-08 20:36:00 +00:00
|
|
|
/* method which zooms based on how far you move the mouse */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-28 15:02:57 +11:00
|
|
|
const int ctr[2] = {
|
2015-04-24 00:12:16 +10:00
|
|
|
BLI_rcti_cent_x(winrct),
|
|
|
|
|
BLI_rcti_cent_y(winrct),
|
2014-03-28 15:02:57 +11:00
|
|
|
};
|
2020-08-18 11:23:34 +10:00
|
|
|
float len_new = (5 * U.dpi_fac) + ((float)len_v2v2_int(ctr, xy_curr) / U.dpi_fac);
|
|
|
|
|
float len_old = (5 * U.dpi_fac) + ((float)len_v2v2_int(ctr, xy_init) / U.dpi_fac);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
/* intentionally ignore 'zoom_invert' for scale */
|
|
|
|
|
if (zoom_invert_force) {
|
|
|
|
|
SWAP(float, len_new, len_old);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
zfac = val_orig * (len_old / max_ff(len_new, 1.0f)) / val;
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else { /* USER_ZOOM_DOLLY */
|
2020-08-18 11:23:34 +10:00
|
|
|
float len_new = 5 * U.dpi_fac;
|
|
|
|
|
float len_old = 5 * U.dpi_fac;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-22 14:47:35 +00:00
|
|
|
if (U.uiflag & USER_ZOOM_HORIZ) {
|
2020-08-18 11:23:34 +10:00
|
|
|
len_new += (winrct->xmax - (xy_curr[0])) / U.dpi_fac;
|
|
|
|
|
len_old += (winrct->xmax - (xy_init[0])) / U.dpi_fac;
|
2009-11-28 04:43:15 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2020-08-18 11:23:34 +10:00
|
|
|
len_new += (winrct->ymax - (xy_curr[1])) / U.dpi_fac;
|
|
|
|
|
len_old += (winrct->ymax - (xy_init[1])) / U.dpi_fac;
|
2009-11-28 04:43:15 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
if (zoom_invert != zoom_invert_force) {
|
|
|
|
|
SWAP(float, len_new, len_old);
|
2012-03-07 18:34:16 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
zfac = val_orig * (2.0f * ((len_new / max_ff(len_old, 1.0f)) - 1.0f) + 1.0f) / val;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
return zfac;
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
static float viewzoom_scale_value_offset(const rcti *winrct,
|
2020-08-18 12:30:10 +10:00
|
|
|
const eViewZoom_Style viewzoom,
|
2018-01-29 16:17:47 +11:00
|
|
|
const bool zoom_invert,
|
|
|
|
|
const bool zoom_invert_force,
|
|
|
|
|
const int xy_curr[2],
|
|
|
|
|
const int xy_init[2],
|
|
|
|
|
const int xy_offset[2],
|
|
|
|
|
const float val,
|
|
|
|
|
const float val_orig,
|
|
|
|
|
double *r_timer_lastdraw)
|
|
|
|
|
{
|
|
|
|
|
const int xy_curr_offset[2] = {
|
|
|
|
|
xy_curr[0] + xy_offset[0],
|
|
|
|
|
xy_curr[1] + xy_offset[1],
|
|
|
|
|
};
|
|
|
|
|
const int xy_init_offset[2] = {
|
|
|
|
|
xy_init[0] + xy_offset[0],
|
|
|
|
|
xy_init[1] + xy_offset[1],
|
|
|
|
|
};
|
|
|
|
|
return viewzoom_scale_value(winrct,
|
|
|
|
|
viewzoom,
|
|
|
|
|
zoom_invert,
|
|
|
|
|
zoom_invert_force,
|
|
|
|
|
xy_curr_offset,
|
|
|
|
|
xy_init_offset,
|
|
|
|
|
val,
|
|
|
|
|
val_orig,
|
|
|
|
|
r_timer_lastdraw);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
static void viewzoom_apply_camera(ViewOpsData *vod,
|
|
|
|
|
const int xy[2],
|
2020-08-18 12:30:10 +10:00
|
|
|
const eViewZoom_Style viewzoom,
|
2018-01-29 13:42:28 +11:00
|
|
|
const bool zoom_invert,
|
|
|
|
|
const bool zoom_to_pos)
|
2015-04-24 00:12:16 +10:00
|
|
|
{
|
|
|
|
|
float zfac;
|
2018-01-29 14:36:40 +11:00
|
|
|
float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->init.camzoom) * 2.0f;
|
2015-04-24 00:12:16 +10:00
|
|
|
float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
zfac = viewzoom_scale_value_offset(&vod->region->winrct,
|
2018-01-29 16:17:47 +11:00
|
|
|
viewzoom,
|
|
|
|
|
zoom_invert,
|
|
|
|
|
true,
|
|
|
|
|
xy,
|
|
|
|
|
vod->init.event_xy,
|
|
|
|
|
vod->init.event_xy_offset,
|
2015-04-24 00:12:16 +10:00
|
|
|
zoomfac,
|
|
|
|
|
zoomfac_prev,
|
2018-01-29 14:36:40 +11:00
|
|
|
&vod->prev.time);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-06 12:30:59 +11:00
|
|
|
if (!ELEM(zfac, 1.0f, 0.0f)) {
|
2015-04-24 00:12:16 +10:00
|
|
|
/* calculate inverted, then invert again (needed because of camera zoom scaling) */
|
|
|
|
|
zfac = 1.0f / zfac;
|
2018-01-29 13:42:28 +11:00
|
|
|
view_zoom_to_window_xy_camera(vod->scene,
|
2018-01-18 15:58:02 +01:00
|
|
|
vod->depsgraph,
|
|
|
|
|
vod->v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
vod->region,
|
2018-01-29 14:36:40 +11:00
|
|
|
zfac,
|
|
|
|
|
zoom_to_pos ? vod->prev.event_xy : NULL);
|
2015-04-24 00:12:16 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(vod->region);
|
2015-04-24 00:12:16 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
static void viewzoom_apply_3d(ViewOpsData *vod,
|
|
|
|
|
const int xy[2],
|
2020-08-18 12:30:10 +10:00
|
|
|
const eViewZoom_Style viewzoom,
|
2018-01-29 13:42:28 +11:00
|
|
|
const bool zoom_invert,
|
|
|
|
|
const bool zoom_to_pos)
|
2015-04-24 00:12:16 +10:00
|
|
|
{
|
|
|
|
|
float zfac;
|
|
|
|
|
float dist_range[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
ED_view3d_dist_range_get(vod->v3d, dist_range);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
zfac = viewzoom_scale_value_offset(&vod->region->winrct,
|
2018-01-29 16:17:47 +11:00
|
|
|
viewzoom,
|
|
|
|
|
zoom_invert,
|
|
|
|
|
false,
|
|
|
|
|
xy,
|
|
|
|
|
vod->init.event_xy,
|
|
|
|
|
vod->init.event_xy_offset,
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->rv3d->dist,
|
|
|
|
|
vod->init.dist,
|
|
|
|
|
&vod->prev.time);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
if (zfac != 1.0f) {
|
|
|
|
|
const float zfac_min = dist_range[0] / vod->rv3d->dist;
|
|
|
|
|
const float zfac_max = dist_range[1] / vod->rv3d->dist;
|
|
|
|
|
CLAMP(zfac, zfac_min, zfac_max);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
view_zoom_to_window_xy_3d(vod->region, zfac, zoom_to_pos ? vod->prev.event_xy : NULL);
|
2012-03-07 18:34:16 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-05-19 17:19:05 +00:00
|
|
|
/* these limits were in old code too */
|
2014-08-25 14:11:50 +10:00
|
|
|
CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_boxview_sync(vod->area, vod->region);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(vod->region);
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-24 00:12:16 +10:00
|
|
|
static void viewzoom_apply(ViewOpsData *vod,
|
|
|
|
|
const int xy[2],
|
2020-08-18 12:30:10 +10:00
|
|
|
const eViewZoom_Style viewzoom,
|
2018-01-29 13:42:28 +11:00
|
|
|
const bool zoom_invert,
|
|
|
|
|
const bool zoom_to_pos)
|
2015-04-24 00:12:16 +10:00
|
|
|
{
|
|
|
|
|
if ((vod->rv3d->persp == RV3D_CAMOB) &&
|
|
|
|
|
(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0) {
|
2018-01-29 13:42:28 +11:00
|
|
|
viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos);
|
2015-04-24 00:12:16 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2018-01-29 13:42:28 +11:00
|
|
|
viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert, zoom_to_pos);
|
2015-04-24 00:12:16 +10:00
|
|
|
}
|
|
|
|
|
}
|
2008-12-19 17:14:02 +00:00
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
2008-12-26 10:31:44 +00:00
|
|
|
{
|
2012-03-25 23:54:33 +00:00
|
|
|
ViewOpsData *vod = op->customdata;
|
|
|
|
|
short event_code = VIEW_PASS;
|
2014-11-24 00:27:50 +01:00
|
|
|
bool use_autokey = false;
|
|
|
|
|
int ret = OPERATOR_RUNNING_MODAL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* execute the events */
|
2010-02-06 12:44:37 +00:00
|
|
|
if (event->type == TIMER && event->customdata == vod->timer) {
|
|
|
|
|
/* continuous zoom */
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_APPLY;
|
2010-02-06 12:44:37 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else if (event->type == MOUSEMOVE) {
|
|
|
|
|
event_code = VIEW_APPLY;
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else if (event->type == EVT_MODAL_MAP) {
|
2009-09-25 10:24:42 +00:00
|
|
|
switch (event->val) {
|
|
|
|
|
case VIEW_MODAL_CONFIRM:
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2009-09-25 10:24:42 +00:00
|
|
|
break;
|
2010-01-06 12:22:59 +00:00
|
|
|
case VIEWROT_MODAL_SWITCH_MOVE:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2010-01-06 12:22:59 +00:00
|
|
|
break;
|
|
|
|
|
case VIEWROT_MODAL_SWITCH_ROTATE:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2010-01-06 12:22:59 +00:00
|
|
|
break;
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
2018-01-29 14:36:40 +11:00
|
|
|
else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
if (event_code == VIEW_APPLY) {
|
2019-05-31 19:53:24 +10:00
|
|
|
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
2018-01-29 13:42:28 +11:00
|
|
|
viewzoom_apply(vod,
|
|
|
|
|
&event->x,
|
2020-08-18 12:30:10 +10:00
|
|
|
(eViewZoom_Style)U.viewzoom,
|
2018-01-29 13:42:28 +11:00
|
|
|
(U.uiflag & USER_ZOOM_INVERT) != 0,
|
2019-05-31 19:53:24 +10:00
|
|
|
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
|
|
|
|
use_autokey = true;
|
|
|
|
|
}
|
2009-09-25 10:24:42 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else if (event_code == VIEW_CONFIRM) {
|
2011-05-21 08:56:37 +00:00
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
2014-11-24 00:27:50 +01:00
|
|
|
use_autokey = true;
|
|
|
|
|
ret = OPERATOR_FINISHED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (use_autokey) {
|
|
|
|
|
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ret & OPERATOR_FINISHED) {
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
return ret;
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2008-12-19 19:27:41 +00:00
|
|
|
static int viewzoom_exec(bContext *C, wmOperator *op)
|
2008-12-19 17:14:02 +00:00
|
|
|
{
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2015-04-24 00:12:16 +10:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2011-01-03 01:26:54 +00:00
|
|
|
View3D *v3d;
|
|
|
|
|
RegionView3D *rv3d;
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area;
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2013-03-22 04:40:45 +00:00
|
|
|
bool use_cam_zoom;
|
2014-08-25 14:11:50 +10:00
|
|
|
float dist_range[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-22 04:40:45 +00:00
|
|
|
const int delta = RNA_int_get(op->ptr, "delta");
|
2019-05-31 19:53:24 +10:00
|
|
|
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-22 16:52:06 +00:00
|
|
|
if (op->customdata) {
|
2012-03-25 23:54:33 +00:00
|
|
|
ViewOpsData *vod = op->customdata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
area = vod->area;
|
2020-03-06 16:56:42 +01:00
|
|
|
region = vod->region;
|
2011-01-03 01:26:54 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2020-04-03 13:25:03 +02:00
|
|
|
area = CTX_wm_area(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
region = CTX_wm_region(C);
|
2011-01-03 01:26:54 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
v3d = area->spacedata.first;
|
2020-03-06 16:56:42 +01:00
|
|
|
rv3d = region->regiondata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
use_cam_zoom = (rv3d->persp == RV3D_CAMOB) &&
|
|
|
|
|
!(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 13:42:28 +11:00
|
|
|
int zoom_xy_buf[2];
|
|
|
|
|
const int *zoom_xy = NULL;
|
2019-05-31 19:53:24 +10:00
|
|
|
if (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) {
|
2018-01-29 13:42:28 +11:00
|
|
|
zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") :
|
2020-03-06 16:56:42 +01:00
|
|
|
region->winx / 2;
|
2018-01-29 13:42:28 +11:00
|
|
|
zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") :
|
2020-03-06 16:56:42 +01:00
|
|
|
region->winy / 2;
|
2018-01-29 13:42:28 +11:00
|
|
|
zoom_xy = zoom_xy_buf;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-08-25 14:11:50 +10:00
|
|
|
ED_view3d_dist_range_get(v3d, dist_range);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-22 16:52:06 +00:00
|
|
|
if (delta < 0) {
|
2015-04-24 00:12:16 +10:00
|
|
|
const float step = 1.2f;
|
2008-12-19 19:27:41 +00:00
|
|
|
/* this min and max is also in viewmove() */
|
2012-02-22 16:52:06 +00:00
|
|
|
if (use_cam_zoom) {
|
2020-03-06 16:56:42 +01:00
|
|
|
view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy);
|
2008-12-19 19:27:41 +00:00
|
|
|
}
|
2015-04-24 00:12:16 +10:00
|
|
|
else {
|
|
|
|
|
if (rv3d->dist < dist_range[1]) {
|
2020-03-06 16:56:42 +01:00
|
|
|
view_zoom_to_window_xy_3d(region, step, zoom_xy);
|
2009-10-16 00:23:40 +00:00
|
|
|
}
|
2008-12-19 19:27:41 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2008-12-19 19:27:41 +00:00
|
|
|
else {
|
2015-04-24 00:12:16 +10:00
|
|
|
const float step = 1.0f / 1.2f;
|
2012-02-22 16:52:06 +00:00
|
|
|
if (use_cam_zoom) {
|
2020-03-06 16:56:42 +01:00
|
|
|
view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy);
|
2008-12-19 19:27:41 +00:00
|
|
|
}
|
2015-04-24 00:12:16 +10:00
|
|
|
else {
|
|
|
|
|
if (rv3d->dist > dist_range[0]) {
|
2020-03-06 16:56:42 +01:00
|
|
|
view_zoom_to_window_xy_3d(region, step, zoom_xy);
|
2015-04-24 00:12:16 +10:00
|
|
|
}
|
2009-10-16 00:23:40 +00:00
|
|
|
}
|
2008-12-19 19:27:41 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_boxview_sync(area, region);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-05-21 08:56:37 +00:00
|
|
|
ED_view3d_depth_tag_update(rv3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
|
2014-11-24 00:27:50 +01:00
|
|
|
ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(region);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-01-19 04:14:57 +00:00
|
|
|
viewops_data_free(C, op);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-19 19:27:41 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-22 15:34:07 +00:00
|
|
|
/* viewdolly_invoke() copied this function, changes here may apply there */
|
2013-03-13 09:03:46 +00:00
|
|
|
static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2008-12-19 19:27:41 +00:00
|
|
|
{
|
2011-05-14 05:42:58 +00:00
|
|
|
ViewOpsData *vod;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-31 19:53:24 +10:00
|
|
|
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-05-14 05:42:58 +00:00
|
|
|
/* makes op->customdata */
|
2013-09-20 01:24:00 +00:00
|
|
|
viewops_data_alloc(C, op);
|
2018-01-29 15:34:39 +11:00
|
|
|
viewops_data_create(C,
|
|
|
|
|
op,
|
|
|
|
|
event,
|
2019-02-28 15:40:28 +11:00
|
|
|
(viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) |
|
2019-05-31 19:53:24 +10:00
|
|
|
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
|
2012-03-25 23:54:33 +00:00
|
|
|
vod = op->customdata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-10-16 00:23:40 +00:00
|
|
|
/* if one or the other zoom position aren't set, set from event */
|
2012-01-11 16:32:12 +00:00
|
|
|
if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
|
2009-10-16 00:23:40 +00:00
|
|
|
RNA_int_set(op->ptr, "mx", event->x);
|
|
|
|
|
RNA_int_set(op->ptr, "my", event->y);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-22 16:52:06 +00:00
|
|
|
if (RNA_struct_property_is_set(op->ptr, "delta")) {
|
2008-12-19 19:27:41 +00:00
|
|
|
viewzoom_exec(C, op);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-11-06 12:30:59 +11:00
|
|
|
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-22 14:47:35 +00:00
|
|
|
if (U.uiflag & USER_ZOOM_HORIZ) {
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
|
2010-01-11 11:14:36 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x -
|
|
|
|
|
event->prevx;
|
2010-01-11 11:14:36 +00:00
|
|
|
}
|
2018-01-29 13:42:28 +11:00
|
|
|
viewzoom_apply(vod,
|
|
|
|
|
&event->prevx,
|
|
|
|
|
USER_ZOOM_DOLLY,
|
|
|
|
|
(U.uiflag & USER_ZOOM_INVERT) != 0,
|
2019-05-31 19:53:24 +10:00
|
|
|
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
|
2014-11-24 00:27:50 +01:00
|
|
|
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-05-21 08:56:37 +00:00
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-01-11 11:14:36 +00:00
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-07-03 17:18:56 +02:00
|
|
|
if (U.viewzoom == USER_ZOOM_CONT) {
|
|
|
|
|
/* needs a timer to continue redrawing */
|
|
|
|
|
vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
|
|
|
|
|
vod->prev.time = PIL_check_seconds_timer();
|
2010-01-11 11:14:36 +00:00
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
|
|
|
|
|
/* add temp handler */
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
2008-12-19 19:27:41 +00:00
|
|
|
}
|
|
|
|
|
return OPERATOR_FINISHED;
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-30 23:08:53 +00:00
|
|
|
static void viewzoom_cancel(bContext *C, wmOperator *op)
|
2011-06-06 11:04:54 +00:00
|
|
|
{
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
}
|
2008-12-19 17:14:02 +00:00
|
|
|
|
2009-03-29 02:15:13 +00:00
|
|
|
void VIEW3D_OT_zoom(wmOperatorType *ot)
|
2008-12-19 17:14:02 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Zoom View";
|
2010-02-10 21:15:44 +00:00
|
|
|
ot->description = "Zoom in/out in the view";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_zoom";
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-19 17:14:02 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = viewzoom_invoke;
|
|
|
|
|
ot->exec = viewzoom_exec;
|
|
|
|
|
ot->modal = viewzoom_modal;
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
ot->poll = view3d_zoom_or_dolly_poll;
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->cancel = viewzoom_cancel;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2019-05-29 00:48:48 +10:00
|
|
|
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2018-01-28 18:22:54 +11:00
|
|
|
/* properties */
|
2018-01-29 13:46:18 +11:00
|
|
|
view3d_operator_properties_common(
|
|
|
|
|
ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT);
|
2008-12-19 17:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Dolly Operator
|
|
|
|
|
*
|
|
|
|
|
* Like zoom but translates the view offset along the view direction
|
|
|
|
|
* which avoids #RegionView3D.dist approaching zero.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
/* this is an exact copy of viewzoom_modal_keymap */
|
|
|
|
|
/* called in transform_ops.c, on each regeneration of keymaps */
|
|
|
|
|
void viewdolly_modal_keymap(wmKeyConfig *keyconf)
|
|
|
|
|
{
|
|
|
|
|
static const EnumPropertyItem modal_items[] = {
|
|
|
|
|
{VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
|
|
|
|
|
|
|
|
|
|
{VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
|
|
|
|
|
{VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
|
|
|
|
|
|
2019-02-03 14:01:45 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2018-01-23 19:48:49 +11:00
|
|
|
};
|
|
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Dolly Modal");
|
2018-01-23 19:48:49 +11:00
|
|
|
|
|
|
|
|
/* this function is called for each spacetype, only needs to add map once */
|
2019-03-26 21:16:47 +11:00
|
|
|
if (keymap && keymap->modal_items) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-01-23 19:48:49 +11:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
keymap = WM_modalkeymap_ensure(keyconf, "View3D Dolly Modal", modal_items);
|
2018-01-23 19:48:49 +11:00
|
|
|
|
|
|
|
|
/* disabled mode switching for now, can re-implement better, later on */
|
|
|
|
|
#if 0
|
|
|
|
|
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
|
|
|
|
|
WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
|
|
|
|
|
WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
|
|
|
|
|
#endif
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/* assign map to operators */
|
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly");
|
|
|
|
|
}
|
2011-04-22 15:34:07 +00:00
|
|
|
|
2017-02-18 17:25:12 +01:00
|
|
|
static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
|
|
|
|
if (ED_view3d_offset_lock_check(v3d, rv3d)) {
|
|
|
|
|
BKE_report(op->reports, RPT_WARNING, "Cannot dolly when the view offset is locked");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
return false;
|
2017-02-18 17:25:12 +01:00
|
|
|
}
|
|
|
|
|
|
2020-08-07 22:56:13 +10:00
|
|
|
static void view_dolly_to_vector_3d(ARegion *region,
|
|
|
|
|
const float orig_ofs[3],
|
|
|
|
|
const float dvec[3],
|
|
|
|
|
float dfac)
|
2011-04-22 15:34:07 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2011-08-19 16:21:29 +00:00
|
|
|
madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -(1.0f - dfac));
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-29 13:42:28 +11:00
|
|
|
static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_invert)
|
2011-04-22 15:34:07 +00:00
|
|
|
{
|
2012-03-25 23:54:33 +00:00
|
|
|
float zfac = 1.0;
|
2011-04-22 15:34:07 +00:00
|
|
|
|
|
|
|
|
{
|
|
|
|
|
float len1, len2;
|
|
|
|
|
|
|
|
|
|
if (U.uiflag & USER_ZOOM_HORIZ) {
|
2020-03-06 16:56:42 +01:00
|
|
|
len1 = (vod->region->winrct.xmax - xy[0]) + 5;
|
|
|
|
|
len2 = (vod->region->winrct.xmax - vod->init.event_xy[0]) + 5;
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2020-03-06 16:56:42 +01:00
|
|
|
len1 = (vod->region->winrct.ymax - xy[1]) + 5;
|
|
|
|
|
len2 = (vod->region->winrct.ymax - vod->init.event_xy[1]) + 5;
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
2018-01-29 13:42:28 +11:00
|
|
|
if (zoom_invert) {
|
2011-04-22 15:34:07 +00:00
|
|
|
SWAP(float, len1, len2);
|
2018-01-29 13:42:28 +11:00
|
|
|
}
|
2011-04-22 15:34:07 +00:00
|
|
|
|
2012-10-13 16:42:12 +00:00
|
|
|
zfac = 1.0f + ((len1 - len2) * 0.01f * vod->rv3d->dist);
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-29 13:42:28 +11:00
|
|
|
if (zfac != 1.0f) {
|
2020-03-06 16:56:42 +01:00
|
|
|
view_dolly_to_vector_3d(vod->region, vod->init.ofs, vod->init.mousevec, zfac);
|
2018-01-29 13:42:28 +11:00
|
|
|
}
|
2011-04-22 15:34:07 +00:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_boxview_sync(vod->area, vod->region);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2011-04-22 15:34:07 +00:00
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
|
2011-05-14 17:50:33 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(vod->region);
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
2011-04-22 15:34:07 +00:00
|
|
|
{
|
2012-03-25 23:54:33 +00:00
|
|
|
ViewOpsData *vod = op->customdata;
|
|
|
|
|
short event_code = VIEW_PASS;
|
2014-11-24 00:27:50 +01:00
|
|
|
bool use_autokey = false;
|
|
|
|
|
int ret = OPERATOR_RUNNING_MODAL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-22 15:34:07 +00:00
|
|
|
/* execute the events */
|
2012-03-25 23:54:33 +00:00
|
|
|
if (event->type == MOUSEMOVE) {
|
|
|
|
|
event_code = VIEW_APPLY;
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else if (event->type == EVT_MODAL_MAP) {
|
2011-04-22 15:34:07 +00:00
|
|
|
switch (event->val) {
|
|
|
|
|
case VIEW_MODAL_CONFIRM:
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2011-04-22 15:34:07 +00:00
|
|
|
break;
|
|
|
|
|
case VIEWROT_MODAL_SWITCH_MOVE:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2011-04-22 15:34:07 +00:00
|
|
|
break;
|
|
|
|
|
case VIEWROT_MODAL_SWITCH_ROTATE:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2011-04-22 15:34:07 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-29 14:36:40 +11:00
|
|
|
else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
|
2012-03-25 23:54:33 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
if (event_code == VIEW_APPLY) {
|
2018-01-29 13:42:28 +11:00
|
|
|
viewdolly_apply(vod, &event->x, (U.uiflag & USER_ZOOM_INVERT) != 0);
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
|
|
|
|
use_autokey = true;
|
|
|
|
|
}
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
else if (event_code == VIEW_CONFIRM) {
|
2011-05-21 08:56:37 +00:00
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
2014-11-24 00:27:50 +01:00
|
|
|
use_autokey = true;
|
|
|
|
|
ret = OPERATOR_FINISHED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (use_autokey) {
|
|
|
|
|
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ret & OPERATOR_FINISHED) {
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
return ret;
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int viewdolly_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
2013-07-21 09:59:08 +00:00
|
|
|
View3D *v3d;
|
2011-04-22 15:34:07 +00:00
|
|
|
RegionView3D *rv3d;
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area;
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2011-04-22 15:34:07 +00:00
|
|
|
float mousevec[3];
|
|
|
|
|
|
2013-03-22 04:40:45 +00:00
|
|
|
const int delta = RNA_int_get(op->ptr, "delta");
|
2011-04-22 15:34:07 +00:00
|
|
|
|
2012-02-22 16:52:06 +00:00
|
|
|
if (op->customdata) {
|
2012-03-25 23:54:33 +00:00
|
|
|
ViewOpsData *vod = op->customdata;
|
2011-04-22 15:34:07 +00:00
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
area = vod->area;
|
2020-03-06 16:56:42 +01:00
|
|
|
region = vod->region;
|
2018-01-29 14:36:40 +11:00
|
|
|
copy_v3_v3(mousevec, vod->init.mousevec);
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2020-04-03 13:25:03 +02:00
|
|
|
area = CTX_wm_area(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
region = CTX_wm_region(C);
|
|
|
|
|
negate_v3_v3(mousevec, ((RegionView3D *)region->regiondata)->viewinv[2]);
|
2011-05-12 06:52:24 +00:00
|
|
|
normalize_v3(mousevec);
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
v3d = area->spacedata.first;
|
2020-03-06 16:56:42 +01:00
|
|
|
rv3d = region->regiondata;
|
2011-04-22 15:34:07 +00:00
|
|
|
|
2019-05-31 19:53:24 +10:00
|
|
|
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
2018-01-29 13:46:18 +11:00
|
|
|
|
2011-04-22 15:34:07 +00:00
|
|
|
/* overwrite the mouse vector with the view direction (zoom into the center) */
|
2019-05-31 19:53:24 +10:00
|
|
|
if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) {
|
2011-04-22 15:34:07 +00:00
|
|
|
normalize_v3_v3(mousevec, rv3d->viewinv[2]);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta < 0 ? 0.2f : 1.8f);
|
2011-04-22 15:34:07 +00:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_boxview_sync(area, region);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2011-04-22 15:34:07 +00:00
|
|
|
|
2011-05-21 08:56:37 +00:00
|
|
|
ED_view3d_depth_tag_update(rv3d);
|
2013-07-21 09:59:08 +00:00
|
|
|
|
2019-07-25 16:36:22 +02:00
|
|
|
ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d);
|
2013-07-21 09:59:08 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(region);
|
2011-04-22 15:34:07 +00:00
|
|
|
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* copied from viewzoom_invoke(), changes here may apply there */
|
2013-03-13 09:03:46 +00:00
|
|
|
static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2011-05-14 05:42:58 +00:00
|
|
|
{
|
|
|
|
|
ViewOpsData *vod;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (viewdolly_offset_lock_check(C, op)) {
|
2013-09-20 01:43:06 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-05-14 05:42:58 +00:00
|
|
|
/* makes op->customdata */
|
2013-09-20 01:24:00 +00:00
|
|
|
viewops_data_alloc(C, op);
|
2012-03-25 23:54:33 +00:00
|
|
|
vod = op->customdata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-04 21:04:36 +11:00
|
|
|
/* poll should check but in some cases fails, see poll func for details */
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_LOCK_ROTATION) {
|
2013-09-20 01:24:00 +00:00
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-20 01:24:00 +00:00
|
|
|
/* needs to run before 'viewops_data_create' so the backup 'rv3d->ofs' is correct */
|
|
|
|
|
/* switch from camera view when: */
|
|
|
|
|
if (vod->rv3d->persp != RV3D_PERSP) {
|
|
|
|
|
if (vod->rv3d->persp == RV3D_CAMOB) {
|
|
|
|
|
/* ignore rv3d->lpersp because dolly only makes sense in perspective mode */
|
2019-07-25 16:36:22 +02:00
|
|
|
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2018-05-21 20:29:00 +02:00
|
|
|
ED_view3d_persp_switch_from_camera(depsgraph, vod->v3d, vod->rv3d, RV3D_PERSP);
|
2013-09-20 01:24:00 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
vod->rv3d->persp = RV3D_PERSP;
|
|
|
|
|
}
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(vod->region);
|
2013-09-20 01:24:00 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-31 19:53:24 +10:00
|
|
|
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-29 15:34:39 +11:00
|
|
|
viewops_data_create(C,
|
|
|
|
|
op,
|
|
|
|
|
event,
|
2019-02-28 15:40:28 +11:00
|
|
|
(viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) |
|
2019-05-31 19:53:24 +10:00
|
|
|
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-22 15:34:07 +00:00
|
|
|
/* if one or the other zoom position aren't set, set from event */
|
2012-01-11 16:32:12 +00:00
|
|
|
if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
|
2011-04-22 15:34:07 +00:00
|
|
|
RNA_int_set(op->ptr, "mx", event->x);
|
|
|
|
|
RNA_int_set(op->ptr, "my", event->y);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-22 16:52:06 +00:00
|
|
|
if (RNA_struct_property_is_set(op->ptr, "delta")) {
|
2011-04-22 15:34:07 +00:00
|
|
|
viewdolly_exec(C, op);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* overwrite the mouse vector with the view direction (zoom into the center) */
|
2019-05-31 19:53:24 +10:00
|
|
|
if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) {
|
2018-01-29 14:36:40 +11:00
|
|
|
negate_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]);
|
|
|
|
|
normalize_v3(vod->init.mousevec);
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-22 15:34:07 +00:00
|
|
|
if (event->type == MOUSEZOOM) {
|
2013-03-20 23:14:18 +00:00
|
|
|
/* Bypass Zoom invert flag for track pads (pass false always) */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-22 15:34:07 +00:00
|
|
|
if (U.uiflag & USER_ZOOM_HORIZ) {
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x -
|
|
|
|
|
event->prevx;
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
2018-01-29 13:42:28 +11:00
|
|
|
viewdolly_apply(vod, &event->prevx, (U.uiflag & USER_ZOOM_INVERT) == 0);
|
2011-05-21 08:56:37 +00:00
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-22 15:34:07 +00:00
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-07-03 17:18:56 +02:00
|
|
|
/* add temp handler */
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-30 23:08:53 +00:00
|
|
|
static void viewdolly_cancel(bContext *C, wmOperator *op)
|
2011-06-06 11:04:54 +00:00
|
|
|
{
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-22 15:34:07 +00:00
|
|
|
void VIEW3D_OT_dolly(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2013-01-27 07:23:58 +00:00
|
|
|
ot->name = "Dolly View";
|
2011-04-22 15:34:07 +00:00
|
|
|
ot->description = "Dolly in/out in the view";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_dolly";
|
2011-04-22 15:34:07 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = viewdolly_invoke;
|
|
|
|
|
ot->exec = viewdolly_exec;
|
|
|
|
|
ot->modal = viewdolly_modal;
|
2013-09-20 01:24:00 +00:00
|
|
|
ot->poll = ED_operator_region_view3d_active;
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->cancel = viewdolly_cancel;
|
2011-04-22 15:34:07 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
2019-05-29 00:48:48 +10:00
|
|
|
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
|
2011-04-22 15:34:07 +00:00
|
|
|
|
2018-01-28 18:22:54 +11:00
|
|
|
/* properties */
|
2018-01-29 13:46:18 +11:00
|
|
|
view3d_operator_properties_common(
|
|
|
|
|
ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT);
|
2011-04-22 15:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View All Operator
|
|
|
|
|
*
|
|
|
|
|
* Move & Zoom the view to fit all of its contents.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2019-03-07 12:37:47 +11:00
|
|
|
static bool view3d_object_skip_minmax(const View3D *v3d,
|
|
|
|
|
const RegionView3D *rv3d,
|
|
|
|
|
const Object *ob,
|
|
|
|
|
const bool skip_camera,
|
|
|
|
|
bool *r_only_center)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(ob->id.orig_id == NULL);
|
|
|
|
|
*r_only_center = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-07 12:37:47 +11:00
|
|
|
if (skip_camera && (ob == v3d->camera)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-07 12:37:47 +11:00
|
|
|
if ((ob->type == OB_EMPTY) && (ob->empty_drawtype == OB_EMPTY_IMAGE) &&
|
|
|
|
|
!BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d)) {
|
|
|
|
|
*r_only_center = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-07 12:37:47 +11:00
|
|
|
return false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-15 16:57:56 +10:00
|
|
|
static void view3d_object_calc_minmax(Depsgraph *depsgraph,
|
|
|
|
|
Scene *scene,
|
|
|
|
|
Object *ob_eval,
|
|
|
|
|
const bool only_center,
|
|
|
|
|
float min[3],
|
|
|
|
|
float max[3])
|
|
|
|
|
{
|
|
|
|
|
/* Account for duplis. */
|
|
|
|
|
if (BKE_object_minmax_dupli(depsgraph, scene, ob_eval, min, max, false) == 0) {
|
|
|
|
|
/* Use if duplis aren't found. */
|
|
|
|
|
if (only_center) {
|
|
|
|
|
minmax_v3v3_v3(min, max, ob_eval->obmat[3]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BKE_object_minmax(ob_eval, min, max, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
static void view3d_from_minmax(bContext *C,
|
|
|
|
|
View3D *v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region,
|
2018-01-23 19:48:49 +11:00
|
|
|
const float min[3],
|
|
|
|
|
const float max[3],
|
|
|
|
|
bool ok_dist,
|
|
|
|
|
const int smooth_viewtx)
|
2012-10-10 12:22:45 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2012-10-10 12:22:45 +00:00
|
|
|
float afm[3];
|
|
|
|
|
float size;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, v3d, region);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 12:22:45 +00:00
|
|
|
/* SMOOTHVIEW */
|
|
|
|
|
float new_ofs[3];
|
|
|
|
|
float new_dist;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 12:22:45 +00:00
|
|
|
sub_v3_v3v3(afm, max, min);
|
2012-12-21 05:07:26 +00:00
|
|
|
size = max_fff(afm[0], afm[1], afm[2]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 12:22:45 +00:00
|
|
|
if (ok_dist) {
|
2015-03-21 15:11:30 +11:00
|
|
|
char persp;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 12:22:45 +00:00
|
|
|
if (rv3d->is_persp) {
|
2012-11-30 04:40:32 +00:00
|
|
|
if (rv3d->persp == RV3D_CAMOB && ED_view3d_camera_lock_check(v3d, rv3d)) {
|
2015-03-21 15:11:30 +11:00
|
|
|
persp = RV3D_CAMOB;
|
2012-11-30 04:40:32 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2015-03-21 15:11:30 +11:00
|
|
|
persp = RV3D_PERSP;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-11-30 04:40:32 +00:00
|
|
|
}
|
2012-10-10 12:22:45 +00:00
|
|
|
else { /* ortho */
|
|
|
|
|
if (size < 0.0001f) {
|
|
|
|
|
/* bounding box was a single point so do not zoom */
|
2013-03-20 23:14:18 +00:00
|
|
|
ok_dist = false;
|
2012-10-10 12:22:45 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* adjust zoom so it looks nicer */
|
2015-03-21 15:11:30 +11:00
|
|
|
persp = RV3D_ORTHO;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-03-21 15:11:30 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-03-21 15:11:30 +11:00
|
|
|
if (ok_dist) {
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2018-05-25 11:05:51 +02:00
|
|
|
new_dist = ED_view3d_radius_to_dist(
|
2020-03-06 16:56:42 +01:00
|
|
|
v3d, region, depsgraph, persp, true, (size / 2) * VIEW3D_MARGIN);
|
2015-03-21 15:11:30 +11:00
|
|
|
if (rv3d->is_persp) {
|
|
|
|
|
/* don't zoom closer than the near clipping plane */
|
2019-02-16 12:21:44 +11:00
|
|
|
new_dist = max_ff(new_dist, v3d->clip_start * 1.5f);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-10-10 12:22:45 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-30 14:22:49 +00:00
|
|
|
mid_v3_v3v3(new_ofs, min, max);
|
|
|
|
|
negate_v3(new_ofs);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 12:22:45 +00:00
|
|
|
if (rv3d->persp == RV3D_CAMOB && !ED_view3d_camera_lock_check(v3d, rv3d)) {
|
|
|
|
|
rv3d->persp = RV3D_PERSP;
|
2015-12-23 02:47:34 +11:00
|
|
|
ED_view3d_smooth_view(C,
|
|
|
|
|
v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2015-12-23 02:47:34 +11:00
|
|
|
smooth_viewtx,
|
2015-12-29 01:08:13 +11:00
|
|
|
&(const V3D_SmoothParams){
|
2015-12-26 15:32:37 +11:00
|
|
|
.camera_old = v3d->camera,
|
|
|
|
|
.ofs = new_ofs,
|
2019-01-07 00:58:10 +11:00
|
|
|
.dist = ok_dist ? &new_dist : NULL,
|
|
|
|
|
});
|
2012-10-10 12:22:45 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2015-12-23 02:47:34 +11:00
|
|
|
ED_view3d_smooth_view(C,
|
|
|
|
|
v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2015-12-23 02:47:34 +11:00
|
|
|
smooth_viewtx,
|
2019-01-07 00:58:10 +11:00
|
|
|
&(const V3D_SmoothParams){
|
|
|
|
|
.ofs = new_ofs,
|
|
|
|
|
.dist = ok_dist ? &new_dist : NULL,
|
|
|
|
|
});
|
2012-10-10 12:22:45 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 12:22:45 +00:00
|
|
|
/* smooth view does viewlock RV3D_BOXVIEW copy */
|
|
|
|
|
}
|
2011-04-22 15:34:07 +00:00
|
|
|
|
2018-01-29 14:59:56 +11:00
|
|
|
/**
|
|
|
|
|
* Same as #view3d_from_minmax but for all regions (except cameras).
|
|
|
|
|
*/
|
2018-01-23 19:48:49 +11:00
|
|
|
static void view3d_from_minmax_multi(bContext *C,
|
|
|
|
|
View3D *v3d,
|
|
|
|
|
const float min[3],
|
|
|
|
|
const float max[3],
|
|
|
|
|
const bool ok_dist,
|
|
|
|
|
const int smooth_viewtx)
|
2012-10-10 12:22:45 +00:00
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2020-04-03 13:25:03 +02:00
|
|
|
for (region = area->regionbase.first; region; region = region->next) {
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region->regiontype == RGN_TYPE_WINDOW) {
|
|
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2012-10-10 12:22:45 +00:00
|
|
|
/* when using all regions, don't jump out of camera view,
|
|
|
|
|
* but _do_ allow locked cameras to be moved */
|
|
|
|
|
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
|
2020-03-06 16:56:42 +01:00
|
|
|
view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx);
|
2012-10-10 12:22:45 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-22 15:34:07 +00:00
|
|
|
|
2018-01-29 14:59:56 +11:00
|
|
|
static int view3d_all_exec(bContext *C, wmOperator *op)
|
2008-12-20 11:33:16 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2019-03-07 11:39:16 +11:00
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
2012-03-25 23:54:33 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2020-09-15 16:57:56 +10:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2018-05-20 19:10:16 +02:00
|
|
|
ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
|
|
|
|
|
Base *base_eval;
|
2013-03-22 04:40:45 +00:00
|
|
|
const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions");
|
2020-03-06 16:56:42 +01:00
|
|
|
const bool skip_camera = (ED_view3d_camera_lock_check(v3d, region->regiondata) ||
|
2013-03-22 04:40:45 +00:00
|
|
|
/* any one of the regions may be locked */
|
|
|
|
|
(use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA));
|
|
|
|
|
const bool center = RNA_boolean_get(op->ptr, "center");
|
2013-09-16 04:04:44 +00:00
|
|
|
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 12:22:45 +00:00
|
|
|
float min[3], max[3];
|
2013-11-26 06:39:14 +11:00
|
|
|
bool changed = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-22 16:52:06 +00:00
|
|
|
if (center) {
|
2009-08-20 21:09:48 +00:00
|
|
|
/* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
|
2018-11-26 13:49:17 +11:00
|
|
|
View3DCursor *cursor = &scene->cursor;
|
2010-10-05 13:15:58 +00:00
|
|
|
zero_v3(min);
|
|
|
|
|
zero_v3(max);
|
2018-05-08 14:18:09 +02:00
|
|
|
zero_v3(cursor->location);
|
2019-03-07 12:58:11 +11:00
|
|
|
float mat3[3][3];
|
|
|
|
|
unit_m3(mat3);
|
|
|
|
|
BKE_scene_cursor_mat3_to_rot(cursor, mat3, false);
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
INIT_MINMAX(min, max);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-20 19:10:16 +02:00
|
|
|
for (base_eval = view_layer_eval->object_bases.first; base_eval; base_eval = base_eval->next) {
|
2018-11-23 14:41:38 -02:00
|
|
|
if (BASE_VISIBLE(v3d, base_eval)) {
|
2019-03-07 12:37:47 +11:00
|
|
|
bool only_center = false;
|
2018-05-20 19:10:16 +02:00
|
|
|
Object *ob = DEG_get_original_object(base_eval->object);
|
2019-03-07 12:37:47 +11:00
|
|
|
if (view3d_object_skip_minmax(v3d, rv3d, ob, skip_camera, &only_center)) {
|
2011-05-14 17:50:33 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-15 16:57:56 +10:00
|
|
|
view3d_object_calc_minmax(depsgraph, scene, base_eval->object, only_center, min, max);
|
2019-03-07 12:31:36 +11:00
|
|
|
changed = true;
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-06 15:52:12 +11:00
|
|
|
if (center) {
|
2020-07-16 13:27:50 +10:00
|
|
|
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
|
|
|
|
|
WM_msg_publish_rna_prop(mbus, &scene->id, &scene->cursor, View3DCursor, location);
|
|
|
|
|
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
|
2018-12-06 15:52:12 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-26 06:39:14 +11:00
|
|
|
if (!changed) {
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(region);
|
2010-06-22 15:46:15 +00:00
|
|
|
/* TODO - should this be cancel?
|
|
|
|
|
* I think no, because we always move the cursor, with or without
|
|
|
|
|
* object, but in this case there is no change in the scene,
|
|
|
|
|
* only the cursor so I choice a ED_region_tag like
|
2012-08-12 01:07:31 +00:00
|
|
|
* view3d_smooth_view do for the center_cursor.
|
2020-09-30 20:09:02 +10:00
|
|
|
* See bug T22640.
|
2010-06-22 15:46:15 +00:00
|
|
|
*/
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-07 20:16:32 +11:00
|
|
|
if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
|
|
|
|
|
/* This is an approximation, see function documentation for details. */
|
|
|
|
|
ED_view3d_clipping_clamp_minmax(rv3d, min, max);
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-10 12:22:45 +00:00
|
|
|
if (use_all_regions) {
|
2013-09-16 04:04:44 +00:00
|
|
|
view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx);
|
2012-10-10 12:22:45 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2020-03-06 16:56:42 +01:00
|
|
|
view3d_from_minmax(C, v3d, region, min, max, true, smooth_viewtx);
|
2012-10-10 12:22:45 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-20 11:33:16 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-09 08:39:58 +00:00
|
|
|
void VIEW3D_OT_view_all(wmOperatorType *ot)
|
2008-12-20 11:33:16 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2020-05-12 15:44:59 +02:00
|
|
|
ot->name = "Frame All";
|
2010-02-10 21:15:44 +00:00
|
|
|
ot->description = "View all objects in scene";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_view_all";
|
2008-12-20 11:33:16 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = view3d_all_exec;
|
|
|
|
|
ot->poll = ED_operator_region_view3d_active;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2018-01-28 18:22:54 +11:00
|
|
|
/* properties */
|
|
|
|
|
view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS);
|
2009-01-16 23:53:11 +00:00
|
|
|
RNA_def_boolean(ot->srna, "center", 0, "Center", "");
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2020-03-04 21:29:23 +11:00
|
|
|
/** \name Frame Selected Operator
|
2018-01-23 19:48:49 +11:00
|
|
|
*
|
|
|
|
|
* Move & Zoom the view to fit selected contents.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2012-01-19 16:04:44 +00:00
|
|
|
/* like a localview without local!, was centerview() in 2.4x */
|
2012-10-10 11:36:24 +00:00
|
|
|
static int viewselected_exec(bContext *C, wmOperator *op)
|
2008-12-26 10:31:44 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2019-03-07 12:37:47 +11:00
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
2012-03-25 23:54:33 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2018-04-24 14:26:09 +02:00
|
|
|
ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
|
2018-05-24 08:55:54 +02:00
|
|
|
Object *ob_eval = OBACT(view_layer_eval);
|
2012-03-25 23:54:33 +00:00
|
|
|
Object *obedit = CTX_data_edit_object(C);
|
2019-07-29 15:17:24 +10:00
|
|
|
const bGPdata *gpd_eval = ob_eval && (ob_eval->type == OB_GPENCIL) ? ob_eval->data : NULL;
|
|
|
|
|
const bool is_gp_edit = gpd_eval ? GPENCIL_ANY_MODE(gpd_eval) : false;
|
2020-03-06 16:56:42 +01:00
|
|
|
const bool is_face_map = ((is_gp_edit == false) && region->gizmo_map &&
|
|
|
|
|
WM_gizmomap_is_any_selected(region->gizmo_map));
|
2012-10-10 10:05:56 +00:00
|
|
|
float min[3], max[3];
|
2013-03-20 23:14:18 +00:00
|
|
|
bool ok = false, ok_dist = true;
|
2013-03-22 04:40:45 +00:00
|
|
|
const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions");
|
2020-03-06 16:56:42 +01:00
|
|
|
const bool skip_camera = (ED_view3d_camera_lock_check(v3d, region->regiondata) ||
|
2013-03-22 04:40:45 +00:00
|
|
|
/* any one of the regions may be locked */
|
|
|
|
|
(use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA));
|
2013-09-16 04:04:44 +00:00
|
|
|
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-20 11:33:16 +00:00
|
|
|
INIT_MINMAX(min, max);
|
2018-10-09 16:55:13 +02:00
|
|
|
if (is_face_map) {
|
2018-04-24 14:26:09 +02:00
|
|
|
ob_eval = NULL;
|
2016-05-10 04:37:00 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-04-24 14:26:09 +02:00
|
|
|
if (ob_eval && (ob_eval->mode & OB_MODE_WEIGHT_PAINT)) {
|
2018-04-05 18:20:27 +02:00
|
|
|
/* hard-coded exception, we look for the one selected armature */
|
2019-01-15 23:24:20 +11:00
|
|
|
/* this is weak code this way, we should make a generic
|
|
|
|
|
* active/selection callback interface once... */
|
2018-04-24 14:26:09 +02:00
|
|
|
Base *base_eval;
|
|
|
|
|
for (base_eval = view_layer_eval->object_bases.first; base_eval; base_eval = base_eval->next) {
|
2019-01-08 18:19:12 +01:00
|
|
|
if (BASE_SELECTED_EDITABLE(v3d, base_eval)) {
|
2019-03-26 21:16:47 +11:00
|
|
|
if (base_eval->object->type == OB_ARMATURE) {
|
|
|
|
|
if (base_eval->object->mode & OB_MODE_POSE) {
|
2018-04-05 18:20:27 +02:00
|
|
|
break;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
}
|
2018-04-05 18:20:27 +02:00
|
|
|
}
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
2019-03-26 21:16:47 +11:00
|
|
|
if (base_eval) {
|
2018-04-24 14:26:09 +02:00
|
|
|
ob_eval = base_eval->object;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-10 04:37:00 +10:00
|
|
|
if (is_gp_edit) {
|
|
|
|
|
CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
|
|
|
|
|
/* we're only interested in selected points here... */
|
|
|
|
|
if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) {
|
2018-07-31 10:22:19 +02:00
|
|
|
ok |= BKE_gpencil_stroke_minmax(gps, true, min, max);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-05-10 04:37:00 +10:00
|
|
|
}
|
|
|
|
|
CTX_DATA_END;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-09 16:55:13 +02:00
|
|
|
if ((ob_eval) && (ok)) {
|
2018-12-17 15:01:50 +01:00
|
|
|
mul_m4_v3(ob_eval->obmat, min);
|
|
|
|
|
mul_m4_v3(ob_eval->obmat, max);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-10-09 16:55:13 +02:00
|
|
|
}
|
2017-07-24 15:28:14 +10:00
|
|
|
else if (is_face_map) {
|
2020-03-06 16:56:42 +01:00
|
|
|
ok = WM_gizmomap_minmax(region->gizmo_map, true, true, min, max);
|
2017-07-24 15:28:14 +10:00
|
|
|
}
|
2016-05-10 04:37:00 +10:00
|
|
|
else if (obedit) {
|
2018-04-17 08:30:29 +02:00
|
|
|
/* only selected */
|
2018-12-01 19:43:10 +03:00
|
|
|
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, obedit->type, obedit->mode, ob_eval_iter) {
|
2018-04-24 14:26:09 +02:00
|
|
|
ok |= ED_view3d_minmax_verts(ob_eval_iter, min, max);
|
2018-04-17 08:30:29 +02:00
|
|
|
}
|
|
|
|
|
FOREACH_OBJECT_IN_MODE_END;
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
2018-04-24 14:26:09 +02:00
|
|
|
else if (ob_eval && (ob_eval->mode & OB_MODE_POSE)) {
|
2018-12-01 19:43:10 +03:00
|
|
|
FOREACH_OBJECT_IN_MODE_BEGIN (
|
|
|
|
|
view_layer_eval, v3d, ob_eval->type, ob_eval->mode, ob_eval_iter) {
|
2018-05-24 08:55:54 +02:00
|
|
|
ok |= BKE_pose_minmax(ob_eval_iter, min, max, true, true);
|
2018-04-17 08:30:29 +02:00
|
|
|
}
|
|
|
|
|
FOREACH_OBJECT_IN_MODE_END;
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
2018-04-24 14:26:09 +02:00
|
|
|
else if (BKE_paint_select_face_test(ob_eval)) {
|
|
|
|
|
ok = paintface_minmax(ob_eval, min, max);
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
2018-04-24 14:26:09 +02:00
|
|
|
else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) {
|
2019-09-26 17:24:29 +02:00
|
|
|
ok = PE_minmax(depsgraph, scene, CTX_data_view_layer(C), min, max);
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
2018-04-24 14:26:09 +02:00
|
|
|
else if (ob_eval && (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT |
|
|
|
|
|
OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
|
|
|
|
|
BKE_paint_stroke_get_average(scene, ob_eval, min);
|
2014-12-29 11:01:10 +01:00
|
|
|
copy_v3_v3(max, min);
|
|
|
|
|
ok = true;
|
2012-05-03 03:51:30 +00:00
|
|
|
ok_dist = 0; /* don't zoom */
|
|
|
|
|
}
|
2008-12-20 11:33:16 +00:00
|
|
|
else {
|
2018-04-24 14:26:09 +02:00
|
|
|
Base *base_eval;
|
|
|
|
|
for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) {
|
2019-01-08 18:19:12 +01:00
|
|
|
if (BASE_SELECTED(v3d, base_eval)) {
|
2019-03-07 12:37:47 +11:00
|
|
|
bool only_center = false;
|
2019-03-07 12:22:56 +11:00
|
|
|
Object *ob = DEG_get_original_object(base_eval->object);
|
2019-03-07 12:37:47 +11:00
|
|
|
if (view3d_object_skip_minmax(v3d, rv3d, ob, skip_camera, &only_center)) {
|
2011-05-14 17:50:33 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-15 16:57:56 +10:00
|
|
|
view3d_object_calc_minmax(depsgraph, scene, base_eval->object, only_center, min, max);
|
2012-03-25 23:54:33 +00:00
|
|
|
ok = 1;
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 10:05:56 +00:00
|
|
|
if (ok == 0) {
|
|
|
|
|
return OPERATOR_FINISHED;
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-07 20:16:32 +11:00
|
|
|
if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
|
|
|
|
|
/* This is an approximation, see function documentation for details. */
|
|
|
|
|
ED_view3d_clipping_clamp_minmax(rv3d, min, max);
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-10 11:36:24 +00:00
|
|
|
if (use_all_regions) {
|
2013-09-16 04:04:44 +00:00
|
|
|
view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx);
|
2012-10-10 11:36:24 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2020-03-06 16:56:42 +01:00
|
|
|
view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx);
|
2012-10-10 11:36:24 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-20 11:33:16 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2009-02-14 13:07:09 +00:00
|
|
|
|
2010-01-13 22:17:56 +00:00
|
|
|
void VIEW3D_OT_view_selected(wmOperatorType *ot)
|
2008-12-20 11:33:16 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2020-03-04 21:29:23 +11:00
|
|
|
ot->name = "Frame Selected";
|
2010-02-10 21:15:44 +00:00
|
|
|
ot->description = "Move the view to the selection center";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_view_selected";
|
2008-12-20 11:33:16 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = viewselected_exec;
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
ot->poll = view3d_zoom_or_dolly_poll;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2012-10-10 11:36:24 +00:00
|
|
|
|
2018-01-28 18:22:54 +11:00
|
|
|
/* properties */
|
|
|
|
|
view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS);
|
2008-12-20 11:33:16 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Lock Clear Operator
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2012-05-05 16:38:23 +00:00
|
|
|
static int view_lock_clear_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
|
{
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
|
|
|
|
|
if (v3d) {
|
2018-01-23 20:22:26 +11:00
|
|
|
ED_view3d_lock_clear(v3d);
|
2012-05-05 16:38:23 +00:00
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-05-05 16:38:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_lock_clear(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "View Lock Clear";
|
2012-05-07 15:50:57 +00:00
|
|
|
ot->description = "Clear all view locking";
|
2012-05-05 16:38:23 +00:00
|
|
|
ot->idname = "VIEW3D_OT_view_lock_clear";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec = view_lock_clear_exec;
|
|
|
|
|
ot->poll = ED_operator_region_view3d_active;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Lock to Active Operator
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2012-05-05 16:38:23 +00:00
|
|
|
static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
|
{
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
Object *obact = CTX_data_active_object(C);
|
|
|
|
|
|
|
|
|
|
if (v3d) {
|
2018-01-23 20:22:26 +11:00
|
|
|
ED_view3d_lock_clear(v3d);
|
2012-05-05 16:38:23 +00:00
|
|
|
|
2020-03-17 11:32:03 +11:00
|
|
|
v3d->ob_center = obact; /* can be NULL */
|
2012-05-05 16:38:23 +00:00
|
|
|
|
|
|
|
|
if (obact && obact->type == OB_ARMATURE) {
|
2018-04-05 18:20:27 +02:00
|
|
|
if (obact->mode & OB_MODE_POSE) {
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
|
|
|
|
Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
|
2018-05-20 18:41:03 +02:00
|
|
|
bPoseChannel *pcham_act = BKE_pose_channel_active(obact_eval);
|
2012-05-05 16:38:23 +00:00
|
|
|
if (pcham_act) {
|
2020-03-17 11:32:03 +11:00
|
|
|
BLI_strncpy(v3d->ob_center_bone, pcham_act->name, sizeof(v3d->ob_center_bone));
|
2012-05-05 16:38:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
EditBone *ebone_act = ((bArmature *)obact->data)->act_edbone;
|
|
|
|
|
if (ebone_act) {
|
2020-03-17 11:32:03 +11:00
|
|
|
BLI_strncpy(v3d->ob_center_bone, ebone_act->name, sizeof(v3d->ob_center_bone));
|
2012-05-05 16:38:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-05-05 16:38:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_lock_to_active(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "View Lock to Active";
|
|
|
|
|
ot->description = "Lock the view to the active object/bone";
|
|
|
|
|
ot->idname = "VIEW3D_OT_view_lock_to_active";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec = view_lock_to_active_exec;
|
|
|
|
|
ot->poll = ED_operator_region_view3d_active;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Center Cursor Operator
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2013-09-16 04:04:44 +00:00
|
|
|
static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
|
2009-11-22 23:11:32 +00:00
|
|
|
{
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2012-03-25 23:54:33 +00:00
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2009-11-22 23:11:32 +00:00
|
|
|
if (rv3d) {
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2013-09-16 04:04:44 +00:00
|
|
|
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
2011-04-28 07:55:29 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, v3d, region);
|
2016-05-04 03:38:20 +10:00
|
|
|
|
2010-07-03 20:47:03 +00:00
|
|
|
/* non camera center */
|
|
|
|
|
float new_ofs[3];
|
2018-11-26 13:49:17 +11:00
|
|
|
negate_v3_v3(new_ofs, scene->cursor.location);
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view(
|
|
|
|
|
C, v3d, region, smooth_viewtx, &(const V3D_SmoothParams){.ofs = new_ofs});
|
2015-12-23 02:47:34 +11:00
|
|
|
|
2010-11-07 14:57:24 +00:00
|
|
|
/* smooth view does viewlock RV3D_BOXVIEW copy */
|
2009-11-22 23:11:32 +00:00
|
|
|
}
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2009-11-22 23:11:32 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Center View to Cursor";
|
|
|
|
|
ot->description = "Center the view so that the cursor is in the middle of the view";
|
|
|
|
|
ot->idname = "VIEW3D_OT_view_center_cursor";
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2009-11-22 23:11:32 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = viewcenter_cursor_exec;
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
ot->poll = view3d_pan_poll;
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2009-11-22 23:11:32 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2009-11-22 23:11:32 +00:00
|
|
|
}
|
2008-12-20 11:33:16 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Center Pick Operator
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2013-09-16 04:04:44 +00:00
|
|
|
static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2013-03-25 01:11:16 +00:00
|
|
|
{
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2013-03-25 01:11:16 +00:00
|
|
|
|
|
|
|
|
if (rv3d) {
|
2019-07-25 16:36:22 +02:00
|
|
|
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2013-03-25 01:11:16 +00:00
|
|
|
float new_ofs[3];
|
2013-09-16 04:04:44 +00:00
|
|
|
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
2013-03-25 01:11:16 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, v3d, region);
|
2016-05-04 03:38:20 +10:00
|
|
|
|
2013-03-25 01:11:16 +00:00
|
|
|
view3d_operator_needs_opengl(C);
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_autodist(depsgraph, region, v3d, event->mval, new_ofs, false, NULL)) {
|
2013-03-26 01:43:00 +00:00
|
|
|
/* pass */
|
2013-03-25 01:11:16 +00:00
|
|
|
}
|
2013-03-26 01:43:00 +00:00
|
|
|
else {
|
|
|
|
|
/* fallback to simple pan */
|
|
|
|
|
negate_v3_v3(new_ofs, rv3d->ofs);
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_win_to_3d_int(v3d, region, new_ofs, event->mval, new_ofs);
|
2013-03-26 01:43:00 +00:00
|
|
|
}
|
|
|
|
|
negate_v3(new_ofs);
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view(
|
|
|
|
|
C, v3d, region, smooth_viewtx, &(const V3D_SmoothParams){.ofs = new_ofs});
|
2013-03-25 01:11:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_center_pick(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "Center View to Mouse";
|
2013-03-25 08:29:06 +00:00
|
|
|
ot->description = "Center the view to the Z-depth position under the mouse cursor";
|
2013-03-25 01:11:16 +00:00
|
|
|
ot->idname = "VIEW3D_OT_view_center_pick";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->invoke = viewcenter_pick_invoke;
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
ot->poll = view3d_pan_poll;
|
2013-03-25 01:11:16 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2020-06-01 11:35:16 -04:00
|
|
|
/** \name Frame Camera Bounds Operator
|
2018-01-23 19:48:49 +11:00
|
|
|
* \{ */
|
|
|
|
|
|
2019-01-15 23:24:20 +11:00
|
|
|
static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op))
|
2010-07-03 20:47:03 +00:00
|
|
|
{
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2012-03-25 23:54:33 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2011-05-15 14:07:24 +00:00
|
|
|
float xfac, yfac;
|
|
|
|
|
float size[2];
|
2010-07-03 20:47:03 +00:00
|
|
|
|
2012-01-16 06:57:37 +00:00
|
|
|
View3D *v3d;
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2012-01-16 06:57:37 +00:00
|
|
|
RegionView3D *rv3d;
|
|
|
|
|
|
|
|
|
|
/* no NULL check is needed, poll checks */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_context_user_region(C, &v3d, ®ion);
|
|
|
|
|
rv3d = region->regiondata;
|
2012-01-16 06:57:37 +00:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
rv3d->camdx = rv3d->camdy = 0.0f;
|
2010-07-03 20:47:03 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_calc_camera_border_size(scene, depsgraph, region, v3d, rv3d, size);
|
2011-05-15 14:07:24 +00:00
|
|
|
|
|
|
|
|
/* 4px is just a little room from the edge of the area */
|
2020-03-06 16:56:42 +01:00
|
|
|
xfac = (float)region->winx / (float)(size[0] + 4);
|
|
|
|
|
yfac = (float)region->winy / (float)(size[1] + 4);
|
2011-05-15 14:07:24 +00:00
|
|
|
|
2012-10-23 13:28:22 +00:00
|
|
|
rv3d->camzoom = BKE_screen_view3d_zoom_from_fac(min_ff(xfac, yfac));
|
2011-05-20 04:14:29 +00:00
|
|
|
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
|
2011-05-15 14:07:24 +00:00
|
|
|
|
2014-03-01 21:47:46 +11:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
|
2010-07-03 20:47:03 +00:00
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_center_camera(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2020-06-01 11:35:16 -04:00
|
|
|
ot->name = "Frame Camera Bounds";
|
|
|
|
|
ot->description = "Center the camera view, resizing the view to fit its bounds";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_view_center_camera";
|
2010-07-03 20:47:03 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = view3d_center_camera_exec;
|
|
|
|
|
ot->poll = view3d_camera_user_poll;
|
2010-07-03 20:47:03 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2010-07-03 20:47:03 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Lock Center Operator
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2019-01-15 23:24:20 +11:00
|
|
|
static int view3d_center_lock_exec(bContext *C, wmOperator *UNUSED(op))
|
2013-07-19 10:54:02 +00:00
|
|
|
{
|
|
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
|
|
|
|
|
|
|
|
|
zero_v2(rv3d->ofs_lock);
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_center_lock(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "View Lock Center";
|
|
|
|
|
ot->description = "Center the view lock offset";
|
|
|
|
|
ot->idname = "VIEW3D_OT_view_center_lock";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec = view3d_center_lock_exec;
|
|
|
|
|
ot->poll = view3d_lock_poll;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Set Render Border Operator
|
|
|
|
|
* \{ */
|
2008-12-27 01:29:56 +00:00
|
|
|
|
|
|
|
|
static int render_border_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2012-03-25 23:54:33 +00:00
|
|
|
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-27 01:29:56 +00:00
|
|
|
rcti rect;
|
2012-10-16 11:57:46 +00:00
|
|
|
rctf vb, border;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
/* get box select values using rna */
|
2012-08-08 20:38:55 +00:00
|
|
|
WM_operator_properties_border_to_rcti(op, &rect);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-27 01:29:56 +00:00
|
|
|
/* calculate range */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-16 11:57:46 +00:00
|
|
|
if (rv3d->persp == RV3D_CAMOB) {
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &vb, false);
|
2012-10-16 11:57:46 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
vb.xmin = 0;
|
|
|
|
|
vb.ymin = 0;
|
2020-03-06 16:56:42 +01:00
|
|
|
vb.xmax = region->winx;
|
|
|
|
|
vb.ymax = region->winy;
|
2012-10-16 11:57:46 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-16 11:57:46 +00:00
|
|
|
border.xmin = ((float)rect.xmin - vb.xmin) / BLI_rctf_size_x(&vb);
|
|
|
|
|
border.ymin = ((float)rect.ymin - vb.ymin) / BLI_rctf_size_y(&vb);
|
|
|
|
|
border.xmax = ((float)rect.xmax - vb.xmin) / BLI_rctf_size_x(&vb);
|
|
|
|
|
border.ymax = ((float)rect.ymax - vb.ymin) / BLI_rctf_size_y(&vb);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-09 02:45:48 +00:00
|
|
|
/* actually set border */
|
2012-10-16 11:57:46 +00:00
|
|
|
CLAMP(border.xmin, 0.0f, 1.0f);
|
|
|
|
|
CLAMP(border.ymin, 0.0f, 1.0f);
|
|
|
|
|
CLAMP(border.xmax, 0.0f, 1.0f);
|
|
|
|
|
CLAMP(border.ymax, 0.0f, 1.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-16 11:57:46 +00:00
|
|
|
if (rv3d->persp == RV3D_CAMOB) {
|
|
|
|
|
scene->r.border = border;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-16 11:57:46 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
v3d->render_border = border;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-16 11:57:46 +00:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-07-05 01:40:20 +02:00
|
|
|
/* drawing a border outside the camera view switches off border rendering */
|
2016-07-08 00:48:03 +10:00
|
|
|
if ((border.xmin == border.xmax || border.ymin == border.ymax)) {
|
2019-03-26 21:16:47 +11:00
|
|
|
if (rv3d->persp == RV3D_CAMOB) {
|
2012-10-16 11:57:46 +00:00
|
|
|
scene->r.mode &= ~R_BORDER;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2012-10-16 11:57:46 +00:00
|
|
|
v3d->flag2 &= ~V3D_RENDER_BORDER;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2012-02-22 16:52:06 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2019-03-26 21:16:47 +11:00
|
|
|
if (rv3d->persp == RV3D_CAMOB) {
|
2012-10-16 11:57:46 +00:00
|
|
|
scene->r.mode |= R_BORDER;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2012-10-16 11:57:46 +00:00
|
|
|
v3d->flag2 |= V3D_RENDER_BORDER;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2008-12-27 01:29:56 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-15 18:02:29 +02:00
|
|
|
if (rv3d->persp == RV3D_CAMOB) {
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
|
2018-05-15 18:02:29 +02:00
|
|
|
}
|
2008-12-27 01:29:56 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_render_border(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2019-03-06 16:43:37 +01:00
|
|
|
ot->name = "Set Render Region";
|
2012-10-21 14:02:30 +00:00
|
|
|
ot->description = "Set the boundaries of the border render and enable border render";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_render_border";
|
2008-12-27 01:29:56 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2018-10-05 10:27:04 +10:00
|
|
|
ot->invoke = WM_gesture_box_invoke;
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = render_border_exec;
|
2018-10-05 10:27:04 +10:00
|
|
|
ot->modal = WM_gesture_box_modal;
|
|
|
|
|
ot->cancel = WM_gesture_box_cancel;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2012-10-16 11:57:46 +00:00
|
|
|
ot->poll = ED_operator_view3d_active;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2012-03-25 23:54:33 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2018-01-28 18:22:54 +11:00
|
|
|
/* properties */
|
2012-08-08 20:38:55 +00:00
|
|
|
WM_operator_properties_border(ot);
|
2009-01-16 00:58:33 +00:00
|
|
|
}
|
2012-10-16 11:57:46 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Clear Render Border Operator
|
|
|
|
|
* \{ */
|
2012-10-16 11:57:46 +00:00
|
|
|
|
|
|
|
|
static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
|
{
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
|
|
|
|
|
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
rctf *border = NULL;
|
|
|
|
|
|
|
|
|
|
if (rv3d->persp == RV3D_CAMOB) {
|
|
|
|
|
scene->r.mode &= ~R_BORDER;
|
|
|
|
|
border = &scene->r.border;
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
v3d->flag2 &= ~V3D_RENDER_BORDER;
|
|
|
|
|
border = &v3d->render_border;
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
border->xmin = 0.0f;
|
|
|
|
|
border->ymin = 0.0f;
|
|
|
|
|
border->xmax = 1.0f;
|
|
|
|
|
border->ymax = 1.0f;
|
|
|
|
|
|
2018-05-15 18:19:08 +02:00
|
|
|
if (rv3d->persp == RV3D_CAMOB) {
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
|
2018-05-15 18:19:08 +02:00
|
|
|
}
|
2012-10-16 11:57:46 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_clear_render_border(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2019-03-06 16:43:37 +01:00
|
|
|
ot->name = "Clear Render Region";
|
2012-10-21 14:02:30 +00:00
|
|
|
ot->description = "Clear the boundaries of the border render and disable border render";
|
2012-10-16 11:57:46 +00:00
|
|
|
ot->idname = "VIEW3D_OT_clear_render_border";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec = clear_render_border_exec;
|
|
|
|
|
ot->poll = ED_operator_view3d_active;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Border Zoom Operator
|
|
|
|
|
* \{ */
|
2009-01-16 00:58:33 +00:00
|
|
|
|
2009-07-24 23:07:18 +00:00
|
|
|
static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
|
2009-01-16 00:58:33 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2012-03-25 23:54:33 +00:00
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
2013-09-16 04:04:44 +00:00
|
|
|
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-16 00:58:33 +00:00
|
|
|
/* Zooms in on a border drawn by the user */
|
|
|
|
|
rcti rect;
|
2012-08-08 19:54:31 +00:00
|
|
|
float dvec[3], vb[2], xscale, yscale;
|
2014-08-25 14:11:50 +10:00
|
|
|
float dist_range[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-16 00:58:33 +00:00
|
|
|
/* SMOOTHVIEW */
|
|
|
|
|
float new_dist;
|
|
|
|
|
float new_ofs[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-16 00:58:33 +00:00
|
|
|
/* ZBuffer depth vars */
|
2012-03-25 23:54:33 +00:00
|
|
|
float depth_close = FLT_MAX;
|
2018-01-29 17:32:20 +11:00
|
|
|
float cent[2], p[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-16 00:58:33 +00:00
|
|
|
/* note; otherwise opengl won't work */
|
|
|
|
|
view3d_operator_needs_opengl(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
/* get box select values using rna */
|
2012-08-08 20:38:55 +00:00
|
|
|
WM_operator_properties_border_to_rcti(op, &rect);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-08-08 19:54:31 +00:00
|
|
|
/* check if zooming in/out view */
|
2017-10-16 21:58:51 +11:00
|
|
|
const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-08-25 14:11:50 +10:00
|
|
|
ED_view3d_dist_range_get(v3d, dist_range);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-16 00:58:33 +00:00
|
|
|
/* Get Z Depths, needed for perspective, nice for ortho */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_draw_depth(CTX_data_ensure_evaluated_depsgraph(C), region, v3d, true);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-10-21 07:38:09 +00:00
|
|
|
{
|
|
|
|
|
/* avoid allocating the whole depth buffer */
|
2012-03-25 23:54:33 +00:00
|
|
|
ViewDepths depth_temp = {0};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-10-21 07:38:09 +00:00
|
|
|
/* avoid view3d_update_depths() for speed. */
|
2020-03-06 16:56:42 +01:00
|
|
|
view3d_update_depths_rect(region, &depth_temp, &rect);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-10-21 07:38:09 +00:00
|
|
|
/* find the closest Z pixel */
|
2012-03-25 23:54:33 +00:00
|
|
|
depth_close = view3d_depth_near(&depth_temp);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-10-06 10:19:47 +02:00
|
|
|
MEM_SAFE_FREE(depth_temp.depths);
|
2009-01-16 00:58:33 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-27 14:08:12 +11:00
|
|
|
/* Resize border to the same ratio as the window. */
|
|
|
|
|
{
|
|
|
|
|
const float region_aspect = (float)region->winx / (float)region->winy;
|
|
|
|
|
if (((float)BLI_rcti_size_x(&rect) / (float)BLI_rcti_size_y(&rect)) < region_aspect) {
|
|
|
|
|
BLI_rcti_resize_x(&rect, (int)(BLI_rcti_size_y(&rect) * region_aspect));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_rcti_resize_y(&rect, (int)(BLI_rcti_size_x(&rect) / region_aspect));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-29 17:32:20 +11:00
|
|
|
cent[0] = (((float)rect.xmin) + ((float)rect.xmax)) / 2;
|
|
|
|
|
cent[1] = (((float)rect.ymin) + ((float)rect.ymax)) / 2;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-05-20 11:15:44 +00:00
|
|
|
if (rv3d->is_persp) {
|
2017-02-25 21:58:23 +01:00
|
|
|
float p_corner[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-16 00:58:33 +00:00
|
|
|
/* no depths to use, we cant do anything! */
|
2012-03-25 23:54:33 +00:00
|
|
|
if (depth_close == FLT_MAX) {
|
2012-10-16 07:53:10 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Depth too large");
|
2009-01-16 00:58:33 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2009-01-21 02:24:12 +00:00
|
|
|
}
|
2009-01-16 00:58:33 +00:00
|
|
|
/* convert border to 3d coordinates */
|
2020-03-06 16:56:42 +01:00
|
|
|
if ((!ED_view3d_unproject(region, cent[0], cent[1], depth_close, p)) ||
|
|
|
|
|
(!ED_view3d_unproject(region, rect.xmin, rect.ymin, depth_close, p_corner))) {
|
2009-01-16 00:58:33 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2012-01-19 16:04:44 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-25 21:58:23 +01:00
|
|
|
sub_v3_v3v3(dvec, p, p_corner);
|
|
|
|
|
negate_v3_v3(new_ofs, p);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-08-08 19:54:31 +00:00
|
|
|
new_dist = len_v3(dvec);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-27 14:08:12 +11:00
|
|
|
/* Account for the lens, without this a narrow lens zooms in too close. */
|
|
|
|
|
new_dist *= (v3d->lens / DEFAULT_SENSOR_WIDTH);
|
|
|
|
|
|
2014-08-25 14:11:50 +10:00
|
|
|
/* ignore dist_range min */
|
2019-02-16 12:21:44 +11:00
|
|
|
dist_range[0] = v3d->clip_start * 1.5f;
|
2012-02-22 16:52:06 +00:00
|
|
|
}
|
2020-02-17 13:00:01 +01:00
|
|
|
else { /* orthographic */
|
2016-06-19 06:25:54 +10:00
|
|
|
/* find the current window width and height */
|
2020-03-06 16:56:42 +01:00
|
|
|
vb[0] = region->winx;
|
|
|
|
|
vb[1] = region->winy;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
new_dist = rv3d->dist;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-16 00:58:33 +00:00
|
|
|
/* convert the drawn rectangle into 3d space */
|
2020-03-06 16:56:42 +01:00
|
|
|
if (depth_close != FLT_MAX && ED_view3d_unproject(region, cent[0], cent[1], depth_close, p)) {
|
2017-02-25 21:58:23 +01:00
|
|
|
negate_v3_v3(new_ofs, p);
|
2011-05-20 13:50:41 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
float mval_f[2];
|
2013-03-09 11:40:42 +00:00
|
|
|
float zfac;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-07-31 14:25:09 +02:00
|
|
|
/* We can't use the depth, fallback to the old way that doesn't set the center depth */
|
2010-02-25 20:26:38 +00:00
|
|
|
copy_v3_v3(new_ofs, rv3d->ofs);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-09 11:40:42 +00:00
|
|
|
{
|
|
|
|
|
float tvec[3];
|
|
|
|
|
negate_v3_v3(tvec, new_ofs);
|
|
|
|
|
zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
mval_f[0] = (rect.xmin + rect.xmax - vb[0]) / 2.0f;
|
|
|
|
|
mval_f[1] = (rect.ymin + rect.ymax - vb[1]) / 2.0f;
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_win_to_delta(region, mval_f, dvec, zfac);
|
2009-01-16 00:58:33 +00:00
|
|
|
/* center the view to the center of the rectangle */
|
2010-04-23 23:57:00 +00:00
|
|
|
sub_v3_v3(new_ofs, dvec);
|
2009-01-16 00:58:33 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-16 00:58:33 +00:00
|
|
|
/* work out the ratios, so that everything selected fits when we zoom */
|
2012-09-15 11:48:20 +00:00
|
|
|
xscale = (BLI_rcti_size_x(&rect) / vb[0]);
|
|
|
|
|
yscale = (BLI_rcti_size_y(&rect) / vb[1]);
|
2012-10-23 13:28:22 +00:00
|
|
|
new_dist *= max_ff(xscale, yscale);
|
2012-08-08 19:54:31 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-16 21:58:51 +11:00
|
|
|
if (!zoom_in) {
|
2012-08-08 19:54:31 +00:00
|
|
|
sub_v3_v3v3(dvec, new_ofs, rv3d->ofs);
|
|
|
|
|
new_dist = rv3d->dist * (rv3d->dist / new_dist);
|
|
|
|
|
add_v3_v3v3(new_ofs, rv3d->ofs, dvec);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-08-08 19:54:31 +00:00
|
|
|
/* clamp after because we may have been zooming out */
|
2014-08-25 14:11:50 +10:00
|
|
|
CLAMP(new_dist, dist_range[0], dist_range[1]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-10 11:45:05 +02:00
|
|
|
/* TODO(campbell): 'is_camera_lock' not currently working well. */
|
|
|
|
|
const bool is_camera_lock = ED_view3d_camera_lock_check(v3d, rv3d);
|
|
|
|
|
if ((rv3d->persp == RV3D_CAMOB) && (is_camera_lock == false)) {
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2018-07-10 11:45:05 +02:00
|
|
|
ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, RV3D_PERSP);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-23 02:47:34 +11:00
|
|
|
ED_view3d_smooth_view(C,
|
|
|
|
|
v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2015-12-23 02:47:34 +11:00
|
|
|
smooth_viewtx,
|
2019-01-07 00:58:10 +11:00
|
|
|
&(const V3D_SmoothParams){
|
|
|
|
|
.ofs = new_ofs,
|
|
|
|
|
.dist = &new_dist,
|
|
|
|
|
});
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
2020-03-06 16:56:42 +01:00
|
|
|
view3d_boxview_sync(CTX_wm_area(C), region);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-16 00:58:33 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
|
2009-03-29 02:15:13 +00:00
|
|
|
void VIEW3D_OT_zoom_border(wmOperatorType *ot)
|
2009-01-16 00:58:33 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2012-08-10 11:43:53 +00:00
|
|
|
ot->name = "Zoom to Border";
|
2010-02-10 21:15:44 +00:00
|
|
|
ot->description = "Zoom in the view to the nearest object contained in the border";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_zoom_border";
|
2009-01-16 00:58:33 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2018-10-05 10:27:04 +10:00
|
|
|
ot->invoke = WM_gesture_box_invoke;
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = view3d_zoom_border_exec;
|
2018-10-05 10:27:04 +10:00
|
|
|
ot->modal = WM_gesture_box_modal;
|
|
|
|
|
ot->cancel = WM_gesture_box_cancel;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
ot->poll = view3d_zoom_or_dolly_poll;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2018-01-28 18:22:54 +11:00
|
|
|
/* properties */
|
2018-10-05 10:27:04 +10:00
|
|
|
WM_operator_properties_gesture_box_zoom(ot);
|
2008-12-27 01:29:56 +00:00
|
|
|
}
|
2011-02-23 06:48:47 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Set Camera Zoom 1:1 Operator
|
|
|
|
|
*
|
|
|
|
|
* Sets the view to 1:1 camera/render-pixel.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2018-04-06 12:07:27 +02:00
|
|
|
static void view3d_set_1_to_1_viewborder(Scene *scene,
|
|
|
|
|
Depsgraph *depsgraph,
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region,
|
2018-04-06 12:07:27 +02:00
|
|
|
View3D *v3d)
|
2011-02-23 06:48:47 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2011-02-23 06:48:47 +00:00
|
|
|
float size[2];
|
2012-03-25 23:54:33 +00:00
|
|
|
int im_width = (scene->r.size * scene->r.xsch) / 100;
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_calc_camera_border_size(scene, depsgraph, region, v3d, rv3d, size);
|
2011-05-20 04:14:29 +00:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
rv3d->camzoom = BKE_screen_view3d_zoom_from_fac((float)im_width / size[0]);
|
2011-05-20 04:14:29 +00:00
|
|
|
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
|
2011-02-23 06:48:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
|
{
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2012-03-25 23:54:33 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2011-02-23 06:48:47 +00:00
|
|
|
|
2012-01-16 06:57:37 +00:00
|
|
|
View3D *v3d;
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2011-02-23 06:48:47 +00:00
|
|
|
|
2012-01-16 06:57:37 +00:00
|
|
|
/* no NULL check is needed, poll checks */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_context_user_region(C, &v3d, ®ion);
|
2012-01-16 06:57:37 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
view3d_set_1_to_1_viewborder(scene, depsgraph, region, v3d);
|
2012-01-16 06:57:37 +00:00
|
|
|
|
2012-03-25 23:54:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
|
2011-02-23 06:48:47 +00:00
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Zoom Camera 1:1";
|
2011-02-23 06:48:47 +00:00
|
|
|
ot->description = "Match the camera to 1:1 to the render output";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_zoom_camera_1_to_1";
|
2011-02-23 06:48:47 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = view3d_zoom_1_to_1_camera_exec;
|
|
|
|
|
ot->poll = view3d_camera_user_poll;
|
2011-02-23 06:48:47 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2011-02-23 06:48:47 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2018-07-05 16:54:30 +02:00
|
|
|
/** \name View Axis Operator
|
2018-01-23 19:48:49 +11:00
|
|
|
* \{ */
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2017-10-18 15:07:26 +11:00
|
|
|
static const EnumPropertyItem prop_view_items[] = {
|
2020-12-24 11:07:32 -06:00
|
|
|
{RV3D_VIEW_LEFT, "LEFT", ICON_TRIA_LEFT, "Left", "View from the left"},
|
|
|
|
|
{RV3D_VIEW_RIGHT, "RIGHT", ICON_TRIA_RIGHT, "Right", "View from the right"},
|
|
|
|
|
{RV3D_VIEW_BOTTOM, "BOTTOM", ICON_TRIA_DOWN, "Bottom", "View from the bottom"},
|
|
|
|
|
{RV3D_VIEW_TOP, "TOP", ICON_TRIA_UP, "Top", "View from the top"},
|
|
|
|
|
{RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View from the front"},
|
|
|
|
|
{RV3D_VIEW_BACK, "BACK", 0, "Back", "View from the back"},
|
2019-02-03 14:01:45 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2012-03-25 23:54:33 +00:00
|
|
|
};
|
2008-12-23 09:59:02 +00:00
|
|
|
|
2009-11-06 10:38:00 +00:00
|
|
|
/* would like to make this a generic function - outside of transform */
|
|
|
|
|
|
2018-07-05 19:27:57 +02:00
|
|
|
/**
|
|
|
|
|
* \param align_to_quat: When not NULL, set the axis relative to this rotation.
|
|
|
|
|
*/
|
2018-01-23 19:48:49 +11:00
|
|
|
static void axis_set_view(bContext *C,
|
|
|
|
|
View3D *v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region,
|
2018-01-23 19:48:49 +11:00
|
|
|
const float quat_[4],
|
2020-02-09 11:50:25 +11:00
|
|
|
char view,
|
|
|
|
|
char view_axis_roll,
|
2018-07-05 19:27:57 +02:00
|
|
|
int perspo,
|
|
|
|
|
const float *align_to_quat,
|
2018-01-23 19:48:49 +11:00
|
|
|
const int smooth_viewtx)
|
2008-12-23 09:59:02 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
RegionView3D *rv3d = region->regiondata; /* no NULL check is needed, poll checks */
|
2014-02-12 13:35:06 +11:00
|
|
|
float quat[4];
|
2015-08-26 20:41:28 +10:00
|
|
|
const short orig_persp = rv3d->persp;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-12 13:35:06 +11:00
|
|
|
normalize_qt_qt(quat, quat_);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-05 19:27:57 +02:00
|
|
|
if (align_to_quat) {
|
|
|
|
|
mul_qt_qtqt(quat, quat, align_to_quat);
|
|
|
|
|
rv3d->view = view = RV3D_VIEW_USER;
|
2020-02-09 11:50:25 +11:00
|
|
|
rv3d->view_axis_roll = RV3D_VIEW_AXIS_ROLL_0;
|
2009-11-06 10:38:00 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-05 19:27:57 +02:00
|
|
|
if (align_to_quat == NULL) {
|
2012-03-10 22:00:55 +00:00
|
|
|
rv3d->view = view;
|
2020-02-09 11:50:25 +11:00
|
|
|
rv3d->view_axis_roll = view_axis_roll;
|
2009-11-06 10:38:00 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) {
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(region);
|
2009-01-20 14:23:32 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-25 12:53:40 +11:00
|
|
|
if (U.uiflag & USER_AUTOPERSP) {
|
|
|
|
|
rv3d->persp = RV3D_VIEW_IS_AXIS(view) ? RV3D_ORTHO : perspo;
|
|
|
|
|
}
|
|
|
|
|
else if (rv3d->persp == RV3D_CAMOB) {
|
|
|
|
|
rv3d->persp = perspo;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-25 12:53:40 +11:00
|
|
|
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
|
2015-08-26 20:41:28 +10:00
|
|
|
/* to camera */
|
2015-12-23 02:47:34 +11:00
|
|
|
ED_view3d_smooth_view(C,
|
|
|
|
|
v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2015-12-23 02:47:34 +11:00
|
|
|
smooth_viewtx,
|
2019-01-07 00:58:10 +11:00
|
|
|
&(const V3D_SmoothParams){
|
|
|
|
|
.camera_old = v3d->camera,
|
|
|
|
|
.ofs = rv3d->ofs,
|
|
|
|
|
.quat = quat,
|
|
|
|
|
});
|
2009-07-09 02:45:48 +00:00
|
|
|
}
|
2015-08-26 20:41:28 +10:00
|
|
|
else if (orig_persp == RV3D_CAMOB && v3d->camera) {
|
|
|
|
|
/* from camera */
|
2015-08-26 15:13:19 +10:00
|
|
|
float ofs[3], dist;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-08-26 15:13:19 +10:00
|
|
|
copy_v3_v3(ofs, rv3d->ofs);
|
|
|
|
|
dist = rv3d->dist;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-08-26 15:13:19 +10:00
|
|
|
/* so we animate _from_ the camera location */
|
2019-07-25 16:36:22 +02:00
|
|
|
Object *camera_eval = DEG_get_evaluated_object(CTX_data_ensure_evaluated_depsgraph(C),
|
|
|
|
|
v3d->camera);
|
2018-05-25 11:05:51 +02:00
|
|
|
ED_view3d_from_object(camera_eval, rv3d->ofs, NULL, &rv3d->dist, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-23 02:47:34 +11:00
|
|
|
ED_view3d_smooth_view(C,
|
|
|
|
|
v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2015-12-23 02:47:34 +11:00
|
|
|
smooth_viewtx,
|
2019-01-07 00:58:10 +11:00
|
|
|
&(const V3D_SmoothParams){
|
2020-10-29 12:33:26 +11:00
|
|
|
.camera_old = camera_eval,
|
2019-01-07 00:58:10 +11:00
|
|
|
.ofs = ofs,
|
|
|
|
|
.quat = quat,
|
|
|
|
|
.dist = &dist,
|
|
|
|
|
});
|
2008-12-23 09:59:02 +00:00
|
|
|
}
|
2015-08-26 20:41:28 +10:00
|
|
|
else {
|
2015-12-23 05:04:52 +11:00
|
|
|
/* rotate around selection */
|
|
|
|
|
const float *dyn_ofs_pt = NULL;
|
|
|
|
|
float dyn_ofs[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-23 05:04:52 +11:00
|
|
|
if (U.uiflag & USER_ORBIT_SELECTION) {
|
|
|
|
|
if (view3d_orbit_calc_center(C, dyn_ofs)) {
|
|
|
|
|
negate_v3(dyn_ofs);
|
|
|
|
|
dyn_ofs_pt = dyn_ofs;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-12-23 05:04:52 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-08-26 20:41:28 +10:00
|
|
|
/* no camera involved */
|
2015-12-23 02:47:34 +11:00
|
|
|
ED_view3d_smooth_view(C,
|
|
|
|
|
v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2015-12-23 02:47:34 +11:00
|
|
|
smooth_viewtx,
|
2019-01-07 00:58:10 +11:00
|
|
|
&(const V3D_SmoothParams){
|
|
|
|
|
.quat = quat,
|
|
|
|
|
.dyn_ofs = dyn_ofs_pt,
|
|
|
|
|
});
|
2015-08-26 20:41:28 +10:00
|
|
|
}
|
2008-12-23 09:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
2018-07-05 16:54:30 +02:00
|
|
|
static int view_axis_exec(bContext *C, wmOperator *op)
|
2008-12-23 09:59:02 +00:00
|
|
|
{
|
2012-01-14 12:24:25 +00:00
|
|
|
View3D *v3d;
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2012-01-14 12:24:25 +00:00
|
|
|
RegionView3D *rv3d;
|
|
|
|
|
static int perspo = RV3D_PERSP;
|
2018-07-05 16:59:52 +02:00
|
|
|
int viewnum;
|
2020-02-09 11:50:25 +11:00
|
|
|
int view_axis_roll = RV3D_VIEW_AXIS_ROLL_0;
|
2013-09-16 04:04:44 +00:00
|
|
|
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-01-16 06:57:37 +00:00
|
|
|
/* no NULL check is needed, poll checks */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_context_user_region(C, &v3d, ®ion);
|
|
|
|
|
rv3d = region->regiondata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, v3d, region);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-02-04 05:15:39 +00:00
|
|
|
viewnum = RNA_enum_get(op->ptr, "type");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-05 19:27:57 +02:00
|
|
|
float align_quat_buf[4];
|
|
|
|
|
float *align_quat = NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-05 19:27:57 +02:00
|
|
|
if (RNA_boolean_get(op->ptr, "align_active")) {
|
|
|
|
|
/* align to active object */
|
|
|
|
|
Object *obact = CTX_data_active_object(C);
|
|
|
|
|
if (obact != NULL) {
|
|
|
|
|
float twmat[3][3];
|
2020-09-14 15:33:36 -03:00
|
|
|
Object *obedit = CTX_data_edit_object(C);
|
2018-07-14 23:49:00 +02:00
|
|
|
/* same as transform gizmo when normal is set */
|
2020-09-14 15:33:36 -03:00
|
|
|
ED_getTransformOrientationMatrix(C, obact, obedit, V3D_AROUND_ACTIVE, twmat);
|
2018-07-05 19:27:57 +02:00
|
|
|
align_quat = align_quat_buf;
|
|
|
|
|
mat3_to_quat(align_quat, twmat);
|
|
|
|
|
invert_qt_normalized(align_quat);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-05 19:27:57 +02:00
|
|
|
if (RNA_boolean_get(op->ptr, "relative")) {
|
2020-02-09 11:50:25 +11:00
|
|
|
float quat_rotate[4];
|
|
|
|
|
float quat_test[4];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-09 11:50:25 +11:00
|
|
|
if (viewnum == RV3D_VIEW_LEFT) {
|
|
|
|
|
axis_angle_to_quat(quat_rotate, rv3d->viewinv[1], -M_PI / 2.0f);
|
2018-07-05 19:41:38 +02:00
|
|
|
}
|
2020-02-09 11:50:25 +11:00
|
|
|
else if (viewnum == RV3D_VIEW_RIGHT) {
|
|
|
|
|
axis_angle_to_quat(quat_rotate, rv3d->viewinv[1], M_PI / 2.0f);
|
2018-07-05 19:41:38 +02:00
|
|
|
}
|
|
|
|
|
else if (viewnum == RV3D_VIEW_TOP) {
|
2020-02-09 11:50:25 +11:00
|
|
|
axis_angle_to_quat(quat_rotate, rv3d->viewinv[0], -M_PI / 2.0f);
|
2018-07-05 19:27:57 +02:00
|
|
|
}
|
|
|
|
|
else if (viewnum == RV3D_VIEW_BOTTOM) {
|
2020-02-09 11:50:25 +11:00
|
|
|
axis_angle_to_quat(quat_rotate, rv3d->viewinv[0], M_PI / 2.0f);
|
2018-07-05 19:27:57 +02:00
|
|
|
}
|
|
|
|
|
else if (viewnum == RV3D_VIEW_FRONT) {
|
2020-02-09 11:50:25 +11:00
|
|
|
unit_qt(quat_rotate);
|
2018-07-05 19:27:57 +02:00
|
|
|
}
|
|
|
|
|
else if (viewnum == RV3D_VIEW_BACK) {
|
2020-02-09 11:50:25 +11:00
|
|
|
axis_angle_to_quat(quat_rotate, rv3d->viewinv[0], M_PI);
|
2018-07-05 19:27:57 +02:00
|
|
|
}
|
2018-07-05 19:41:38 +02:00
|
|
|
else {
|
|
|
|
|
BLI_assert(0);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-09 11:50:25 +11:00
|
|
|
mul_qt_qtqt(quat_test, rv3d->viewquat, quat_rotate);
|
|
|
|
|
|
|
|
|
|
float angle_best = FLT_MAX;
|
|
|
|
|
int view_best = -1;
|
|
|
|
|
int view_axis_roll_best = -1;
|
2018-07-05 19:27:57 +02:00
|
|
|
for (int i = RV3D_VIEW_FRONT; i <= RV3D_VIEW_BOTTOM; i++) {
|
2020-02-09 11:50:25 +11:00
|
|
|
for (int j = RV3D_VIEW_AXIS_ROLL_0; j <= RV3D_VIEW_AXIS_ROLL_270; j++) {
|
|
|
|
|
float quat_axis[4];
|
|
|
|
|
ED_view3d_quat_from_axis_view(i, j, quat_axis);
|
|
|
|
|
if (align_quat) {
|
|
|
|
|
mul_qt_qtqt(quat_axis, quat_axis, align_quat);
|
|
|
|
|
}
|
|
|
|
|
const float angle_test = fabsf(angle_signed_qtqt(quat_axis, quat_test));
|
|
|
|
|
if (angle_best > angle_test) {
|
|
|
|
|
angle_best = angle_test;
|
|
|
|
|
view_best = i;
|
|
|
|
|
view_axis_roll_best = j;
|
|
|
|
|
}
|
2018-07-05 19:27:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-02-09 11:50:25 +11:00
|
|
|
if (view_best == -1) {
|
|
|
|
|
view_best = RV3D_VIEW_FRONT;
|
|
|
|
|
view_axis_roll_best = RV3D_VIEW_AXIS_ROLL_0;
|
2018-07-05 19:27:57 +02:00
|
|
|
}
|
2020-02-09 11:50:25 +11:00
|
|
|
|
|
|
|
|
/* Disallow non-upright views in turn-table modes,
|
|
|
|
|
* it's too difficult to navigate out of them. */
|
|
|
|
|
if ((U.flag & USER_TRACKBALL) == 0) {
|
|
|
|
|
if (!ELEM(view_best, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
|
|
|
|
|
view_axis_roll_best = RV3D_VIEW_AXIS_ROLL_0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
viewnum = view_best;
|
|
|
|
|
view_axis_roll = view_axis_roll_best;
|
2018-07-05 19:27:57 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-23 09:59:02 +00:00
|
|
|
/* Use this to test if we started out with a camera */
|
2018-07-05 16:59:52 +02:00
|
|
|
const int nextperspo = (rv3d->persp == RV3D_CAMOB) ? rv3d->lpersp : perspo;
|
|
|
|
|
float quat[4];
|
2020-02-09 11:50:25 +11:00
|
|
|
ED_view3d_quat_from_axis_view(viewnum, view_axis_roll, quat);
|
2020-03-06 16:56:42 +01:00
|
|
|
axis_set_view(
|
|
|
|
|
C, v3d, region, quat, viewnum, view_axis_roll, nextperspo, align_quat, smooth_viewtx);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-05 16:54:30 +02:00
|
|
|
perspo = rv3d->persp;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-05 16:54:30 +02:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_axis(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "View Axis";
|
|
|
|
|
ot->description = "Use a preset viewpoint";
|
|
|
|
|
ot->idname = "VIEW3D_OT_view_axis";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec = view_axis_exec;
|
|
|
|
|
ot->poll = ED_operator_rv3d_user_region_poll;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
|
|
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "Preset viewpoint to use");
|
|
|
|
|
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
|
|
|
|
|
prop = RNA_def_boolean(
|
|
|
|
|
ot->srna, "align_active", 0, "Align Active", "Align to the active object's axis");
|
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2018-07-05 19:27:57 +02:00
|
|
|
prop = RNA_def_boolean(
|
|
|
|
|
ot->srna, "relative", 0, "Relative", "Rotate relative to the current orientation");
|
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2018-07-05 16:54:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Camera Operator
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static int view_camera_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
View3D *v3d;
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2018-07-05 16:54:30 +02:00
|
|
|
RegionView3D *rv3d;
|
|
|
|
|
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
|
|
|
|
|
|
|
|
|
/* no NULL check is needed, poll checks */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_context_user_region(C, &v3d, ®ion);
|
|
|
|
|
rv3d = region->regiondata;
|
2018-07-05 16:54:30 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, v3d, region);
|
2018-07-05 16:54:30 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) == 0) {
|
2018-07-05 16:59:52 +02:00
|
|
|
/* lastview - */
|
2014-02-12 13:35:06 +11:00
|
|
|
|
2018-07-05 16:59:52 +02:00
|
|
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
2018-05-20 19:10:16 +02:00
|
|
|
|
2018-07-05 16:59:52 +02:00
|
|
|
if (rv3d->persp != RV3D_CAMOB) {
|
|
|
|
|
Object *ob = OBACT(view_layer);
|
2014-02-12 13:35:06 +11:00
|
|
|
|
2018-07-05 16:59:52 +02:00
|
|
|
if (!rv3d->smooth_timer) {
|
|
|
|
|
/* store settings of current view before allowing overwriting with camera view
|
|
|
|
|
* only if we're not currently in a view transition */
|
2014-03-25 14:21:50 +11:00
|
|
|
|
2018-07-05 16:59:52 +02:00
|
|
|
ED_view3d_lastview_store(rv3d);
|
|
|
|
|
}
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#if 0
|
2018-07-05 16:59:52 +02:00
|
|
|
if (G.qual == LR_ALTKEY) {
|
|
|
|
|
if (oldcamera && is_an_active_object(oldcamera)) {
|
|
|
|
|
v3d->camera = oldcamera;
|
2014-02-12 13:35:06 +11:00
|
|
|
}
|
2018-07-05 16:59:52 +02:00
|
|
|
handle_view3d_lock();
|
|
|
|
|
}
|
2013-12-22 14:11:10 +11:00
|
|
|
#endif
|
2014-02-12 13:35:06 +11:00
|
|
|
|
2018-07-05 16:59:52 +02:00
|
|
|
/* first get the default camera for the view lock type */
|
|
|
|
|
if (v3d->scenelock) {
|
|
|
|
|
/* sets the camera view if available */
|
|
|
|
|
v3d->camera = scene->camera;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* use scene camera if one is not set (even though we're unlocked) */
|
|
|
|
|
if (v3d->camera == NULL) {
|
2014-02-12 13:35:06 +11:00
|
|
|
v3d->camera = scene->camera;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-02-12 13:35:06 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-05 16:59:52 +02:00
|
|
|
/* if the camera isn't found, check a number of options */
|
2019-03-26 21:16:47 +11:00
|
|
|
if (v3d->camera == NULL && ob && ob->type == OB_CAMERA) {
|
2018-07-05 16:59:52 +02:00
|
|
|
v3d->camera = ob;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (v3d->camera == NULL) {
|
2018-07-05 16:59:52 +02:00
|
|
|
v3d->camera = BKE_view_layer_camera_find(view_layer);
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-09-27 15:49:59 +02:00
|
|
|
/* couldn't find any useful camera, bail out */
|
2019-03-26 21:16:47 +11:00
|
|
|
if (v3d->camera == NULL) {
|
2018-07-05 16:59:52 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-05 16:59:52 +02:00
|
|
|
/* important these don't get out of sync for locked scenes */
|
2019-03-08 12:11:42 +01:00
|
|
|
if (v3d->scenelock && scene->camera != v3d->camera) {
|
2018-07-05 16:59:52 +02:00
|
|
|
scene->camera = v3d->camera;
|
2019-03-08 12:11:42 +01:00
|
|
|
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-05 16:59:52 +02:00
|
|
|
/* finally do snazzy view zooming */
|
|
|
|
|
rv3d->persp = RV3D_CAMOB;
|
|
|
|
|
ED_view3d_smooth_view(C,
|
|
|
|
|
v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2018-07-05 16:59:52 +02:00
|
|
|
smooth_viewtx,
|
|
|
|
|
&(const V3D_SmoothParams){
|
|
|
|
|
.camera = v3d->camera,
|
|
|
|
|
.ofs = rv3d->ofs,
|
|
|
|
|
.quat = rv3d->viewquat,
|
2019-01-07 00:58:10 +11:00
|
|
|
.dist = &rv3d->dist,
|
|
|
|
|
.lens = &v3d->lens,
|
|
|
|
|
});
|
2018-07-05 16:59:52 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* return to settings of last view */
|
|
|
|
|
/* does view3d_smooth_view too */
|
2020-02-09 11:50:25 +11:00
|
|
|
axis_set_view(C,
|
|
|
|
|
v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2020-02-09 11:50:25 +11:00
|
|
|
rv3d->lviewquat,
|
|
|
|
|
rv3d->lview,
|
|
|
|
|
rv3d->lview_axis_roll,
|
|
|
|
|
rv3d->lpersp,
|
|
|
|
|
NULL,
|
|
|
|
|
smooth_viewtx);
|
2014-02-12 13:35:06 +11:00
|
|
|
}
|
2008-12-23 09:59:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-23 09:59:02 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2010-11-19 17:16:25 +00:00
|
|
|
|
2018-07-05 16:54:30 +02:00
|
|
|
void VIEW3D_OT_view_camera(wmOperatorType *ot)
|
2008-12-23 09:59:02 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2018-07-05 16:54:30 +02:00
|
|
|
ot->name = "View Camera";
|
|
|
|
|
ot->description = "Toggle the camera view";
|
|
|
|
|
ot->idname = "VIEW3D_OT_view_camera";
|
2008-12-23 09:59:02 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2018-07-05 16:54:30 +02:00
|
|
|
ot->exec = view_camera_exec;
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->poll = ED_operator_rv3d_user_region_poll;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2008-12-23 09:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Orbit Operator
|
2018-01-29 14:59:56 +11:00
|
|
|
*
|
|
|
|
|
* Rotate (orbit) in incremental steps. For interactive orbit see #VIEW3D_OT_rotate.
|
2018-01-23 19:48:49 +11:00
|
|
|
* \{ */
|
|
|
|
|
|
2019-04-14 09:58:40 +02:00
|
|
|
enum {
|
|
|
|
|
V3D_VIEW_STEPLEFT = 1,
|
|
|
|
|
V3D_VIEW_STEPRIGHT,
|
|
|
|
|
V3D_VIEW_STEPDOWN,
|
|
|
|
|
V3D_VIEW_STEPUP,
|
|
|
|
|
};
|
|
|
|
|
|
2017-10-18 15:07:26 +11:00
|
|
|
static const EnumPropertyItem prop_view_orbit_items[] = {
|
2020-12-24 11:07:32 -06:00
|
|
|
{V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the left"},
|
|
|
|
|
{V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the right"},
|
|
|
|
|
{V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view up"},
|
|
|
|
|
{V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view down"},
|
2019-02-03 14:01:45 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2012-03-25 23:54:33 +00:00
|
|
|
};
|
2009-02-03 03:54:03 +00:00
|
|
|
|
|
|
|
|
static int vieworbit_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
2012-01-14 12:24:25 +00:00
|
|
|
View3D *v3d;
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2012-01-14 12:24:25 +00:00
|
|
|
RegionView3D *rv3d;
|
2009-02-03 03:54:03 +00:00
|
|
|
int orbitdir;
|
2015-03-13 04:45:40 +11:00
|
|
|
char view_opposite;
|
|
|
|
|
PropertyRNA *prop_angle = RNA_struct_find_property(op->ptr, "angle");
|
|
|
|
|
float angle = RNA_property_is_set(op->ptr, prop_angle) ?
|
2015-06-11 18:12:26 +02:00
|
|
|
RNA_property_float_get(op->ptr, prop_angle) :
|
|
|
|
|
DEG2RADF(U.pad_rot_angle);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-01-14 12:24:25 +00:00
|
|
|
/* no NULL check is needed, poll checks */
|
2015-03-13 04:45:40 +11:00
|
|
|
v3d = CTX_wm_view3d(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
region = CTX_wm_region(C);
|
|
|
|
|
rv3d = region->regiondata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-03-13 04:45:40 +11:00
|
|
|
/* support for switching to the opposite view (even when in locked views) */
|
|
|
|
|
view_opposite = (fabsf(angle) == (float)M_PI) ? ED_view3d_axis_view_opposite(rv3d->view) :
|
|
|
|
|
RV3D_VIEW_USER;
|
2009-02-03 03:54:03 +00:00
|
|
|
orbitdir = RNA_enum_get(op->ptr, "type");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) && (view_opposite == RV3D_VIEW_USER)) {
|
2015-03-13 04:45:40 +11:00
|
|
|
/* no NULL check is needed, poll checks */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_context_user_region(C, &v3d, ®ion);
|
|
|
|
|
rv3d = region->regiondata;
|
2015-03-13 04:45:40 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, v3d, region);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0 || (view_opposite != RV3D_VIEW_USER)) {
|
2012-02-22 16:52:06 +00:00
|
|
|
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
|
2014-04-30 02:16:01 +10:00
|
|
|
int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
2012-07-22 18:31:08 +00:00
|
|
|
float quat_mul[4];
|
|
|
|
|
float quat_new[4];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-03-13 04:45:40 +11:00
|
|
|
if (view_opposite == RV3D_VIEW_USER) {
|
2019-07-25 16:36:22 +02:00
|
|
|
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_persp_ensure(depsgraph, v3d, region);
|
2015-03-13 04:45:40 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-07-22 18:31:08 +00:00
|
|
|
if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) {
|
|
|
|
|
if (orbitdir == V3D_VIEW_STEPRIGHT) {
|
|
|
|
|
angle = -angle;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-25 12:09:59 +01:00
|
|
|
/* z-axis */
|
|
|
|
|
axis_angle_to_quat_single(quat_mul, 'Z', angle);
|
2009-02-03 03:54:03 +00:00
|
|
|
}
|
2012-07-22 18:31:08 +00:00
|
|
|
else {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-07-22 18:31:08 +00:00
|
|
|
if (orbitdir == V3D_VIEW_STEPDOWN) {
|
|
|
|
|
angle = -angle;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-25 12:09:59 +01:00
|
|
|
/* horizontal axis */
|
2012-07-22 18:31:08 +00:00
|
|
|
axis_angle_to_quat(quat_mul, rv3d->viewinv[0], angle);
|
2009-02-03 03:54:03 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-07-22 18:31:08 +00:00
|
|
|
mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 17:44:36 +11:00
|
|
|
/* avoid precision loss over time */
|
|
|
|
|
normalize_qt(quat_new);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-03-13 04:45:40 +11:00
|
|
|
if (view_opposite != RV3D_VIEW_USER) {
|
|
|
|
|
rv3d->view = view_opposite;
|
|
|
|
|
/* avoid float in-precision, just get a new orientation */
|
2020-02-09 11:50:25 +11:00
|
|
|
ED_view3d_quat_from_axis_view(view_opposite, rv3d->view_axis_roll, quat_new);
|
2015-03-13 04:45:40 +11:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
rv3d->view = RV3D_VIEW_USER;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-23 05:04:52 +11:00
|
|
|
float dyn_ofs[3], *dyn_ofs_pt = NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-23 05:04:52 +11:00
|
|
|
if (U.uiflag & USER_ORBIT_SELECTION) {
|
|
|
|
|
if (view3d_orbit_calc_center(C, dyn_ofs)) {
|
|
|
|
|
negate_v3(dyn_ofs);
|
|
|
|
|
dyn_ofs_pt = dyn_ofs;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-12-23 05:04:52 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-23 02:47:34 +11:00
|
|
|
ED_view3d_smooth_view(C,
|
|
|
|
|
v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2015-12-23 02:47:34 +11:00
|
|
|
smooth_viewtx,
|
2019-01-07 00:58:10 +11:00
|
|
|
&(const V3D_SmoothParams){
|
|
|
|
|
.quat = quat_new,
|
|
|
|
|
.dyn_ofs = dyn_ofs_pt,
|
|
|
|
|
});
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-07-22 18:31:08 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2009-02-03 03:54:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-07-22 18:31:08 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2009-02-03 03:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_orbit(wmOperatorType *ot)
|
|
|
|
|
{
|
2015-03-13 04:45:40 +11:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
2009-02-03 03:54:03 +00:00
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "View Orbit";
|
2010-02-10 21:15:44 +00:00
|
|
|
ot->description = "Orbit the view";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_view_orbit";
|
2009-02-03 03:54:03 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = vieworbit_exec;
|
|
|
|
|
ot->poll = ED_operator_rv3d_user_region_poll;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-02-03 03:54:03 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2012-10-08 06:21:36 +00:00
|
|
|
/* properties */
|
2015-03-13 04:45:40 +11:00
|
|
|
prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX);
|
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
2012-10-08 06:21:36 +00:00
|
|
|
ot->prop = RNA_def_enum(
|
|
|
|
|
ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
|
2009-02-03 03:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
2013-08-31 08:18:08 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Roll Operator
|
|
|
|
|
* \{ */
|
2013-08-31 08:18:08 +00:00
|
|
|
|
|
|
|
|
static void view_roll_angle(
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region, float quat[4], const float orig_quat[4], const float dvec[3], float angle)
|
2013-08-31 08:18:08 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2013-08-31 08:18:08 +00:00
|
|
|
float quat_mul[4];
|
|
|
|
|
|
|
|
|
|
/* camera axis */
|
2014-02-01 21:32:34 +11:00
|
|
|
axis_angle_normalized_to_quat(quat_mul, dvec, angle);
|
2013-08-31 08:18:08 +00:00
|
|
|
|
|
|
|
|
mul_qt_qtqt(quat, orig_quat, quat_mul);
|
2016-12-28 17:44:36 +11:00
|
|
|
|
|
|
|
|
/* avoid precision loss over time */
|
|
|
|
|
normalize_qt(quat);
|
|
|
|
|
|
2013-08-31 08:18:08 +00:00
|
|
|
rv3d->view = RV3D_VIEW_USER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y))
|
|
|
|
|
{
|
|
|
|
|
float angle = 0.0;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
float len1, len2, tot;
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
tot = vod->region->winrct.xmax - vod->region->winrct.xmin;
|
|
|
|
|
len1 = (vod->region->winrct.xmax - x) / tot;
|
|
|
|
|
len2 = (vod->region->winrct.xmax - vod->init.event_xy[0]) / tot;
|
2013-08-31 08:18:08 +00:00
|
|
|
angle = (len1 - len2) * (float)M_PI * 4.0f;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (angle != 0.0f) {
|
2020-03-06 16:56:42 +01:00
|
|
|
view_roll_angle(vod->region, vod->rv3d->viewquat, vod->init.quat, vod->init.mousevec, angle);
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2013-08-31 08:18:08 +00:00
|
|
|
|
2015-12-23 05:20:39 +11:00
|
|
|
if (vod->use_dyn_ofs) {
|
2018-01-29 14:36:40 +11:00
|
|
|
view3d_orbit_apply_dyn_ofs(
|
|
|
|
|
vod->rv3d->ofs, vod->init.ofs, vod->init.quat, vod->rv3d->viewquat, vod->dyn_ofs);
|
2015-12-23 05:20:39 +11:00
|
|
|
}
|
|
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_boxview_sync(vod->area, vod->region);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2013-08-31 08:18:08 +00:00
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
|
2013-08-31 08:18:08 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(vod->region);
|
2013-08-31 08:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
ViewOpsData *vod = op->customdata;
|
|
|
|
|
short event_code = VIEW_PASS;
|
2014-11-24 00:27:50 +01:00
|
|
|
bool use_autokey = false;
|
|
|
|
|
int ret = OPERATOR_RUNNING_MODAL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-08-31 08:18:08 +00:00
|
|
|
/* execute the events */
|
|
|
|
|
if (event->type == MOUSEMOVE) {
|
|
|
|
|
event_code = VIEW_APPLY;
|
|
|
|
|
}
|
|
|
|
|
else if (event->type == EVT_MODAL_MAP) {
|
|
|
|
|
switch (event->val) {
|
|
|
|
|
case VIEW_MODAL_CONFIRM:
|
|
|
|
|
event_code = VIEW_CONFIRM;
|
|
|
|
|
break;
|
|
|
|
|
case VIEWROT_MODAL_SWITCH_MOVE:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
|
|
|
|
|
event_code = VIEW_CONFIRM;
|
|
|
|
|
break;
|
|
|
|
|
case VIEWROT_MODAL_SWITCH_ROTATE:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
|
|
|
|
|
event_code = VIEW_CONFIRM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-29 14:36:40 +11:00
|
|
|
else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
|
2013-08-31 08:18:08 +00:00
|
|
|
event_code = VIEW_CONFIRM;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-08-31 08:18:08 +00:00
|
|
|
if (event_code == VIEW_APPLY) {
|
|
|
|
|
viewroll_apply(vod, event->x, event->y);
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
|
|
|
|
use_autokey = true;
|
|
|
|
|
}
|
2013-08-31 08:18:08 +00:00
|
|
|
}
|
|
|
|
|
else if (event_code == VIEW_CONFIRM) {
|
|
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
2014-11-24 00:27:50 +01:00
|
|
|
use_autokey = true;
|
|
|
|
|
ret = OPERATOR_FINISHED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (use_autokey) {
|
|
|
|
|
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, false);
|
2013-08-31 08:18:08 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
if (ret & OPERATOR_FINISHED) {
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-24 00:27:50 +01:00
|
|
|
return ret;
|
2013-08-31 08:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-18 15:07:26 +11:00
|
|
|
static const EnumPropertyItem prop_view_roll_items[] = {
|
2016-02-01 11:01:00 +11:00
|
|
|
{0, "ANGLE", 0, "Roll Angle", "Roll the view using an angle value"},
|
2020-12-24 11:07:32 -06:00
|
|
|
{V3D_VIEW_STEPLEFT, "LEFT", 0, "Roll Left", "Roll the view around to the left"},
|
|
|
|
|
{V3D_VIEW_STEPRIGHT, "RIGHT", 0, "Roll Right", "Roll the view around to the right"},
|
2019-02-03 14:01:45 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2014-10-16 11:34:32 +02:00
|
|
|
};
|
|
|
|
|
|
2013-08-31 08:18:08 +00:00
|
|
|
static int viewroll_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
View3D *v3d;
|
|
|
|
|
RegionView3D *rv3d;
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-08-31 08:18:08 +00:00
|
|
|
if (op->customdata) {
|
|
|
|
|
ViewOpsData *vod = op->customdata;
|
2020-03-06 16:56:42 +01:00
|
|
|
region = vod->region;
|
2013-08-31 08:18:08 +00:00
|
|
|
v3d = vod->v3d;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_context_user_region(C, &v3d, ®ion);
|
2013-08-31 08:18:08 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
rv3d = region->regiondata;
|
2013-08-31 08:18:08 +00:00
|
|
|
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, v3d, region);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-10-16 11:34:32 +02:00
|
|
|
int type = RNA_enum_get(op->ptr, "type");
|
2015-06-11 18:12:26 +02:00
|
|
|
float angle = (type == 0) ? RNA_float_get(op->ptr, "angle") : DEG2RADF(U.pad_rot_angle);
|
2013-08-31 08:18:08 +00:00
|
|
|
float mousevec[3];
|
|
|
|
|
float quat_new[4];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-16 04:04:44 +00:00
|
|
|
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-10-16 11:34:32 +02:00
|
|
|
if (type == V3D_VIEW_STEPLEFT) {
|
|
|
|
|
angle = -angle;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-08-31 08:18:08 +00:00
|
|
|
normalize_v3_v3(mousevec, rv3d->viewinv[2]);
|
|
|
|
|
negate_v3(mousevec);
|
2020-03-06 16:56:42 +01:00
|
|
|
view_roll_angle(region, quat_new, rv3d->viewquat, mousevec, angle);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-23 05:20:39 +11:00
|
|
|
const float *dyn_ofs_pt = NULL;
|
|
|
|
|
float dyn_ofs[3];
|
|
|
|
|
if (U.uiflag & USER_ORBIT_SELECTION) {
|
|
|
|
|
if (view3d_orbit_calc_center(C, dyn_ofs)) {
|
|
|
|
|
negate_v3(dyn_ofs);
|
|
|
|
|
dyn_ofs_pt = dyn_ofs;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-12-23 05:20:39 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-23 02:47:34 +11:00
|
|
|
ED_view3d_smooth_view(C,
|
|
|
|
|
v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2015-12-23 02:47:34 +11:00
|
|
|
smooth_viewtx,
|
2019-01-07 00:58:10 +11:00
|
|
|
&(const V3D_SmoothParams){
|
|
|
|
|
.quat = quat_new,
|
|
|
|
|
.dyn_ofs = dyn_ofs_pt,
|
|
|
|
|
});
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-08-31 08:18:08 +00:00
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2013-08-31 08:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
ViewOpsData *vod;
|
|
|
|
|
|
2014-10-16 11:34:32 +02:00
|
|
|
bool use_angle = RNA_enum_get(op->ptr, "type") != 0;
|
|
|
|
|
|
|
|
|
|
if (use_angle || RNA_struct_property_is_set(op->ptr, "angle")) {
|
2013-08-31 08:18:08 +00:00
|
|
|
viewroll_exec(C, op);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2014-02-04 21:44:37 +11:00
|
|
|
/* makes op->customdata */
|
|
|
|
|
viewops_data_alloc(C, op);
|
2018-01-29 15:34:39 +11:00
|
|
|
viewops_data_create(C, op, event, viewops_flag_from_prefs());
|
2014-02-04 21:44:37 +11:00
|
|
|
vod = op->customdata;
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
2016-05-05 02:01:18 +10:00
|
|
|
|
2013-08-31 08:18:08 +00:00
|
|
|
/* overwrite the mouse vector with the view direction */
|
2018-01-29 14:36:40 +11:00
|
|
|
normalize_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]);
|
|
|
|
|
negate_v3(vod->init.mousevec);
|
2013-08-31 08:18:08 +00:00
|
|
|
|
|
|
|
|
if (event->type == MOUSEROTATE) {
|
2018-01-29 14:36:40 +11:00
|
|
|
vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
|
2013-08-31 08:18:08 +00:00
|
|
|
viewroll_apply(vod, event->prevx, event->prevy);
|
|
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
|
|
|
|
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-03 17:18:56 +02:00
|
|
|
/* add temp handler */
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
2013-08-31 08:18:08 +00:00
|
|
|
}
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-30 23:08:53 +00:00
|
|
|
static void viewroll_cancel(bContext *C, wmOperator *op)
|
2013-08-31 08:18:08 +00:00
|
|
|
{
|
|
|
|
|
viewops_data_free(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_roll(wmOperatorType *ot)
|
|
|
|
|
{
|
2014-10-16 11:34:32 +02:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
2013-08-31 08:18:08 +00:00
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "View Roll";
|
|
|
|
|
ot->description = "Roll the view";
|
|
|
|
|
ot->idname = "VIEW3D_OT_view_roll";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->invoke = viewroll_invoke;
|
|
|
|
|
ot->exec = viewroll_exec;
|
|
|
|
|
ot->modal = viewroll_modal;
|
|
|
|
|
ot->poll = ED_operator_rv3d_user_region_poll;
|
|
|
|
|
ot->cancel = viewroll_cancel;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
|
|
|
|
|
|
|
|
|
/* properties */
|
2014-10-16 11:34:32 +02:00
|
|
|
ot->prop = prop = RNA_def_float(
|
|
|
|
|
ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX);
|
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
prop = RNA_def_enum(ot->srna,
|
|
|
|
|
"type",
|
|
|
|
|
prop_view_roll_items,
|
|
|
|
|
0,
|
|
|
|
|
"Roll Angle Source",
|
|
|
|
|
"How roll angle is calculated");
|
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2013-08-31 08:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-14 09:58:40 +02:00
|
|
|
enum {
|
|
|
|
|
V3D_VIEW_PANLEFT = 1,
|
|
|
|
|
V3D_VIEW_PANRIGHT,
|
|
|
|
|
V3D_VIEW_PANDOWN,
|
|
|
|
|
V3D_VIEW_PANUP,
|
|
|
|
|
};
|
|
|
|
|
|
2017-10-18 15:07:26 +11:00
|
|
|
static const EnumPropertyItem prop_view_pan_items[] = {
|
2020-12-24 11:07:32 -06:00
|
|
|
{V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the left"},
|
|
|
|
|
{V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the right"},
|
|
|
|
|
{V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view up"},
|
|
|
|
|
{V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view down"},
|
2019-02-03 14:01:45 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2012-03-25 23:54:33 +00:00
|
|
|
};
|
2009-02-03 03:54:03 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Pan Operator
|
|
|
|
|
*
|
2018-01-29 14:59:56 +11:00
|
|
|
* Move (pan) in incremental steps. For interactive pan see #VIEW3D_OT_move.
|
2018-01-23 19:48:49 +11:00
|
|
|
* \{ */
|
|
|
|
|
|
2017-02-18 17:25:12 +01:00
|
|
|
static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2009-02-03 03:54:03 +00:00
|
|
|
{
|
2017-02-18 17:25:12 +01:00
|
|
|
int x = 0, y = 0;
|
|
|
|
|
int pandir = RNA_enum_get(op->ptr, "type");
|
2013-04-08 04:48:34 +00:00
|
|
|
|
2017-02-18 17:25:12 +01:00
|
|
|
if (pandir == V3D_VIEW_PANRIGHT) {
|
|
|
|
|
x = -32;
|
|
|
|
|
}
|
|
|
|
|
else if (pandir == V3D_VIEW_PANLEFT) {
|
|
|
|
|
x = 32;
|
|
|
|
|
}
|
|
|
|
|
else if (pandir == V3D_VIEW_PANUP) {
|
|
|
|
|
y = -25;
|
|
|
|
|
}
|
|
|
|
|
else if (pandir == V3D_VIEW_PANDOWN) {
|
|
|
|
|
y = 25;
|
|
|
|
|
}
|
2009-02-03 03:54:03 +00:00
|
|
|
|
2017-02-18 17:25:12 +01:00
|
|
|
viewops_data_alloc(C, op);
|
2019-02-28 15:40:28 +11:00
|
|
|
viewops_data_create(C, op, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT));
|
2017-02-18 17:25:12 +01:00
|
|
|
ViewOpsData *vod = op->customdata;
|
2013-04-08 11:45:20 +00:00
|
|
|
|
2018-01-29 14:36:40 +11:00
|
|
|
viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y);
|
2013-04-08 11:45:20 +00:00
|
|
|
|
2017-02-18 17:25:12 +01:00
|
|
|
ED_view3d_depth_tag_update(vod->rv3d);
|
|
|
|
|
viewops_data_free(C, op);
|
2009-02-03 03:54:03 +00:00
|
|
|
|
2009-07-09 02:45:48 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2009-02-03 03:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_pan(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2018-06-27 17:07:02 +02:00
|
|
|
ot->name = "Pan View Direction";
|
|
|
|
|
ot->description = "Pan the view in a given direction";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_view_pan";
|
2009-02-03 03:54:03 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2017-02-18 17:25:12 +01:00
|
|
|
ot->invoke = viewpan_invoke;
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
ot->poll = view3d_pan_poll;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-02-03 03:54:03 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2012-10-08 06:21:36 +00:00
|
|
|
/* Properties */
|
|
|
|
|
ot->prop = RNA_def_enum(
|
|
|
|
|
ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
|
2009-02-03 03:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Toggle Perspective/Orthographic Operator
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-02-03 03:54:03 +00:00
|
|
|
{
|
2012-01-14 12:24:25 +00:00
|
|
|
View3D *v3d_dummy;
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2012-01-14 12:24:25 +00:00
|
|
|
RegionView3D *rv3d;
|
|
|
|
|
|
|
|
|
|
/* no NULL check is needed, poll checks */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_context_user_region(C, &v3d_dummy, ®ion);
|
|
|
|
|
rv3d = region->regiondata;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
/* Could add a separate lock flag for locking persp. */
|
|
|
|
|
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) == 0) {
|
2019-03-26 21:16:47 +11:00
|
|
|
if (rv3d->persp != RV3D_ORTHO) {
|
2012-03-25 23:54:33 +00:00
|
|
|
rv3d->persp = RV3D_ORTHO;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
rv3d->persp = RV3D_PERSP;
|
|
|
|
|
}
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(region);
|
2009-02-03 03:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_view_persportho(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2020-12-17 19:06:21 -06:00
|
|
|
ot->name = "View Perspective/Orthographic";
|
2012-10-08 06:21:36 +00:00
|
|
|
ot->description = "Switch the current view from perspective/orthographic projection";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_view_persportho";
|
2009-02-03 03:54:03 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = viewpersportho_exec;
|
|
|
|
|
ot->poll = ED_operator_rv3d_user_region_poll;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-02-03 03:54:03 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2009-02-03 03:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Navigate Operator
|
|
|
|
|
*
|
|
|
|
|
* Wraps walk/fly modes.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2013-12-03 03:14:09 -02:00
|
|
|
static int view3d_navigate_invoke(bContext *C,
|
|
|
|
|
wmOperator *UNUSED(op),
|
|
|
|
|
const wmEvent *UNUSED(event))
|
|
|
|
|
{
|
|
|
|
|
eViewNavigation_Method mode = U.navigation_mode;
|
|
|
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case VIEW_NAVIGATION_FLY:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_fly", WM_OP_INVOKE_DEFAULT, NULL);
|
|
|
|
|
break;
|
|
|
|
|
case VIEW_NAVIGATION_WALK:
|
|
|
|
|
default:
|
|
|
|
|
WM_operator_name_call(C, "VIEW3D_OT_walk", WM_OP_INVOKE_DEFAULT, NULL);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_navigate(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2019-06-29 08:08:02 +10:00
|
|
|
ot->name = "View Navigation (Walk/Fly)";
|
2013-12-03 22:42:58 +01:00
|
|
|
ot->description =
|
|
|
|
|
"Interactively navigate around the scene (uses the mode (walk/fly) preference)";
|
2013-12-03 03:14:09 -02:00
|
|
|
ot->idname = "VIEW3D_OT_navigate";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->invoke = view3d_navigate_invoke;
|
|
|
|
|
ot->poll = ED_operator_view3d_active;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
2011-04-28 08:26:49 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Background Image Add Operator
|
|
|
|
|
* \{ */
|
2009-02-03 03:54:03 +00:00
|
|
|
|
2018-07-06 09:10:07 +02:00
|
|
|
static Camera *background_image_camera_from_context(bContext *C)
|
|
|
|
|
{
|
|
|
|
|
/* Needed to support drag-and-drop & camera buttons context. */
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
if (v3d != NULL) {
|
|
|
|
|
if (v3d->camera && v3d->camera->data && v3d->camera->type == OB_CAMERA) {
|
|
|
|
|
return v3d->camera->data;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
|
|
|
|
|
return CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
|
2010-09-01 13:41:53 +00:00
|
|
|
}
|
2010-01-19 22:44:43 +00:00
|
|
|
|
2010-12-08 11:42:11 +00:00
|
|
|
static int background_image_add_exec(bContext *C, wmOperator *UNUSED(op))
|
2010-09-01 13:41:53 +00:00
|
|
|
{
|
2018-07-06 09:10:07 +02:00
|
|
|
Camera *cam = background_image_camera_from_context(C);
|
|
|
|
|
BKE_camera_background_image_new(cam);
|
2010-01-19 22:44:43 +00:00
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
2010-01-19 22:44:43 +00:00
|
|
|
{
|
2018-07-06 09:10:07 +02:00
|
|
|
Camera *cam = background_image_camera_from_context(C);
|
2014-11-27 11:15:43 +01:00
|
|
|
Image *ima;
|
2017-10-26 21:40:37 +11:00
|
|
|
CameraBGImage *bgpic;
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2014-11-23 22:48:48 +01:00
|
|
|
ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
|
2014-11-27 11:15:43 +01:00
|
|
|
/* may be NULL, continue anyway */
|
2014-11-23 22:48:48 +01:00
|
|
|
|
2018-07-06 09:10:07 +02:00
|
|
|
bgpic = BKE_camera_background_image_new(cam);
|
2014-11-23 22:48:48 +01:00
|
|
|
bgpic->ima = ima;
|
2014-11-23 19:38:27 +01:00
|
|
|
|
2017-10-26 21:40:37 +11:00
|
|
|
cam->flag |= CAM_SHOW_BG_IMAGE;
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
|
2019-07-17 16:36:44 +02:00
|
|
|
DEG_id_tag_update(&cam->id, ID_RECALC_COPY_ON_WRITE);
|
2017-10-26 21:40:37 +11:00
|
|
|
|
2010-09-01 13:41:53 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2010-01-19 22:44:43 +00:00
|
|
|
}
|
|
|
|
|
|
2018-07-06 09:10:07 +02:00
|
|
|
static bool background_image_add_poll(bContext *C)
|
|
|
|
|
{
|
|
|
|
|
return background_image_camera_from_context(C) != NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-08 11:42:11 +00:00
|
|
|
void VIEW3D_OT_background_image_add(wmOperatorType *ot)
|
2010-01-19 22:44:43 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2013-03-01 14:47:06 +00:00
|
|
|
/* note: having key shortcut here is bad practice,
|
|
|
|
|
* but for now keep because this displays when dragging an image over the 3D viewport */
|
2018-07-06 09:10:07 +02:00
|
|
|
ot->name = "Add Background Image";
|
|
|
|
|
ot->description = "Add a new background image";
|
2010-12-08 11:42:11 +00:00
|
|
|
ot->idname = "VIEW3D_OT_background_image_add";
|
2010-01-19 22:44:43 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2010-12-08 11:42:11 +00:00
|
|
|
ot->invoke = background_image_add_invoke;
|
|
|
|
|
ot->exec = background_image_add_exec;
|
2018-07-06 09:10:07 +02:00
|
|
|
ot->poll = background_image_add_poll;
|
2010-01-19 22:44:43 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
2016-07-31 17:33:57 +02:00
|
|
|
ot->flag = OPTYPE_UNDO;
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2010-09-01 13:41:53 +00:00
|
|
|
/* properties */
|
2012-03-25 23:54:33 +00:00
|
|
|
RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign");
|
2016-02-07 22:56:20 +11:00
|
|
|
WM_operator_properties_filesel(ot,
|
|
|
|
|
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
|
|
|
|
|
FILE_SPECIAL,
|
|
|
|
|
FILE_OPENFILE,
|
|
|
|
|
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
|
|
|
|
|
FILE_DEFAULTDISPLAY,
|
2020-11-02 23:55:59 +01:00
|
|
|
FILE_SORT_DEFAULT);
|
2010-01-19 22:44:43 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Background Image Remove Operator
|
|
|
|
|
* \{ */
|
2010-09-01 13:41:53 +00:00
|
|
|
|
2010-12-08 11:42:11 +00:00
|
|
|
static int background_image_remove_exec(bContext *C, wmOperator *op)
|
2010-01-19 22:44:43 +00:00
|
|
|
{
|
2017-10-26 21:40:37 +11:00
|
|
|
Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
|
2013-03-22 04:40:45 +00:00
|
|
|
const int index = RNA_int_get(op->ptr, "index");
|
2017-10-26 21:40:37 +11:00
|
|
|
CameraBGImage *bgpic_rem = BLI_findlink(&cam->bg_images, index);
|
2010-01-19 22:44:43 +00:00
|
|
|
|
2012-02-22 16:52:06 +00:00
|
|
|
if (bgpic_rem) {
|
2017-10-26 21:40:37 +11:00
|
|
|
if (bgpic_rem->source == CAM_BGIMG_SOURCE_IMAGE) {
|
2014-07-01 04:09:27 +10:00
|
|
|
id_us_min((ID *)bgpic_rem->ima);
|
2014-06-30 17:54:45 +02:00
|
|
|
}
|
2017-10-26 21:40:37 +11:00
|
|
|
else if (bgpic_rem->source == CAM_BGIMG_SOURCE_MOVIE) {
|
2014-07-01 04:09:27 +10:00
|
|
|
id_us_min((ID *)bgpic_rem->clip);
|
2014-06-30 17:54:45 +02:00
|
|
|
}
|
2014-07-01 04:09:27 +10:00
|
|
|
|
2017-10-26 21:40:37 +11:00
|
|
|
BKE_camera_background_image_remove(cam, bgpic_rem);
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
|
2019-07-17 16:36:44 +02:00
|
|
|
DEG_id_tag_update(&cam->id, ID_RECALC_COPY_ON_WRITE);
|
|
|
|
|
|
2011-01-12 03:41:12 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
2010-01-19 22:44:43 +00:00
|
|
|
}
|
|
|
|
|
|
2010-12-08 11:42:11 +00:00
|
|
|
void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
|
2010-01-19 22:44:43 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "Remove Background Image";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->description = "Remove a background image from the 3D view";
|
2010-12-08 11:42:11 +00:00
|
|
|
ot->idname = "VIEW3D_OT_background_image_remove";
|
2010-01-19 22:44:43 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2010-12-08 11:42:11 +00:00
|
|
|
ot->exec = background_image_remove_exec;
|
2017-10-26 21:40:37 +11:00
|
|
|
ot->poll = ED_operator_camera;
|
2010-01-19 22:44:43 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = 0;
|
2018-01-29 14:59:56 +11:00
|
|
|
|
2012-10-08 06:21:36 +00:00
|
|
|
/* properties */
|
2012-03-02 21:14:37 +00:00
|
|
|
RNA_def_int(
|
|
|
|
|
ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove", 0, INT_MAX);
|
2010-01-19 22:44:43 +00:00
|
|
|
}
|
2010-09-01 13:41:53 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Clipping Planes Operator
|
|
|
|
|
*
|
|
|
|
|
* Draw border or toggle off.
|
|
|
|
|
* \{ */
|
2008-12-21 12:43:34 +00:00
|
|
|
|
2020-08-02 17:17:31 +10:00
|
|
|
static void calc_local_clipping(float clip_local[6][4],
|
|
|
|
|
const BoundBox *clipbb,
|
|
|
|
|
const float mat[4][4])
|
2009-11-21 16:44:05 +00:00
|
|
|
{
|
|
|
|
|
BoundBox clipbb_local;
|
|
|
|
|
float imat[4][4];
|
|
|
|
|
|
|
|
|
|
invert_m4_m4(imat, mat);
|
|
|
|
|
|
2020-09-09 18:41:07 +02:00
|
|
|
for (int i = 0; i < 8; i++) {
|
2009-11-21 16:44:05 +00:00
|
|
|
mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-07 00:25:27 +11:00
|
|
|
ED_view3d_clipping_calc_from_boundbox(clip_local, &clipbb_local, is_negative_m4(mat));
|
2009-11-21 16:44:05 +00:00
|
|
|
}
|
|
|
|
|
|
2020-08-02 17:17:31 +10:00
|
|
|
void ED_view3d_clipping_local(RegionView3D *rv3d, const float mat[4][4])
|
2009-11-21 16:44:05 +00:00
|
|
|
{
|
2019-03-26 21:16:47 +11:00
|
|
|
if (rv3d->rflag & RV3D_CLIPPING) {
|
2009-11-21 16:44:05 +00:00
|
|
|
calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2009-11-21 16:44:05 +00:00
|
|
|
}
|
|
|
|
|
|
2008-12-21 12:43:34 +00:00
|
|
|
static int view3d_clipping_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2012-03-25 23:54:33 +00:00
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
2008-12-21 12:43:34 +00:00
|
|
|
rcti rect;
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2012-08-08 20:38:55 +00:00
|
|
|
WM_operator_properties_border_to_rcti(op, &rect);
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
rv3d->rflag |= RV3D_CLIPPING;
|
2012-03-25 23:54:33 +00:00
|
|
|
rv3d->clipbb = MEM_callocN(sizeof(BoundBox), "clipbb");
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2017-02-25 21:58:23 +01:00
|
|
|
/* NULL object because we don't want it in object space */
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_clipping_calc(rv3d->clipbb, rv3d->clip, region, NULL, &rect);
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-21 12:43:34 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int view3d_clipping_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2008-12-21 12:43:34 +00:00
|
|
|
{
|
2012-03-25 23:54:33 +00:00
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
|
2012-02-22 16:52:06 +00:00
|
|
|
if (rv3d->rflag & RV3D_CLIPPING) {
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
rv3d->rflag &= ~RV3D_CLIPPING;
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(region);
|
2019-03-26 21:16:47 +11:00
|
|
|
if (rv3d->clipbb) {
|
|
|
|
|
MEM_freeN(rv3d->clipbb);
|
|
|
|
|
}
|
2012-03-25 23:54:33 +00:00
|
|
|
rv3d->clipbb = NULL;
|
2008-12-21 12:43:34 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
return WM_gesture_box_invoke(C, op, event);
|
2008-12-21 12:43:34 +00:00
|
|
|
}
|
|
|
|
|
|
2009-07-09 08:39:58 +00:00
|
|
|
void VIEW3D_OT_clip_border(wmOperatorType *ot)
|
2008-12-21 12:43:34 +00:00
|
|
|
{
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-21 12:43:34 +00:00
|
|
|
/* identifiers */
|
2019-03-06 16:43:37 +01:00
|
|
|
ot->name = "Clipping Region";
|
|
|
|
|
ot->description = "Set the view clipping region";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_clip_border";
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2008-12-21 12:43:34 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = view3d_clipping_invoke;
|
|
|
|
|
ot->exec = view3d_clipping_exec;
|
2018-10-05 10:27:04 +10:00
|
|
|
ot->modal = WM_gesture_box_modal;
|
|
|
|
|
ot->cancel = WM_gesture_box_cancel;
|
2008-12-26 10:31:44 +00:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->poll = ED_operator_region_view3d_active;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = 0;
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2018-01-28 18:22:54 +11:00
|
|
|
/* properties */
|
2012-08-08 20:38:55 +00:00
|
|
|
WM_operator_properties_border(ot);
|
2008-12-21 12:43:34 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Set Cursor Operator
|
|
|
|
|
* \{ */
|
2008-12-26 19:07:31 +00:00
|
|
|
|
2012-12-26 16:24:50 +00:00
|
|
|
/* cursor position in vec, result in vec, mval in region coords */
|
|
|
|
|
/* note: cannot use event->mval here (called by object_add() */
|
2018-07-31 02:57:53 +12:00
|
|
|
void ED_view3d_cursor3d_position(bContext *C,
|
|
|
|
|
const int mval[2],
|
|
|
|
|
const bool use_depth,
|
|
|
|
|
float cursor_co[3])
|
2008-12-26 19:07:31 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2013-03-09 11:40:42 +00:00
|
|
|
bool flip;
|
2013-12-29 13:35:00 +11:00
|
|
|
bool depth_used = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-18 00:28:23 +00:00
|
|
|
/* normally the caller should ensure this,
|
|
|
|
|
* but this is called from areas that aren't already dealing with the viewport */
|
2019-03-26 21:16:47 +11:00
|
|
|
if (rv3d == NULL) {
|
2013-09-18 00:28:23 +00:00
|
|
|
return;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-22 12:55:15 +02:00
|
|
|
ED_view3d_calc_zfac(rv3d, cursor_co, &flip);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-07-01 13:12:24 +10:00
|
|
|
/* Reset the depth based on the view offset (we _know_ the offset is in front of us). */
|
2012-02-22 16:52:06 +00:00
|
|
|
if (flip) {
|
2018-06-22 12:55:15 +02:00
|
|
|
negate_v3_v3(cursor_co, rv3d->ofs);
|
2012-10-05 01:27:28 +00:00
|
|
|
/* re initialize, no need to check flip again */
|
2018-06-22 12:55:15 +02:00
|
|
|
ED_view3d_calc_zfac(rv3d, cursor_co, NULL /* &flip */);
|
2010-08-06 03:52:13 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-22 15:07:11 +02:00
|
|
|
if (use_depth) { /* maybe this should be accessed some other way */
|
2019-07-25 16:36:22 +02:00
|
|
|
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-12-29 13:35:00 +11:00
|
|
|
view3d_operator_needs_opengl(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_autodist(depsgraph, region, v3d, mval, cursor_co, true, NULL)) {
|
2013-12-29 13:35:00 +11:00
|
|
|
depth_used = true;
|
2008-12-26 19:07:31 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2013-12-29 13:35:00 +11:00
|
|
|
if (depth_used == false) {
|
|
|
|
|
float depth_pt[3];
|
2018-06-22 12:55:15 +02:00
|
|
|
copy_v3_v3(depth_pt, cursor_co);
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_win_to_3d_int(v3d, region, depth_pt, mval, cursor_co);
|
2012-12-26 16:24:50 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-06-22 15:07:11 +02:00
|
|
|
void ED_view3d_cursor3d_position_rotation(bContext *C,
|
|
|
|
|
const int mval[2],
|
|
|
|
|
const bool use_depth,
|
|
|
|
|
enum eV3DCursorOrient orientation,
|
|
|
|
|
float cursor_co[3],
|
|
|
|
|
float cursor_quat[4])
|
2012-12-26 16:24:50 +00:00
|
|
|
{
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
|
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-22 13:56:14 +02:00
|
|
|
/* XXX, caller should check. */
|
2019-03-26 21:16:47 +11:00
|
|
|
if (rv3d == NULL) {
|
2018-06-22 13:56:14 +02:00
|
|
|
return;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-22 15:07:11 +02:00
|
|
|
ED_view3d_cursor3d_position(C, mval, use_depth, cursor_co);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-22 15:07:11 +02:00
|
|
|
if (orientation == V3D_CURSOR_ORIENT_NONE) {
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
|
|
|
|
else if (orientation == V3D_CURSOR_ORIENT_VIEW) {
|
|
|
|
|
copy_qt_qt(cursor_quat, rv3d->viewquat);
|
|
|
|
|
cursor_quat[0] *= -1.0f;
|
|
|
|
|
}
|
2018-08-16 16:14:03 +10:00
|
|
|
else if (orientation == V3D_CURSOR_ORIENT_XFORM) {
|
|
|
|
|
float mat[3][3];
|
|
|
|
|
ED_transform_calc_orientation_from_type(C, mat);
|
|
|
|
|
mat3_to_quat(cursor_quat, mat);
|
|
|
|
|
}
|
2018-06-22 15:07:11 +02:00
|
|
|
else if (orientation == V3D_CURSOR_ORIENT_GEOM) {
|
|
|
|
|
copy_qt_qt(cursor_quat, rv3d->viewquat);
|
|
|
|
|
cursor_quat[0] *= -1.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 14:18:09 +02:00
|
|
|
const float mval_fl[2] = {UNPACK2(mval)};
|
|
|
|
|
float ray_no[3];
|
2018-06-22 13:56:14 +02:00
|
|
|
float ray_co[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 14:18:09 +02:00
|
|
|
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
|
2020-05-27 16:54:34 +10:00
|
|
|
scene, 0, region, v3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 14:18:09 +02:00
|
|
|
float obmat[4][4];
|
|
|
|
|
Object *ob_dummy = NULL;
|
|
|
|
|
float dist_px = 0;
|
|
|
|
|
if (ED_transform_snap_object_project_view3d_ex(snap_context,
|
2020-03-09 10:02:11 -03:00
|
|
|
CTX_data_ensure_evaluated_depsgraph(C),
|
2018-05-08 14:18:09 +02:00
|
|
|
SCE_SNAP_MODE_FACE,
|
|
|
|
|
&(const struct SnapObjectParams){
|
|
|
|
|
.snap_select = SNAP_ALL,
|
|
|
|
|
.use_object_edit_cage = false,
|
2020-01-14 09:39:46 -03:00
|
|
|
.use_occlusion_test = true,
|
2018-05-08 14:18:09 +02:00
|
|
|
},
|
2018-05-16 23:04:28 -03:00
|
|
|
mval_fl,
|
2019-08-20 19:18:25 -03:00
|
|
|
NULL,
|
2018-05-16 23:04:28 -03:00
|
|
|
&dist_px,
|
2018-06-22 13:56:14 +02:00
|
|
|
ray_co,
|
|
|
|
|
ray_no,
|
|
|
|
|
NULL,
|
2018-05-08 14:18:09 +02:00
|
|
|
&ob_dummy,
|
2019-07-05 18:23:06 -03:00
|
|
|
obmat) != 0) {
|
2018-06-22 15:07:11 +02:00
|
|
|
if (use_depth) {
|
2018-06-22 13:56:14 +02:00
|
|
|
copy_v3_v3(cursor_co, ray_co);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 14:18:09 +02:00
|
|
|
/* Math normal (Z). */
|
|
|
|
|
{
|
2020-01-15 20:08:58 +11:00
|
|
|
float tquat[4];
|
2018-05-08 14:18:09 +02:00
|
|
|
float z_src[3] = {0, 0, 1};
|
2018-06-22 13:56:14 +02:00
|
|
|
mul_qt_v3(cursor_quat, z_src);
|
2018-05-08 14:18:09 +02:00
|
|
|
rotation_between_vecs_to_quat(tquat, z_src, ray_no);
|
2018-06-22 13:56:14 +02:00
|
|
|
mul_qt_qtqt(cursor_quat, tquat, cursor_quat);
|
2018-05-08 14:18:09 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 14:18:09 +02:00
|
|
|
/* Match object matrix (X). */
|
|
|
|
|
{
|
|
|
|
|
const float ortho_axis_dot[3] = {
|
|
|
|
|
dot_v3v3(ray_no, obmat[0]),
|
|
|
|
|
dot_v3v3(ray_no, obmat[1]),
|
|
|
|
|
dot_v3v3(ray_no, obmat[2]),
|
|
|
|
|
};
|
|
|
|
|
const int ortho_axis = axis_dominant_v3_ortho_single(ortho_axis_dot);
|
2020-01-15 20:08:58 +11:00
|
|
|
|
|
|
|
|
float tquat_best[4];
|
|
|
|
|
float angle_best = -1.0f;
|
|
|
|
|
|
|
|
|
|
float tan_dst[3];
|
|
|
|
|
project_plane_v3_v3v3(tan_dst, obmat[ortho_axis], ray_no);
|
|
|
|
|
normalize_v3(tan_dst);
|
|
|
|
|
|
|
|
|
|
/* As the tangent is arbitrary from the users point of view,
|
|
|
|
|
* make the cursor 'roll' on the shortest angle.
|
|
|
|
|
* otherwise this can cause noticeable 'flipping', see T72419. */
|
|
|
|
|
for (int axis = 0; axis < 2; axis++) {
|
|
|
|
|
float tan_src[3] = {0, 0, 0};
|
|
|
|
|
tan_src[axis] = 1.0f;
|
|
|
|
|
mul_qt_v3(cursor_quat, tan_src);
|
|
|
|
|
|
|
|
|
|
for (int axis_sign = 0; axis_sign < 2; axis_sign++) {
|
|
|
|
|
float tquat_test[4];
|
|
|
|
|
rotation_between_vecs_to_quat(tquat_test, tan_src, tan_dst);
|
|
|
|
|
const float angle_test = angle_normalized_qt(tquat_test);
|
|
|
|
|
if (angle_test < angle_best || angle_best == -1.0f) {
|
|
|
|
|
angle_best = angle_test;
|
|
|
|
|
copy_qt_qt(tquat_best, tquat_test);
|
|
|
|
|
}
|
|
|
|
|
negate_v3(tan_src);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mul_qt_qtqt(cursor_quat, tquat_best, cursor_quat);
|
2018-05-08 14:18:09 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-05-08 14:18:09 +02:00
|
|
|
ED_transform_snap_object_context_destroy(snap_context);
|
2018-06-22 13:56:14 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-06-22 15:07:11 +02:00
|
|
|
void ED_view3d_cursor3d_update(bContext *C,
|
|
|
|
|
const int mval[2],
|
|
|
|
|
const bool use_depth,
|
|
|
|
|
enum eV3DCursorOrient orientation)
|
2018-06-22 13:56:14 +02:00
|
|
|
{
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
|
|
|
|
RegionView3D *rv3d = region->regiondata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-26 13:49:17 +11:00
|
|
|
View3DCursor *cursor_curr = &scene->cursor;
|
2018-06-22 13:56:14 +02:00
|
|
|
View3DCursor cursor_prev = *cursor_curr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-02-26 00:58:35 +11:00
|
|
|
{
|
|
|
|
|
float quat[4], quat_prev[4];
|
|
|
|
|
BKE_scene_cursor_rot_to_quat(cursor_curr, quat);
|
|
|
|
|
copy_qt_qt(quat_prev, quat);
|
|
|
|
|
ED_view3d_cursor3d_position_rotation(
|
|
|
|
|
C, mval, use_depth, orientation, cursor_curr->location, quat);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-02-26 00:58:35 +11:00
|
|
|
if (!equals_v4v4(quat_prev, quat)) {
|
|
|
|
|
if ((cursor_curr->rotation_mode == ROT_MODE_AXISANGLE) && RV3D_VIEW_IS_AXIS(rv3d->view)) {
|
|
|
|
|
float tmat[3][3], cmat[3][3];
|
|
|
|
|
quat_to_mat3(tmat, quat);
|
|
|
|
|
negate_v3_v3(cursor_curr->rotation_axis, tmat[2]);
|
|
|
|
|
axis_angle_to_mat3(cmat, cursor_curr->rotation_axis, 0.0f);
|
|
|
|
|
cursor_curr->rotation_angle = angle_signed_on_axis_v3v3_v3(
|
|
|
|
|
cmat[0], tmat[0], cursor_curr->rotation_axis);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BKE_scene_cursor_quat_to_rot(cursor_curr, quat, true);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-07 02:45:26 +10:00
|
|
|
/* offset the cursor lock to avoid jumping to new offset */
|
2020-03-17 11:32:03 +11:00
|
|
|
if (v3d->ob_center_cursor) {
|
2017-07-29 01:35:07 +10:00
|
|
|
if (U.uiflag & USER_LOCK_CURSOR_ADJUST) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-22 12:55:15 +02:00
|
|
|
float co_2d_curr[2], co_2d_prev[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-22 12:55:15 +02:00
|
|
|
if ((ED_view3d_project_float_global(
|
2020-03-06 16:56:42 +01:00
|
|
|
region, cursor_prev.location, co_2d_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
|
2018-06-22 12:55:15 +02:00
|
|
|
(ED_view3d_project_float_global(
|
2020-03-06 16:56:42 +01:00
|
|
|
region, cursor_curr->location, co_2d_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) {
|
|
|
|
|
rv3d->ofs_lock[0] += (co_2d_curr[0] - co_2d_prev[0]) / (region->winx * 0.5f);
|
|
|
|
|
rv3d->ofs_lock[1] += (co_2d_curr[1] - co_2d_prev[1]) / (region->winy * 0.5f);
|
2017-07-29 01:35:07 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2019-01-15 23:24:20 +11:00
|
|
|
/* Cursor may be outside of the view,
|
|
|
|
|
* prevent it getting 'lost', see: T40353 & T45301 */
|
2017-07-29 01:35:07 +10:00
|
|
|
zero_v2(rv3d->ofs_lock);
|
2015-06-07 02:45:26 +10:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (v3d->localvd) {
|
2012-03-25 23:54:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2012-03-25 23:54:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-06 16:41:32 +02:00
|
|
|
{
|
|
|
|
|
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
|
2019-08-23 09:52:12 +02:00
|
|
|
wmMsgParams_RNA msg_key_params = {{0}};
|
2019-03-01 12:35:48 +11:00
|
|
|
RNA_pointer_create(&scene->id, &RNA_View3DCursor, &scene->cursor, &msg_key_params.ptr);
|
|
|
|
|
WM_msg_publish_rna_params(mbus, &msg_key_params);
|
2018-05-06 16:41:32 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
|
2014-07-03 13:04:29 +03:00
|
|
|
}
|
|
|
|
|
|
2018-06-22 15:07:11 +02:00
|
|
|
static int view3d_cursor3d_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2014-07-03 13:04:29 +03:00
|
|
|
{
|
2018-06-22 15:07:11 +02:00
|
|
|
bool use_depth = (U.uiflag & USER_DEPTH_CURSOR);
|
|
|
|
|
{
|
|
|
|
|
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_depth");
|
|
|
|
|
if (RNA_property_is_set(op->ptr, prop)) {
|
|
|
|
|
use_depth = RNA_property_boolean_get(op->ptr, prop);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
RNA_property_boolean_set(op->ptr, prop, use_depth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const enum eV3DCursorOrient orientation = RNA_enum_get(op->ptr, "orientation");
|
|
|
|
|
ED_view3d_cursor3d_update(C, event->mval, use_depth, orientation);
|
2014-07-03 13:04:29 +03:00
|
|
|
|
2015-06-09 00:20:34 +10:00
|
|
|
return OPERATOR_FINISHED;
|
2008-12-26 19:07:31 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-14 03:06:06 +13:00
|
|
|
void VIEW3D_OT_cursor3d(wmOperatorType *ot)
|
|
|
|
|
{
|
2015-12-17 14:54:06 +11:00
|
|
|
|
2008-12-26 19:07:31 +00:00
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Set 3D Cursor";
|
2010-02-10 21:15:44 +00:00
|
|
|
ot->description = "Set the location of the 3D cursor";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "VIEW3D_OT_cursor3d";
|
2009-07-09 02:45:48 +00:00
|
|
|
|
2008-12-26 19:07:31 +00:00
|
|
|
/* api callbacks */
|
2012-10-05 01:27:28 +00:00
|
|
|
ot->invoke = view3d_cursor3d_invoke;
|
2015-12-17 14:54:06 +11:00
|
|
|
|
|
|
|
|
ot->poll = ED_operator_region_view3d_active;
|
2011-04-21 13:11:51 +00:00
|
|
|
|
2009-11-02 16:07:49 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
// ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2018-06-22 15:07:11 +02:00
|
|
|
|
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
static const EnumPropertyItem orientation_items[] = {
|
2018-08-16 16:14:03 +10:00
|
|
|
{V3D_CURSOR_ORIENT_NONE, "NONE", 0, "None", "Leave orientation unchanged"},
|
|
|
|
|
{V3D_CURSOR_ORIENT_VIEW, "VIEW", 0, "View", "Orient to the viewport"},
|
|
|
|
|
{V3D_CURSOR_ORIENT_XFORM,
|
|
|
|
|
"XFORM",
|
|
|
|
|
0,
|
|
|
|
|
"Transform",
|
|
|
|
|
"Orient to the current transform setting"},
|
|
|
|
|
{V3D_CURSOR_ORIENT_GEOM, "GEOM", 0, "Geometry", "Match the surface normal"},
|
2019-02-03 14:01:45 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2018-06-22 15:07:11 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
prop = RNA_def_boolean(
|
2018-06-23 09:45:53 +02:00
|
|
|
ot->srna, "use_depth", true, "Surface Project", "Project onto the surface");
|
2018-06-22 15:07:11 +02:00
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
|
|
prop = RNA_def_enum(ot->srna,
|
|
|
|
|
"orientation",
|
|
|
|
|
orientation_items,
|
|
|
|
|
V3D_CURSOR_ORIENT_VIEW,
|
2018-06-23 09:45:53 +02:00
|
|
|
"Orientation",
|
|
|
|
|
"Preset viewpoint to use");
|
2018-06-22 15:07:11 +02:00
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2008-12-26 19:07:31 +00:00
|
|
|
}
|
2008-12-21 12:43:34 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
2009-07-08 15:01:28 +00:00
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
2018-07-05 12:28:03 +02:00
|
|
|
/** \name Toggle Shading Operator
|
2018-01-23 19:48:49 +11:00
|
|
|
* \{ */
|
2016-05-22 15:44:18 +02:00
|
|
|
|
2018-07-05 12:28:03 +02:00
|
|
|
static const EnumPropertyItem prop_shading_type_items[] = {
|
2018-09-21 15:46:49 +02:00
|
|
|
{OB_WIRE, "WIREFRAME", 0, "Wireframe", "Toggle wireframe shading"},
|
|
|
|
|
{OB_SOLID, "SOLID", 0, "Solid", "Toggle solid shading"},
|
2018-07-05 12:28:03 +02:00
|
|
|
{OB_MATERIAL, "MATERIAL", 0, "LookDev", "Toggle lookdev shading"},
|
|
|
|
|
{OB_RENDER, "RENDERED", 0, "Rendered", "Toggle rendered shading"},
|
2019-02-03 14:01:45 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2018-07-05 12:28:03 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int toggle_shading_exec(bContext *C, wmOperator *op)
|
2016-05-22 15:44:18 +02:00
|
|
|
{
|
2018-07-05 12:28:03 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2016-05-22 15:44:18 +02:00
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2018-07-05 12:28:03 +02:00
|
|
|
int type = RNA_enum_get(op->ptr, "type");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-23 16:25:00 +11:00
|
|
|
if (type == OB_SOLID) {
|
2018-09-21 15:46:49 +02:00
|
|
|
if (v3d->shading.type != type) {
|
|
|
|
|
v3d->shading.type = type;
|
2018-07-05 12:28:03 +02:00
|
|
|
}
|
2018-09-21 15:46:49 +02:00
|
|
|
else if (v3d->shading.type == OB_WIRE) {
|
2018-07-11 14:20:39 +02:00
|
|
|
v3d->shading.type = OB_SOLID;
|
2018-07-05 12:28:03 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2018-09-21 15:46:49 +02:00
|
|
|
v3d->shading.type = OB_WIRE;
|
2018-07-05 12:28:03 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-09-21 15:46:49 +02:00
|
|
|
else {
|
2018-11-23 16:25:00 +11:00
|
|
|
char *prev_type = ((type == OB_WIRE) ? &v3d->shading.prev_type_wire : &v3d->shading.prev_type);
|
2018-09-21 15:46:49 +02:00
|
|
|
if (v3d->shading.type == type) {
|
2018-11-23 16:25:00 +11:00
|
|
|
if (*prev_type == type || !ELEM(*prev_type, OB_WIRE, OB_SOLID, OB_MATERIAL, OB_RENDER)) {
|
|
|
|
|
*prev_type = OB_SOLID;
|
|
|
|
|
}
|
|
|
|
|
v3d->shading.type = *prev_type;
|
2018-07-05 12:28:03 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2018-11-23 16:25:00 +11:00
|
|
|
*prev_type = v3d->shading.type;
|
2018-09-21 15:46:49 +02:00
|
|
|
v3d->shading.type = type;
|
2018-07-05 12:28:03 +02:00
|
|
|
}
|
2016-05-22 15:44:18 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_view3d_shade_update(bmain, v3d, area);
|
2016-05-22 15:44:18 +02:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-22 15:44:18 +02:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-05 12:28:03 +02:00
|
|
|
void VIEW3D_OT_toggle_shading(wmOperatorType *ot)
|
2016-05-22 15:44:18 +02:00
|
|
|
{
|
2018-07-05 12:28:03 +02:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
2016-05-22 15:44:18 +02:00
|
|
|
/* identifiers */
|
2018-07-05 12:28:03 +02:00
|
|
|
ot->name = "Toggle Shading Type";
|
|
|
|
|
ot->description = "Toggle shading type in 3D viewport";
|
|
|
|
|
ot->idname = "VIEW3D_OT_toggle_shading";
|
2016-05-22 15:44:18 +02:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2018-07-05 12:28:03 +02:00
|
|
|
ot->exec = toggle_shading_exec;
|
2016-05-22 15:44:18 +02:00
|
|
|
ot->poll = ED_operator_view3d_active;
|
2018-07-05 12:28:03 +02:00
|
|
|
|
|
|
|
|
prop = RNA_def_enum(
|
|
|
|
|
ot->srna, "type", prop_shading_type_items, 0, "Type", "Shading type to toggle");
|
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2016-05-22 15:44:18 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-23 19:48:49 +11:00
|
|
|
/** \} */
|
2018-11-22 06:44:09 +11:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Toggle XRay
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static int toggle_xray_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2018-11-22 06:44:09 +11:00
|
|
|
Object *obact = CTX_data_active_object(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-23 13:17:10 +11:00
|
|
|
if (obact && ((obact->mode & OB_MODE_POSE) ||
|
|
|
|
|
((obact->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(obact)))) {
|
2018-11-22 06:44:09 +11:00
|
|
|
v3d->overlay.flag ^= V3D_OVERLAY_BONE_SELECT;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const bool xray_active = ((obact && (obact->mode & OB_MODE_EDIT)) ||
|
|
|
|
|
ELEM(v3d->shading.type, OB_WIRE, OB_SOLID));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-22 06:44:09 +11:00
|
|
|
if (v3d->shading.type == OB_WIRE) {
|
2019-06-13 17:33:51 +10:00
|
|
|
v3d->shading.flag ^= V3D_SHADING_XRAY_WIREFRAME;
|
2018-11-22 06:44:09 +11:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
v3d->shading.flag ^= V3D_SHADING_XRAY;
|
|
|
|
|
}
|
|
|
|
|
if (!xray_active) {
|
|
|
|
|
BKE_report(op->reports, RPT_INFO, "X-Ray not available in current mode");
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-11-22 06:44:09 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_redraw(area);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-22 06:44:09 +11:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VIEW3D_OT_toggle_xray(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "Toggle X-Ray";
|
|
|
|
|
ot->idname = "VIEW3D_OT_toggle_xray";
|
2020-05-11 17:01:22 -04:00
|
|
|
ot->description = "Transparent scene display. Allow selecting through items";
|
2018-11-22 06:44:09 +11:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec = toggle_xray_exec;
|
|
|
|
|
ot->poll = ED_operator_view3d_active;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|