3D View: support for editing cursor rotation

Add buttons for editing the cursor rotation as well as rotation modes,
similar to object and pose bones.
This commit is contained in:
Campbell Barton 2019-02-26 00:58:35 +11:00
parent 213ac7b1ac
commit 86c0ee8020
11 changed files with 263 additions and 26 deletions

View File

@ -4329,6 +4329,14 @@ class VIEW3D_PT_view3d_cursor(Panel):
scene = context.scene
layout.column().prop(scene, "cursor_location", text="Location")
rotation_mode = scene.cursor_rotation_mode
if rotation_mode == 'QUATERNION':
layout.column().prop(scene, "cursor_rotation_quaternion", text="Rotation")
elif rotation_mode == 'AXIS_ANGLE':
layout.column().prop(scene, "cursor_rotation_axis_angle", text="Rotation")
else:
layout.column().prop(scene, "cursor_rotation_euler", text="Rotation")
layout.row().prop(scene, "cursor_rotation_mode")
class VIEW3D_PT_collections(Panel):

View File

@ -36,6 +36,7 @@ struct RenderData;
struct Scene;
struct TransformOrientation;
struct UnitSettings;
struct View3DCursor;
struct ViewLayer;
struct ViewRender;
struct WorkSpace;
@ -201,6 +202,12 @@ struct TransformOrientation *BKE_scene_transform_orientation_find(
int BKE_scene_transform_orientation_get_index(
const struct Scene *scene, const struct TransformOrientation *orientation);
void BKE_scene_cursor_rot_to_mat3(const struct View3DCursor *cursor, float mat[3][3]);
void BKE_scene_cursor_mat3_to_rot(struct View3DCursor *cursor, const float mat[3][3], bool use_compat);
void BKE_scene_cursor_rot_to_quat(const struct View3DCursor *cursor, float quat[4]);
void BKE_scene_cursor_quat_to_rot(struct View3DCursor *cursor, const float quat[4], bool use_compat);
#ifdef __cplusplus
}
#endif

View File

@ -547,7 +547,10 @@ void BKE_scene_init(Scene *sce)
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(sce, id));
unit_qt(sce->cursor.rotation);
sce->cursor.rotation_mode = ROT_MODE_XYZ;
sce->cursor.rotation_quaternion[0] = 1.0f;
sce->cursor.rotation_axis[1] = 1.0f;
sce->r.mode = R_OSA;
sce->r.cfra = 1;
@ -2242,3 +2245,97 @@ int BKE_scene_transform_orientation_get_index(
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Scene Cursor Rotation
*
* Matches #BKE_object_rot_to_mat3 and #BKE_object_mat3_to_rot.
* \{ */
void BKE_scene_cursor_rot_to_mat3(const View3DCursor *cursor, float mat[3][3])
{
if (cursor->rotation_mode > 0) {
eulO_to_mat3(mat, cursor->rotation_euler, cursor->rotation_mode);
}
else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
axis_angle_to_mat3(mat, cursor->rotation_axis, cursor->rotation_angle);
}
else {
float tquat[4];
normalize_qt_qt(tquat, cursor->rotation_quaternion);
quat_to_mat3(mat, tquat);
}
}
void BKE_scene_cursor_rot_to_quat(const View3DCursor *cursor, float quat[4])
{
if (cursor->rotation_mode > 0) {
eulO_to_quat(quat, cursor->rotation_euler, cursor->rotation_mode);
}
else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
axis_angle_to_quat(quat, cursor->rotation_axis, cursor->rotation_angle);
}
else {
normalize_qt_qt(quat, cursor->rotation_quaternion);
}
}
void BKE_scene_cursor_mat3_to_rot(View3DCursor *cursor, const float mat[3][3], bool use_compat)
{
BLI_ASSERT_UNIT_M3(mat);
switch (cursor->rotation_mode) {
case ROT_MODE_QUAT:
{
mat3_normalized_to_quat(cursor->rotation_quaternion, mat);
break;
}
case ROT_MODE_AXISANGLE:
{
mat3_to_axis_angle(cursor->rotation_axis, &cursor->rotation_angle, mat);
break;
}
default:
{
if (use_compat) {
mat3_to_compatible_eulO(cursor->rotation_euler, cursor->rotation_euler, cursor->rotation_mode, mat);
}
else {
mat3_to_eulO(cursor->rotation_euler, cursor->rotation_mode, mat);
}
break;
}
}
}
void BKE_scene_cursor_quat_to_rot(View3DCursor *cursor, const float quat[4], bool use_compat)
{
BLI_ASSERT_UNIT_QUAT(quat);
switch (cursor->rotation_mode) {
case ROT_MODE_QUAT:
{
copy_qt_qt(cursor->rotation_quaternion, quat);
break;
}
case ROT_MODE_AXISANGLE:
{
quat_to_axis_angle(cursor->rotation_axis, &cursor->rotation_angle, quat);
break;
}
default:
{
if (use_compat) {
quat_to_compatible_eulO(cursor->rotation_euler, cursor->rotation_euler, cursor->rotation_mode, quat);
}
else {
quat_to_eulO(cursor->rotation_euler, cursor->rotation_mode, quat);
}
break;
}
}
}
/** \} */

