WIP: Viewport-Facing Mesh Select #106531

Closed
Lukas Sneyd wants to merge 1 commits from lcas:viewport-facing-mesh-select into blender-v3.5-release

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
9 changed files with 657 additions and 53 deletions

View File

@ -153,7 +153,7 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
bl_context = ".mesh_edit" # dot on purpose (access from topbar)
bl_label = "Options"
bl_options = {'DEFAULT_CLOSED'}
bl_ui_units_x = 12
bl_ui_units_x = 13
@classmethod
def poll(cls, context):
@ -220,6 +220,39 @@ class VIEW3D_PT_tools_meshedit_options_automerge(View3DPanel, Panel):
col.prop(tool_settings, "double_threshold", text="Threshold")
class VIEW3D_PT_tools_meshedit_options_viewport_facing_select(View3DPanel, Panel):
bl_category = "Tool"
bl_context = ".mesh_edit" # dot on purpose (access from topbar)
bl_label = "Viewport Facing Select"
bl_parent_id = "VIEW3D_PT_tools_meshedit_options"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return context.active_object
def draw_header(self, context):
tool_settings = context.tool_settings
self.layout.prop(tool_settings, "viewport_facing_select", text="", toggle=False)
def draw(self, context):
layout = self.layout
tool_settings = context.tool_settings
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column(align=True)
col.active = tool_settings.viewport_facing_select
col.prop(tool_settings, "viewport_facing_select_mode")
col.prop(tool_settings, "viewport_facing_select_threshold", text="Threshold")
col.prop(tool_settings, "viewport_facing_select_vert")
col.prop(tool_settings, "viewport_facing_select_edge")
col.prop(tool_settings, "viewport_facing_select_face")
# ********** default tools for editmode_armature ****************
@ -2364,6 +2397,7 @@ classes = (
VIEW3D_PT_tools_object_options_transform,
VIEW3D_PT_tools_meshedit_options,
VIEW3D_PT_tools_meshedit_options_automerge,
VIEW3D_PT_tools_meshedit_options_viewport_facing_select,
VIEW3D_PT_tools_armatureedit_options,
VIEW3D_PT_tools_posemode_options,

View File

@ -373,6 +373,12 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
if (idprop) {
IDP_ClearProperty(idprop);
}
/* Viewport-Facing Select */
ts->viewport_facing_select_mode = 1;
ts->viewport_facing_select_vert = 1;
ts->viewport_facing_select_edge = 1;
ts->viewport_facing_select_face = 1;
}
void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)

View File

@ -100,7 +100,10 @@ void ED_getTransformOrientationMatrix(const struct Scene *scene,
struct Object *ob,
struct Object *obedit,
short around,
float r_orientation_mat[3][3]);
float r_orientation_mat[3][3],
struct BMVert *eve,
struct BMEdge *eed,
struct BMFace *efa);
int BIF_countTransformOrientation(const struct bContext *C);

View File

@ -1192,7 +1192,7 @@ static int view_axis_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
/* same as transform gizmo when normal is set */
ED_getTransformOrientationMatrix(
scene, view_layer, v3d, obact, obedit, V3D_AROUND_ACTIVE, twmat);
scene, view_layer, v3d, obact, obedit, V3D_AROUND_ACTIVE, twmat, NULL, NULL, NULL);
align_quat = align_quat_buf;
mat3_to_quat(align_quat, twmat);
invert_qt_normalized(align_quat);

View File

