Object: add-object option to place on the surface normal

Optionally use the surface normal under the mouse cursor.
This commit is contained in:
Campbell Barton 2020-07-22 22:28:13 +10:00
parent 980dd43bd4
commit 4950022e7d
2 changed files with 160 additions and 14 deletions

View File

@ -455,6 +455,11 @@ class _defs_view3d_add:
row = layout.row()
row.prop(props, "plane_axis", text="")
row = layout.row()
row.scale_x = 0.8
row.label(text="Orientation:")
row = layout.row()
row.prop(props, "plane_orientation", text="")
row = layout.row()
row.scale_x = 0.7
row.prop(props, "plane_origin")

View File

@ -86,6 +86,11 @@ enum ePlace_Depth {
PLACE_DEPTH_CURSOR_VIEW = 3,
};
enum ePlace_Orient {
PLACE_ORIENT_SURFACE = 1,
PLACE_ORIENT_DEFAULT = 2,
};
struct InteractivePlaceData {
/* Window manager variables (set these even when waiting for input). */
Scene *scene;
@ -145,16 +150,96 @@ struct InteractivePlaceData {
/* On-screen snap distance. */
#define MVAL_MAX_PX_DIST 12.0f
static bool idp_snap_point_from_gizmo(wmGizmo *gz, float r_location[3])
static bool idp_snap_point_from_gizmo_ex(wmGizmo *gz, const char *prop_id, float r_location[3])
{
if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
PropertyRNA *prop_location = RNA_struct_find_property(gz->ptr, "location");
PropertyRNA *prop_location = RNA_struct_find_property(gz->ptr, prop_id);
RNA_property_float_get_array(gz->ptr, prop_location, r_location);
return true;
}
return false;
}
static bool idp_snap_point_from_gizmo(wmGizmo *gz, float r_location[3])
{
return idp_snap_point_from_gizmo_ex(gz, "location", r_location);
}
static bool idp_snap_normal_from_gizmo(wmGizmo *gz, float r_normal[3])
{
return idp_snap_point_from_gizmo_ex(gz, "normal", r_normal);
}
/**
* Calculate a 3x3 orientation matrix from the surface under the cursor.
*/
static bool idp_poject_surface_normal(SnapObjectContext *snap_context,
struct Depsgraph *depsgraph,
const float mval_fl[2],
const float mat_fallback[3][3],
const float normal_fallback[3],
float r_mat[3][3])
{
bool success = false;
float normal[3] = {0.0f};
float co_dummy[3];
/* We could use the index to get the orientation from the face. */
Object *ob_snap;
float obmat[4][4];
if (ED_transform_snap_object_project_view3d_ex(snap_context,
depsgraph,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
.use_object_edit_cage = true,
},
mval_fl,
NULL,
NULL,
co_dummy,
normal,
NULL,
&ob_snap,
obmat)) {
/* pass */
}
else if (normal_fallback != NULL) {
copy_m4_m3(obmat, mat_fallback);
copy_v3_v3(normal, normal_fallback);
}
if (!is_zero_v3(normal)) {
float mat[3][3];
copy_m3_m4(mat, obmat);
normalize_m3(mat);
float dot_best = fabsf(dot_v3v3(mat[0], normal));
int i_best = 0;
for (int i = 1; i < 3; i++) {
float dot_test = fabsf(dot_v3v3(mat[i], normal));
if (dot_test > dot_best) {
i_best = i;
dot_best = dot_test;
}
}
if (dot_v3v3(mat[i_best], normal) < 0.0f) {
negate_v3(mat[(i_best + 1) % 3]);
negate_v3(mat[(i_best + 2) % 3]);
}
copy_v3_v3(mat[i_best], normal);
orthogonalize_m3(mat, i_best);
normalize_m3(mat);
copy_v3_v3(r_mat[0], mat[(i_best + 1) % 3]);
copy_v3_v3(r_mat[1], mat[(i_best + 2) % 3]);
copy_v3_v3(r_mat[2], mat[i_best]);
success = true;
}
return success;
}
/** \} */
/* -------------------------------------------------------------------- */
@ -549,21 +634,14 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv
const int plane_axis = RNA_enum_get(op->ptr, "plane_axis");
const enum ePlace_Depth plane_depth = RNA_enum_get(op->ptr, "plane_depth");
const enum ePlace_Origin plane_origin = RNA_enum_get(op->ptr, "plane_origin");
const enum ePlace_Orient plane_orient = RNA_enum_get(op->ptr, "plane_orientation");
const float mval_fl[2] = {UNPACK2(event->mval)};
struct InteractivePlaceData *ipd = op->customdata;
RegionView3D *rv3d = ipd->region->regiondata;
ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
ED_transform_calc_orientation_from_type(C, ipd->matrix_orient);
ipd->orient_axis = plane_axis;
ipd->is_centered_init = (plane_origin == PLACE_ORIGIN_CENTER);
ipd->step[0].is_centered = ipd->is_centered_init;
ipd->step[1].is_centered = ipd->is_centered_init;
ipd->step_index = STEP_BASE;
/* Assign snap gizmo which is may be used as part of the tool. */
{
wmGizmoMap *gzmap = ipd->region->gizmo_map;
@ -573,6 +651,52 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv
}
}
ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
ED_transform_calc_orientation_from_type(C, ipd->matrix_orient);
/* Set the orientation. */
if (plane_orient == PLACE_ORIENT_SURFACE) {
bool snap_context_free = false;
SnapObjectContext *snap_context =
(ipd->snap_gizmo ? ED_gizmotypes_snap_3d_context_ensure(
ipd->scene, ipd->region, ipd->v3d, ipd->snap_gizmo) :
NULL);
if (snap_context == NULL) {
snap_context = ED_transform_snap_object_context_create_view3d(
ipd->scene, 0, ipd->region, ipd->v3d);
snap_context_free = true;
}
float matrix_orient_surface[3][3];
/* Use the snap normal as a fallback in case the cursor isn't over a surface
* but snapping is enabled. */
float normal_fallback[3];
bool use_normal_fallback = ipd->snap_gizmo ?
idp_snap_normal_from_gizmo(ipd->snap_gizmo, normal_fallback) :
false;
if (idp_poject_surface_normal(snap_context,
CTX_data_ensure_evaluated_depsgraph(C),
mval_fl,
use_normal_fallback ? ipd->matrix_orient : NULL,
use_normal_fallback ? normal_fallback : NULL,
matrix_orient_surface)) {
copy_m3_m3(ipd->matrix_orient, matrix_orient_surface);
}
if (snap_context_free) {
ED_transform_snap_object_context_destroy(snap_context);
}
}
ipd->orient_axis = plane_axis;
ipd->is_centered_init = (plane_origin == PLACE_ORIGIN_CENTER);
ipd->step[0].is_centered = ipd->is_centered_init;
ipd->step[1].is_centered = ipd->is_centered_init;
ipd->step_index = STEP_BASE;
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "primitive_type");
if (RNA_property_is_set(op->ptr, prop)) {
@ -618,8 +742,6 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv
plane_from_point_normal_v3(
ipd->step[0].plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]);
const float mval_fl[2] = {UNPACK2(event->mval)};
const bool is_snap_found = ipd->snap_gizmo ?
idp_snap_point_from_gizmo(ipd->snap_gizmo, ipd->co_src) :
false;
@ -1102,6 +1224,25 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
RNA_def_property_enum_items(prop, origin_items);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
static const EnumPropertyItem plane_orientation_items[] = {
{PLACE_ORIENT_SURFACE,
"SURFACE",
ICON_SNAP_NORMAL,
"Surface",
"Use the surface normal (the transform orientation as a fallback)"},
{PLACE_ORIENT_DEFAULT,
"DEFAULT",
ICON_ORIENTATION_GLOBAL,
"Default",
"Use the current transform orientation"},
{0, NULL, 0, NULL, NULL},
};
prop = RNA_def_property(ot->srna, "plane_orientation", PROP_ENUM, PROP_NONE);
RNA_def_property_ui_text(prop, "Orientation", "The initial depth used when placing the cursor");
RNA_def_property_enum_default(prop, PLACE_ORIENT_SURFACE);
RNA_def_property_enum_items(prop, plane_orientation_items);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* When not accessed via a tool. */
prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);