View File

@ -8086,8 +8086,8 @@ void blo_lib_link_restore(Main *oldmain, Main *newmain, wmWindowManager *curwm,
BKE_workspace_active_set(win->workspace_hook, workspace);
/* keep cursor location through undo */
copy_v3_v3(win->scene->cursor.location, oldscene->cursor.location);
copy_qt_qt(win->scene->cursor.rotation, oldscene->cursor.rotation);
memcpy(&win->scene->cursor, &oldscene->cursor, sizeof(win->scene->cursor));
lib_link_window_scene_data_restore(win, win->scene, cur_view_layer);
BLI_assert(win->screen == NULL);

View File

@ -1336,12 +1336,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
if (!DNA_struct_find(fd->filesdna, "View3DCursor")) {
for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
unit_qt(scene->cursor.rotation);
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 280, 14)) {
@ -2821,5 +2815,15 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
if (!DNA_struct_elem_find(fd->filesdna, "View3DCursor", "short", "rotation_mode")) {
for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
if (is_zero_v3(scene->cursor.rotation_axis)) {
scene->cursor.rotation_mode = ROT_MODE_XYZ;
scene->cursor.rotation_quaternion[0] = 1.0f;
scene->cursor.rotation_axis[1] = 1.0f;
}
}
}
}
}

View File