@ -80,6 +80,7 @@
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_select_utils.h"
#include "ED_transform.h"
#include "UI_interface.h"
#include "UI_resources.h"
@ -239,28 +240,197 @@ static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *w
/** \name Internal Edit-Mesh Utilities
* \{ */
static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel,
bool edbm_normal_facing_viewport(ViewContext *vc,
struct BMVert *eve,
struct BMEdge *eed,
struct BMFace *efa,
bool use_direction)
{
ToolSettings *ts = vc->scene->toolsettings;
float meshmat[3][3];
bool backface = false;
int direction = 0;
if (eve != NULL) {
ED_getTransformOrientationMatrix(vc->scene,
vc->view_layer,
vc->v3d,
vc->obact,
vc->obedit,
V3D_AROUND_ACTIVE,
meshmat,
eve,
NULL,
NULL);
direction = ts->viewport_facing_select_vert;
if (use_direction && (direction == 4 || direction == 8)) {
backface = true;
}
}
else if (eed != NULL) {
ED_getTransformOrientationMatrix(vc->scene,
vc->view_layer,
vc->v3d,
vc->obact,
vc->obedit,
V3D_AROUND_ACTIVE,
meshmat,
NULL,
eed,
NULL);
direction = ts->viewport_facing_select_edge;
if (use_direction && (direction == 4 || direction == 8)) {
backface = true;
}
}
else if (efa != NULL) {
ED_getTransformOrientationMatrix(vc->scene,
vc->view_layer,
vc->v3d,
vc->obact,
vc->obedit,
V3D_AROUND_ACTIVE,
meshmat,
NULL,
NULL,
efa);
direction = ts->viewport_facing_select_face;
if (use_direction && (direction == 4 || direction == 8)) {
backface = true;
}
}
normalize_m3(meshmat);
invert_m3(meshmat);
float meshcol3[3] = {0, 0, 0};
meshcol3[0] = meshmat[0][2];
meshcol3[1] = meshmat[1][2];
meshcol3[2] = meshmat[2][2];
float viewcol3[3] = {0, 0, 0};
viewcol3[0] = vc->rv3d->viewmat[0][2];
viewcol3[1] = vc->rv3d->viewmat[1][2];
viewcol3[2] = vc->rv3d->viewmat[2][2];
bool mesh_facing;
if (backface) {
mesh_facing = dot_v3v3(meshcol3, viewcol3) < -ts->viewport_facing_select_threshold;
}
else {
mesh_facing = dot_v3v3(meshcol3, viewcol3) > ts->viewport_facing_select_threshold;
}
return mesh_facing;
}
bool edbm_facing_viewport_precheck(ToolSettings *ts, int style, bool xray)
{
if (!ts->viewport_facing_select) {
return false;
}
const bool mode_match = xray ? ts->viewport_facing_select_mode == 1 ||
ts->viewport_facing_select_mode == 4 :
ts->viewport_facing_select_mode < 4;
const bool check_mesh_facing = mode_match && style > 0 && style < 16;
return check_mesh_facing;
}
bool edbm_facing_viewport(ViewContext *vc, BMVert *eve, BMEdge *eed, BMFace *efa, int style)
{
BMIter iter;
bool mesh_facing = false;
if (eve != NULL) {
/* viewport-facing or rear-facing vert */
mesh_facing = edbm_normal_facing_viewport(vc, eve, NULL, NULL, true);
if (!mesh_facing && eve->e && eve->e->l && (style == 2 || style == 8)) {
BM_ITER_ELEM (efa, &iter, eve, BM_FACES_OF_VERT) {
const bool eve_efa_facing = edbm_normal_facing_viewport(vc, NULL, NULL, efa, false);
/* vert of a viewport-facing face */
if (style == 2) {
if (eve_efa_facing) {
mesh_facing = true;
break;
}
}
/* vert of a rear-facing face */
else if (!eve_efa_facing) {
mesh_facing = true;
break;
}
}
}
}
else if (eed != NULL) {
/* viewport-facing or rear-facing edge */
mesh_facing = edbm_normal_facing_viewport(vc, NULL, eed, NULL, true);
if (!mesh_facing && eed->l && (style == 2 || style == 8)) {
BM_ITER_ELEM (efa, &iter, eed, BM_FACES_OF_EDGE) {
const bool eed_efa_facing = edbm_normal_facing_viewport(vc, NULL, NULL, efa, false);
/* edge of a viewport-facing face */
if (style == 2) {
if (eed_efa_facing) {
mesh_facing = true;
break;
}
}
/* edge of a rear-facing face */
else if (!eed_efa_facing) {
mesh_facing = true;
break;
}
}
}
}
else if (efa != NULL) {
/* viewport-facing or rear-facing face */
mesh_facing = edbm_normal_facing_viewport(vc, NULL, NULL, efa, true);
if (!mesh_facing && (style == 2 || style == 8)) {
BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) {
const bool efa_eve_facing = edbm_normal_facing_viewport(vc, eve, NULL, NULL, false);
/* face has a viewport-facing vert */
if (style == 2) {
if (efa_eve_facing) {
mesh_facing = true;
break;
}
}
/* face has a rear-facing vert */
else if (!efa_eve_facing) {
mesh_facing = true;
break;
}
}
}
}
return mesh_facing;
}
static bool edbm_backbuf_check_and_select_verts(ViewContext *vc,
EditSelectBuf_Cache *esel,
Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
const eSelectOp sel_op)
{
ToolSettings *ts = vc->scene->toolsettings;
BMVert *eve;
BMIter iter;
bool changed = false;
const int style = ts->viewport_facing_select_vert;
const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false);
const BLI_bitmap *select_bitmap = esel->select_bitmap;
uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_VERTEX);
if (index == 0) {
return false;
}
index -= 1;
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && check_mesh_facing) {
mesh_facing = edbm_facing_viewport(vc, eve, NULL, NULL, style);
}
const int sel_op_result = ED_select_op_action_deselected(
sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_vert_select_set(em->bm, eve, sel_op_result);
changed = true;
@ -271,15 +441,19 @@ static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel,
return changed;
}
static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel,
static bool edbm_backbuf_check_and_select_edges(ViewContext *vc,
EditSelectBuf_Cache *esel,
Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
const eSelectOp sel_op)
{
ToolSettings *ts = vc->scene->toolsettings;
BMEdge *eed;
BMIter iter;
bool changed = false;
const int style = ts->viewport_facing_select_edge;
const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false);
const BLI_bitmap *select_bitmap = esel->select_bitmap;
uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_EDGE);
@ -292,7 +466,12 @@ static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel,
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && check_mesh_facing) {
mesh_facing = edbm_facing_viewport(vc, NULL, eed, NULL, style);
}
const int sel_op_result = ED_select_op_action_deselected(
sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_edge_select_set(em->bm, eed, sel_op_result);
changed = true;
@ -303,15 +482,19 @@ static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel,
return changed;
}
static bool edbm_backbuf_check_and_select_faces(EditSelectBuf_Cache *esel,
static bool edbm_backbuf_check_and_select_faces(ViewContext *vc,
EditSelectBuf_Cache *esel,
Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
const eSelectOp sel_op)
{
ToolSettings *ts = vc->scene->toolsettings;
BMFace *efa;
BMIter iter;
bool changed = false;
const int style = ts->viewport_facing_select_face;
const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false);
const BLI_bitmap *select_bitmap = esel->select_bitmap;
uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_FACE);
@ -324,7 +507,12 @@ static bool edbm_backbuf_check_and_select_faces(EditSelectBuf_Cache *esel,
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && check_mesh_facing) {
mesh_facing = edbm_facing_viewport(vc, NULL, NULL, efa, style);
}
const int sel_op_result = ED_select_op_action_deselected(
sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_face_select_set(em->bm, efa, sel_op_result);
changed = true;
@ -412,6 +600,7 @@ struct LassoSelectUserData {
int mcoords_len;
eSelectOp sel_op;
eBezTriple_Flag select_flag;
bool check_mesh_direction;
/* runtime */
int pass;
@ -711,7 +900,13 @@ static void do_lasso_select_mesh__doSelectVert(void *userData,
(BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
BLI_lasso_is_point_inside(
data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, eve, NULL, NULL, data->vc->scene->toolsettings->viewport_facing_select_vert);
}
const int sel_op_result = ED_select_op_action_deselected(
data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
data->is_changed = true;
@ -744,7 +939,13 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data,
data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) &&
BLI_lasso_is_point_inside(
data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge);
}
const int sel_op_result = ED_select_op_action_deselected(
data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
data->is_done = true;
@ -772,7 +973,13 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data,
UNPACK2(screen_co_a),
UNPACK2(screen_co_b),
IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge);
}
const int sel_op_result = ED_select_op_action_deselected(
data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
data->is_changed = true;
@ -790,7 +997,13 @@ static void do_lasso_select_mesh__doSelectFace(void *userData,
(BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
BLI_lasso_is_point_inside(
data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face);
}
const int sel_op_result = ED_select_op_action_deselected(
data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
data->is_changed = true;
@ -841,9 +1054,11 @@ static bool do_lasso_select_mesh(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (use_zbuf) {
data.is_changed |= edbm_backbuf_check_and_select_verts(
esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
}
else {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_vert, true);
mesh_foreachScreenVert(
vc, do_lasso_select_mesh__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
@ -859,6 +1074,14 @@ static bool do_lasso_select_mesh(ViewContext *vc,
const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
(use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB);
if (use_zbuf) {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_edge, false);
}
else {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_edge, true);
}
/* Fully inside. */
mesh_foreachScreenEdge_clip_bb_segment(
vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag);
@ -875,9 +1098,11 @@ static bool do_lasso_select_mesh(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_FACE) {
if (use_zbuf) {
data.is_changed |= edbm_backbuf_check_and_select_faces(
esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
}
else {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_face, true);
mesh_foreachScreenFace(
vc, do_lasso_select_mesh__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
@ -3231,6 +3456,7 @@ struct BoxSelectUserData {
rctf _rect_fl;
eSelectOp sel_op;
eBezTriple_Flag select_flag;
bool check_mesh_direction;
/* runtime */
bool is_done;
@ -3492,7 +3718,13 @@ static void do_mesh_box_select__doSelectVert(void *userData,
BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData);
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, eve, NULL, NULL, data->vc->scene->toolsettings->viewport_facing_select_vert);
}
const int sel_op_result = ED_select_op_action_deselected(
data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
data->is_changed = true;
@ -3521,7 +3753,13 @@ static void do_mesh_box_select__doSelectEdge_pass0(
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside = (is_visible &&
edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge);
}
const int sel_op_result = ED_select_op_action_deselected(
data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
data->is_done = true;
@ -3545,7 +3783,13 @@ static void do_mesh_box_select__doSelectEdge_pass1(
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside = (is_visible && edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge);
}
const int sel_op_result = ED_select_op_action_deselected(
data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
data->is_changed = true;
@ -3559,7 +3803,13 @@ static void do_mesh_box_select__doSelectFace(void *userData,
BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData);
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
bool mesh_facing = true;
if (is_inside && data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face);
}
const int sel_op_result = ED_select_op_action_deselected(
data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
data->is_changed = true;
@ -3602,9 +3852,11 @@ static bool do_mesh_box_select(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (use_zbuf) {
data.is_changed |= edbm_backbuf_check_and_select_verts(
esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
}
else {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_vert, true);
mesh_foreachScreenVert(
vc, do_mesh_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
@ -3621,6 +3873,14 @@ static bool do_mesh_box_select(ViewContext *vc,
const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
(use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB);
if (use_zbuf) {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_edge, false);
}
else {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_edge, true);
}
/* Fully inside. */
mesh_foreachScreenEdge_clip_bb_segment(
vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag);
@ -3637,9 +3897,11 @@ static bool do_mesh_box_select(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_FACE) {
if (use_zbuf) {
data.is_changed |= edbm_backbuf_check_and_select_faces(
esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
}
else {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_face, true);
mesh_foreachScreenFace(
vc, do_mesh_box_select__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
@ -4106,6 +4368,7 @@ struct CircleSelectUserData {
float radius;
float radius_squared;
eBezTriple_Flag select_flag;
bool check_mesh_direction;
/* runtime */
bool is_changed;
@ -4141,8 +4404,15 @@ static void mesh_circle_doSelectVert(void *userData,
CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
BM_vert_select_set(data->vc->em->bm, eve, data->select);
data->is_changed = true;
bool mesh_facing = true;
if (data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, eve, NULL, NULL, data->vc->scene->toolsettings->viewport_facing_select_vert);
}
if (mesh_facing) {
BM_vert_select_set(data->vc->em->bm, eve, data->select);
data->is_changed = true;
}
}
}
static void mesh_circle_doSelectEdge(void *userData,
@ -4154,8 +4424,15 @@ static void mesh_circle_doSelectEdge(void *userData,
CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
BM_edge_select_set(data->vc->em->bm, eed, data->select);
data->is_changed = true;
bool mesh_facing = true;
if (data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge);
}
if (mesh_facing) {
BM_edge_select_set(data->vc->em->bm, eed, data->select);
data->is_changed = true;
}
}
}
static void mesh_circle_doSelectFace(void *userData,
@ -4166,8 +4443,15 @@ static void mesh_circle_doSelectFace(void *userData,
CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
BM_face_select_set(data->vc->em->bm, efa, data->select);
data->is_changed = true;
bool mesh_facing = true;
if (data->check_mesh_direction) {
mesh_facing = edbm_facing_viewport(
data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face);
}
if (mesh_facing) {
BM_face_select_set(data->vc->em->bm, efa, data->select);
data->is_changed = true;
}
}
}
@ -4217,10 +4501,12 @@ static bool mesh_circle_select(ViewContext *vc,
if (use_zbuf) {
if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_verts(
esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
vc, esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
}
else {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_vert, true);
mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
}
@ -4229,10 +4515,12 @@ static bool mesh_circle_select(ViewContext *vc,
if (use_zbuf) {
if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_edges(
esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
vc, esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
}
else {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_edge, true);
mesh_foreachScreenEdge_clip_bb_segment(
vc,
mesh_circle_doSelectEdge,
@ -4245,10 +4533,12 @@ static bool mesh_circle_select(ViewContext *vc,
if (use_zbuf) {
if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_faces(
esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
vc, esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
}
else {
data.check_mesh_direction = edbm_facing_viewport_precheck(
ts, ts->viewport_facing_select_face, true);
mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
}

View File

@ -516,7 +516,8 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
}
case V3D_ORIENT_NORMAL: {
if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat);
ED_getTransformOrientationMatrix(
scene, view_layer, v3d, ob, obedit, pivot_point, r_mat, NULL, NULL, NULL);
break;
}
/* No break we define 'normal' as 'local' in Object mode. */
@ -529,7 +530,8 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
* use the active pones axis for display #33575, this works as expected on a single
* bone and users who select many bones will understand what's going on and what local
* means when they start transforming. */
ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat);
ED_getTransformOrientationMatrix(
scene, view_layer, v3d, ob, obedit, pivot_point, r_mat, NULL, NULL, NULL);
}
else {
transform_orientations_create_from_axis(r_mat, UNPACK3(ob->object_to_world));
@ -752,13 +754,18 @@ int getTransformOrientation_ex(const Scene *scene,
struct Object *obedit,
float normal[3],
float plane[3],
const short around)
const short around,
struct BMVert *eve,
struct BMEdge *eed,
struct BMFace *efa)
{
int result = ORIENTATION_NONE;
const bool activeOnly = (around == V3D_AROUND_ACTIVE);
zero_v3(normal);
zero_v3(plane);
if (efa == NULL && eed == NULL) {
zero_v3(normal);
zero_v3(plane);
}
if (obedit) {
float imat[3][3], mat[3][3];
@ -777,20 +784,72 @@ int getTransformOrientation_ex(const Scene *scene,
float vec[3] = {0, 0, 0};
/* USE LAST SELECTED WITH ACTIVE */
if (activeOnly && BM_select_history_active_get(em->bm, &ese)) {
BM_editselection_normal(&ese, normal);
BM_editselection_plane(&ese, plane);
if (efa != NULL || eed != NULL || eve != NULL ||
activeOnly && BM_select_history_active_get(em->bm, &ese)) {
if (efa != NULL) {
copy_v3_v3(normal, efa->no);
BM_face_calc_tangent_auto(efa, plane);
result = ORIENTATION_FACE;
}
else if (eed != NULL) {
float eed_plane[3];
float vec[3];
add_v3_v3v3(normal, eed->v1->no, eed->v2->no);
sub_v3_v3v3(eed_plane, eed->v2->co, eed->v1->co);
cross_v3_v3v3(vec, normal, eed_plane);
cross_v3_v3v3(normal, eed_plane, vec);
normalize_v3(normal);
switch (ese.htype) {
case BM_VERT:
result = ORIENTATION_VERT;
break;
case BM_EDGE:
result = ORIENTATION_EDGE;
break;
case BM_FACE:
result = ORIENTATION_FACE;
break;
if (BM_edge_is_boundary(eed)) {
sub_v3_v3v3(plane, eed->l->v->co, eed->l->next->v->co);
}
else {
if (eed->v2->co[1] > eed->v1->co[1]) {
sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
}
else {
sub_v3_v3v3(plane, eed->v1->co, eed->v2->co);
}
}
normalize_v3(plane);
result = ORIENTATION_EDGE;
}
else if (eve != NULL) {
copy_v3_v3(normal, eve->no);
if (eve->e) {
float vert1v3[3] = {eve->e->v1->co[0], eve->e->v1->co[1], eve->e->v1->co[2]};
float vert2v3[3] = {eve->e->v2->co[0], eve->e->v2->co[1], eve->e->v2->co[2]};
sub_v3_v3v3(plane, vert2v3, vert1v3);
}
else {
if (eve->no[0] < 0.5f) {
vec[0] = 1.0f;
}
else if (eve->no[1] < 0.5f) {
vec[1] = 1.0f;
}
else {
vec[2] = 1.0f;
}
cross_v3_v3v3(plane, eve->no, vec);
}
normalize_v3(plane);
result = ORIENTATION_VERT;
}
else {
BM_editselection_normal(&ese, normal);
BM_editselection_plane(&ese, plane);
switch (ese.htype) {
case BM_VERT:
result = ORIENTATION_VERT;
break;
case BM_EDGE:
result = ORIENTATION_EDGE;
break;
case BM_FACE:
result = ORIENTATION_FACE;
break;
}
}
}
else {
@ -1289,7 +1348,8 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3])
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
return getTransformOrientation_ex(scene, view_layer, v3d, obact, obedit, normal, plane, around);
return getTransformOrientation_ex(
scene, view_layer, v3d, obact, obedit, normal, plane, around, NULL, NULL, NULL);
}
void ED_getTransformOrientationMatrix(const Scene *scene,
@ -1298,14 +1358,32 @@ void ED_getTransformOrientationMatrix(const Scene *scene,
Object *ob,
Object *obedit,
const short around,
float r_orientation_mat[3][3])
float r_orientation_mat[3][3],
struct BMVert *eve,
struct BMEdge *eed,
struct BMFace *efa)
{
float normal[3] = {0.0, 0.0, 0.0};
float plane[3] = {0.0, 0.0, 0.0};
int type;
type = getTransformOrientation_ex(scene, view_layer, v3d, ob, obedit, normal, plane, around);
if (efa != NULL) {
type = getTransformOrientation_ex(
scene, view_layer, v3d, ob, obedit, normal, plane, around, NULL, NULL, efa);
}
else if (eed != NULL) {
type = getTransformOrientation_ex(
scene, view_layer, v3d, ob, obedit, normal, plane, around, NULL, eed, NULL);
}
else if (eve != NULL) {
type = getTransformOrientation_ex(
scene, view_layer, v3d, ob, obedit, normal, plane, around, eve, NULL, NULL);
}
else {
type = getTransformOrientation_ex(
scene, view_layer, v3d, ob, obedit, normal, plane, around, NULL, NULL, NULL);
}
/* Fallback, when the plane can't be calculated. */
if (ORIENTATION_USE_PLANE(type) && is_zero_v3(plane)) {

View File

@ -366,6 +366,12 @@
/* UV painting */ \
.uv_sculpt_settings = 0, \
.uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN, \
\
/* Viewport-Facing Select */ \
.viewport_facing_select_mode = 1, \
.viewport_facing_select_vert = 1, \
.viewport_facing_select_edge = 1, \
.viewport_facing_select_face = 1, \
}
/* clang-format off */

View File

@ -1557,7 +1557,15 @@ typedef struct ToolSettings {
char gpencil_v3d_align;
/** General 2D Editor. */
char gpencil_v2d_align;
char _pad0[2];
/* Mesh Normal Direction Select */
char viewport_facing_select;
char viewport_facing_select_mode;
char _pad0[1];
float viewport_facing_select_threshold;
char viewport_facing_select_vert;
char viewport_facing_select_edge;
char viewport_facing_select_face;
/* Annotations. */
/** Stroke placement settings - 3D View. */
@ -2331,6 +2339,40 @@ typedef enum eSnapTransformMode {
SCE_SNAP_TRANSFORM_MODE_SCALE = (1 << 2),
} eSnapTransformMode;
/** #ToolSettings.viewport_facing_mode */
enum {
VIEWPORT_FACING_SELECT_BOTH = (1 << 0),
VIEWPORT_FACING_SELECT_NEAR = (1 << 1),
VIEWPORT_FACING_SELECT_XRAY = (1 << 2),
};
/** #ToolSettings.viewport_facing_select_vert */
enum {
VIEWPORT_FACING_SELECT_FRONT_VERTS = (1 << 0),
VIEWPORT_FACING_SELECT_FRONT_VERTS_FACE = (1 << 1),
VIEWPORT_FACING_SELECT_REAR_VERTS = (1 << 2),
VIEWPORT_FACING_SELECT_REAR_VERTS_FACE = (1 << 3),
VIEWPORT_FACING_SELECT_ALL_VERTS = (1 << 4),
};
/** #ToolSettings.viewport_facing_select_edge */
enum {
VIEWPORT_FACING_SELECT_FRONT_EDGES = (1 << 0),
VIEWPORT_FACING_SELECT_FRONT_EDGES_FACE = (1 << 1),
VIEWPORT_FACING_SELECT_REAR_EDGES = (1 << 2),
VIEWPORT_FACING_SELECT_REAR_EDGES_FACE = (1 << 3),
VIEWPORT_FACING_SELECT_ALL_EDGES = (1 << 4),
};
/** #ToolSettings.viewport_facing_select_face */
enum {
VIEWPORT_FACING_SELECT_FRONT_FACES = (1 << 0),
VIEWPORT_FACING_SELECT_FRONT_FACES_VERT = (1 << 1),
VIEWPORT_FACING_SELECT_REAR_FACES = (1 << 2),
VIEWPORT_FACING_SELECT_REAR_FACES_VERT = (1 << 3),
VIEWPORT_FACING_SELECT_ALL_FACES = (1 << 4),
};
/** #ToolSettings.selectmode */
#define SCE_SELECT_VERTEX (1 << 0) /* for mesh */
#define SCE_SELECT_EDGE (1 << 1)

View File

@ -3049,6 +3049,112 @@ static void rna_def_tool_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem viewport_facing_select_mode_items[] = {
{VIEWPORT_FACING_SELECT_BOTH,
"BOTH",
0,
"Near and X-Ray",
"Use viewport-facing selection in near select and X-Ray"},
{VIEWPORT_FACING_SELECT_NEAR,
"NEAR",
0,
"Near",
"Use viewport-facing selection in near select"},
{VIEWPORT_FACING_SELECT_XRAY,
"XRAY",
0,
"X-Ray",
"Use viewport-facing selection in X-Ray"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem viewport_facing_select_vert_items[] = {
{VIEWPORT_FACING_SELECT_FRONT_VERTS,
"FRONT_VERTS",
0,
"Front Verts",
"Select vertices with viewport-facing normals"},
{VIEWPORT_FACING_SELECT_FRONT_VERTS_FACE,
"FRONT_VERTS_FACE",
0,
"Verts of Front Face",
"Select vertices if they are part of a face that has a viewport-facing normal"},
{VIEWPORT_FACING_SELECT_REAR_VERTS,
"REAR_VERTS",
0,
"Rear Verts",
"Select vertices without viewport-facing normals"},
{VIEWPORT_FACING_SELECT_REAR_VERTS_FACE,
"REAR_VERTS_FACE",
0,
"Verts of Rear Face",
"Select vertices if they are part of a face that does not have a viewport-facing normal"},
{VIEWPORT_FACING_SELECT_ALL_VERTS,
"ALL_VERTS",
0,
"All Verts",
"Select vertices regarless of their normal direction"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem viewport_facing_select_edge_items[] = {
{VIEWPORT_FACING_SELECT_FRONT_EDGES,
"FRONT_EDGES",
0,
"Front Edges",
"Select edges with viewport-facing normals"},
{VIEWPORT_FACING_SELECT_FRONT_EDGES_FACE,
"FRONT_EDGES_FACE",
0,
"Edges of Front Face",
"Select edges if they are part of a face that has a viewport-facing normal"},
{VIEWPORT_FACING_SELECT_REAR_EDGES,
"REAR_EDGES",
0,
"Rear Edges",
"Select edges without viewport-facing normals"},
{VIEWPORT_FACING_SELECT_REAR_EDGES_FACE,
"REAR_EDGES_FACE",
0,
"Edges of Rear Face",
"Select edges if they are part of a face that does not have a viewport-facing normal"},
{VIEWPORT_FACING_SELECT_ALL_EDGES,
"ALL_EDGES",
0,
"All Edges",
"Select edges regarless of their normal direction"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem viewport_facing_select_face_items[] = {
{VIEWPORT_FACING_SELECT_FRONT_FACES,
"FRONT_FACES",
0,
"Front Faces",
"Select faces with viewport-facing normals"},
{VIEWPORT_FACING_SELECT_FRONT_FACES_VERT,
"FRONT_FACES_VERT",
0,
"Faces of Front Vert",
"Select faces if they have a vertex with a viewport-facing normal"},
{VIEWPORT_FACING_SELECT_REAR_FACES,
"REAR_FACES",
0,
"Rear Faces",
"Select faces without viewport-facing normals"},
{VIEWPORT_FACING_SELECT_REAR_FACES_VERT,
"REAR_FACES_VERT",
0,
"Faces of Rear Vert",
"Select faces if they have a vertex without a viewport-facing normal"},
{VIEWPORT_FACING_SELECT_ALL_FACES,
"ALL_FACES",
0,
"All Faces",
"Select faces regarless of their normal direction"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "ToolSettings", NULL);
RNA_def_struct_path_func(srna, "rna_ToolSettings_path");
RNA_def_struct_ui_text(srna, "Tool Settings", "");
@ -3725,6 +3831,43 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Normal Vector", "Normal Vector used to copy, add or multiply");
RNA_def_property_ui_range(prop, -10000.0, 10000.0, 1, 3);
prop = RNA_def_property(srna, "viewport_facing_select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "viewport_facing_select", 0);
RNA_def_property_ui_text(
prop,
"Viewport Facing Select",
"Filter box, lasso, and circle selection of mesh elements based on the direction of their "
"normals compared to the viewport");
prop = RNA_def_property(srna, "viewport_facing_select_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_mode");
RNA_def_property_enum_items(prop, viewport_facing_select_mode_items);
RNA_def_property_ui_text(
prop, "Mode", "Which selection modes to use viewport-facing selection");
prop = RNA_def_property(srna, "viewport_facing_select_vert", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_vert");
RNA_def_property_enum_items(prop, viewport_facing_select_vert_items);
RNA_def_property_ui_text(prop, "Vert", "Direction and mode for vertices");
prop = RNA_def_property(srna, "viewport_facing_select_edge", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_edge");
RNA_def_property_enum_items(prop, viewport_facing_select_edge_items);
RNA_def_property_ui_text(prop, "Edge", "Direction and mode for edges");
prop = RNA_def_property(srna, "viewport_facing_select_face", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_face");
RNA_def_property_enum_items(prop, viewport_facing_select_face_items);
RNA_def_property_ui_text(prop, "Face", "Direction and mode for faces");
prop = RNA_def_property(srna, "viewport_facing_select_threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1.0f, 2);
RNA_def_property_ui_text(
prop,
"Threshold",
"How close the angles of the viewport and mesh element need to be for selection to occur");
/* Unified Paint Settings */
prop = RNA_def_property(srna, "unified_paint_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@ -3800,6 +3943,8 @@ static void rna_def_sequencer_tool_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "SequencerToolSettings", NULL);
RNA_def_struct_path_func(srna, "rna_SequencerToolSettings_path");
RNA_def_struct_ui_text(srna, "Sequencer Tool Settings", "");