@ -201,12 +201,18 @@ void DRW_draw_cursor(void)
if (is_cursor_visible(draw_ctx, scene, view_layer)) {
int co[2];
/* Get cursor data into quaternion form */
const View3DCursor *cursor = &scene->cursor;
if (ED_view3d_project_int_global(
ar, cursor->location, co, V3D_PROJ_TEST_NOP | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
{
RegionView3D *rv3d = ar->regiondata;
float cursor_quat[4];
BKE_scene_cursor_rot_to_quat(cursor, cursor_quat);
/* Draw nice Anti Aliased cursor. */
GPU_line_width(1.0f);
glEnable(GL_BLEND);
@ -214,7 +220,12 @@ void DRW_draw_cursor(void)
float eps = 1e-5f;
rv3d->viewquat[0] = -rv3d->viewquat[0];
const bool is_aligned = compare_v4v4(cursor->rotation, rv3d->viewquat, eps);
bool is_aligned = compare_v4v4(cursor_quat, rv3d->viewquat, eps);
if (is_aligned == false) {
float tquat[4];
rotation_between_quats_to_quat(tquat, rv3d->viewquat, cursor_quat);
is_aligned = tquat[0] - eps < -1.0f;
}
rv3d->viewquat[0] = -rv3d->viewquat[0];
/* Draw lines */
@ -241,7 +252,7 @@ void DRW_draw_cursor(void)
for (int axis = 0; axis < 3; axis++) {
float axis_vec[3] = {0};
axis_vec[axis] = scale;
mul_qt_v3(cursor->rotation, axis_vec);
mul_qt_v3(cursor_quat, axis_vec);
CURSOR_EDGE(axis_vec, axis, +);
CURSOR_EDGE(axis_vec, axis, -);
}

View File

@ -2712,7 +2712,10 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
zero_v3(min);
zero_v3(max);
zero_v3(cursor->location);
unit_qt(cursor->rotation);
unit_qt(cursor->rotation_quaternion);
zero_v3(cursor->rotation_euler);
ARRAY_SET_ITEMS(cursor->rotation_axis, 0.0f, 1.0f, 0.0f);
cursor->rotation_angle = 0.0f;
}
else {
INIT_MINMAX(min, max);
@ -4762,10 +4765,30 @@ void ED_view3d_cursor3d_update(
View3DCursor *cursor_curr = &scene->cursor;
View3DCursor cursor_prev = *cursor_curr;
ED_view3d_cursor3d_position_rotation(
C, mval,
use_depth, orientation,
cursor_curr->location, cursor_curr->rotation);
{
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);
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);
}
}
}
/* offset the cursor lock to avoid jumping to new offset */
if (v3d->ob_centre_cursor) {

View File

@ -45,6 +45,7 @@
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@ -88,13 +89,15 @@ void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float
void ED_view3d_cursor3d_calc_mat3(const Scene *scene, float mat[3][3])
{
const View3DCursor *cursor = &scene->cursor;
quat_to_mat3(mat, cursor->rotation);
BKE_scene_cursor_rot_to_mat3(cursor, mat);
}
void ED_view3d_cursor3d_calc_mat4(const Scene *scene, float mat[4][4])
{
const View3DCursor *cursor = &scene->cursor;
quat_to_mat4(mat, cursor->rotation);
float mat3[3][3];
BKE_scene_cursor_rot_to_mat3(cursor, mat3);
copy_m4_m3(mat, mat3);
copy_v3_v3(mat[3], cursor->location);
}

View File

@ -405,15 +405,39 @@ static void createTransCursor_view3d(TransInfo *t)
td->ob = NULL;
unit_m3(td->mtx);
quat_to_mat3(td->axismtx, cursor->rotation);
BKE_scene_cursor_rot_to_mat3(cursor, td->axismtx);
normalize_m3(td->axismtx);
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
td->loc = cursor->location;
copy_v3_v3(td->iloc, cursor->location);
td->ext->quat = cursor->rotation;
copy_qt_qt(td->ext->iquat, cursor->rotation);
if (cursor->rotation_mode > 0) {
td->ext->rot = cursor->rotation_euler;
td->ext->rotAxis = NULL;
td->ext->rotAngle = NULL;
td->ext->quat = NULL;
copy_v3_v3(td->ext->irot, cursor->rotation_euler);
}
else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
td->ext->rot = NULL;
td->ext->rotAxis = cursor->rotation_axis;
td->ext->rotAngle = &cursor->rotation_angle;
td->ext->quat = NULL;
td->ext->irotAngle = cursor->rotation_angle;
copy_v3_v3(td->ext->irotAxis, cursor->rotation_axis);
}
else {
td->ext->rot = NULL;
td->ext->rotAxis = NULL;
td->ext->rotAngle = NULL;
td->ext->quat = cursor->rotation_quaternion;
copy_qt_qt(td->ext->iquat, cursor->rotation_quaternion);
}
td->ext->rotOrder = cursor->rotation_mode;
}
/** \} */

View File

@ -136,8 +136,13 @@ typedef struct RegionView3D {
typedef struct View3DCursor {
float location[3];
float rotation[4];
char _pad[4];
float rotation_quaternion[4];
float rotation_euler[3];
float rotation_axis[3], rotation_angle;
short rotation_mode;
char _pad[6];
} View3DCursor;
/* 3D Viewport Shading settings */

View File

@ -40,6 +40,7 @@
#include "BLT_translation.h"
#include "BKE_armature.h"
#include "BKE_editmesh.h"
#include "BKE_paint.h"
@ -1634,7 +1635,36 @@ static void rna_Scene_sync_mode_set(PointerRNA *ptr, int value)
}
}
static void rna_Scene_cursor_rotation_mode_set(PointerRNA *ptr, int value)
{
Scene *scene = ptr->id.data;
View3DCursor *cursor = &scene->cursor;
/* use API Method for conversions... */
BKE_rotMode_change_values(
cursor->rotation_quaternion,
cursor->rotation_euler,
cursor->rotation_axis, &cursor->rotation_angle, cursor->rotation_mode, (short)value);
/* finally, set the new rotation type */
cursor->rotation_mode = value;
}
static void rna_Scene_cursor_rotation_axis_angle_get(PointerRNA *ptr, float *value)
{
Scene *scene = ptr->id.data;
View3DCursor *cursor = &scene->cursor;
value[0] = cursor->rotation_angle;
copy_v3_v3(&value[1], cursor->rotation_axis);
}
static void rna_Scene_cursor_rotation_axis_angle_set(PointerRNA *ptr, const float *value)
{
Scene *scene = ptr->id.data;
View3DCursor *cursor = &scene->cursor;
cursor->rotation_angle = value[0];
copy_v3_v3(cursor->rotation_axis, &value[1]);
}
static TimeMarker *rna_TimeLine_add(Scene *scene, const char name[], int frame)
{
@ -6303,6 +6333,10 @@ void RNA_def_scene(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
static float default_quat[4] = {1, 0, 0, 0}; /* default quaternion values */
static float default_axisAngle[4] = {0, 0, 1, 0}; /* default axis-angle rotation values */
/* Struct definition */
srna = RNA_def_struct(brna, "Scene", "ID");
RNA_def_struct_ui_text(srna, "Scene", "Scene data-block, consisting in objects and "
@ -6336,9 +6370,30 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, 4);
RNA_def_property_update(prop, NC_WINDOW, NULL);
prop = RNA_def_property(srna, "cursor_rotation", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_float_sdna(prop, NULL, "cursor.rotation");
RNA_def_property_ui_text(prop, "Cursor Rotation", "3D cursor rotation in quaternions (keep normalized)");
prop = RNA_def_property(srna, "cursor_rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_float_sdna(prop, NULL, "cursor.rotation_quaternion");
RNA_def_property_float_array_default(prop, default_quat);
RNA_def_property_ui_text(prop, "Cursor Quaternion Rotation", "3D cursor rotation in quaternions (keep normalized)");
RNA_def_property_update(prop, NC_WINDOW, NULL);
prop = RNA_def_property(srna, "cursor_rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE);
RNA_def_property_array(prop, 4);
RNA_def_property_float_funcs(prop, "rna_Scene_cursor_rotation_axis_angle_get",
"rna_Scene_cursor_rotation_axis_angle_set", NULL);
RNA_def_property_float_array_default(prop, default_axisAngle);
RNA_def_property_ui_text(prop, "Cursor Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation");
RNA_def_property_update(prop, NC_WINDOW, NULL);
prop = RNA_def_property(srna, "cursor_rotation_euler", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "cursor.rotation_euler");
RNA_def_property_ui_text(prop, "Cursor Euler Rotation", "3D cursor rotation");
RNA_def_property_update(prop, NC_WINDOW, NULL);
prop = RNA_def_property(srna, "cursor_rotation_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "cursor.rotation_mode");
RNA_def_property_enum_items(prop, rna_enum_object_rotation_mode_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_Scene_cursor_rotation_mode_set", NULL);
RNA_def_property_ui_text(prop, "Cursor Rotation Mode", "");
RNA_def_property_update(prop, NC_WINDOW, NULL);
prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);