UI: View-Facing Mesh Select Option #109357

Open
Lukas Sneyd wants to merge 12 commits from lcas/blender:vfs into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
6 changed files with 583 additions and 29 deletions

View File

@ -157,7 +157,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
def draw(self, _context):
# layout = self.layout
@ -210,6 +210,39 @@ class VIEW3D_PT_tools_meshedit_options_transform(View3DPanel, Panel):
sub.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")
class VIEW3D_PT_tools_meshedit_options_uvs(View3DPanel, Panel):
bl_category = "Tool"
bl_context = ".mesh_edit" # dot on purpose (access from topbar)
@ -2374,6 +2407,7 @@ classes = (
VIEW3D_PT_tools_object_options_transform,
VIEW3D_PT_tools_meshedit_options,
VIEW3D_PT_tools_meshedit_options_transform,
VIEW3D_PT_tools_meshedit_options_viewport_facing_select,
VIEW3D_PT_tools_meshedit_options_uvs,
VIEW3D_PT_tools_armatureedit_options,
VIEW3D_PT_tools_posemode_options,

View File

@ -377,6 +377,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

@ -244,15 +244,217 @@ 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,
void edbm_vert_orientation(const BMVert *eve, float normal[3], float plane[3], float meshmat[3][3])
{
float vec[3] = {0.0, 0.0, 0.0};
float tangent[3] = {0.0f, 0.0f, 1.0f};
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);
copy_v3_v3(meshmat[2], normal);
cross_v3_v3v3(meshmat[0], meshmat[2], tangent);
if (is_zero_v3(meshmat[0])) {
tangent[0] = 1.0f;
tangent[1] = tangent[2] = 0.0f;
cross_v3_v3v3(meshmat[0], tangent, meshmat[2]);
}
cross_v3_v3v3(meshmat[1], meshmat[2], meshmat[0]);
}
void edbm_edge_orientation(const BMEdge *eed, float normal[3], float plane[3], float meshmat[3][3])
{
float eed_plane[3] = {0.0, 0.0, 0.0};
float vec[3] = {0.0, 0.0, 0.0};
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);
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);
}
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 normal[3] = {0, 0, 0};
float plane[3] = {0, 0, 0};
float meshcol3[3] = {0, 0, 0};
float viewcol3[3] = {0, 0, 0};
float meshmat[3][3] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
int direction = eve != NULL ? ts->viewport_facing_select_vert :
eed != NULL ? ts->viewport_facing_select_edge :
ts->viewport_facing_select_face;
bool backface = use_direction && (direction == 4 || direction == 8);
if (eve != NULL) {
edbm_vert_orientation(eve, normal, plane, meshmat);
}
else {
if (eed != NULL) {
edbm_edge_orientation(eed, normal, plane, meshmat);
}
else if (efa != NULL) {
copy_v3_v3(normal, efa->no);
BM_face_calc_tangent_auto(efa, plane);
}
normalize_v3_v3(meshmat[2], normal);
negate_v3_v3(meshmat[1], plane);
if (is_zero_v3(meshmat[1])) {
meshmat[1][2] = 1.0f;
}
cross_v3_v3v3(meshmat[0], meshmat[2], meshmat[1]);
cross_v3_v3v3(meshmat[1], meshmat[2], meshmat[0]);
normalize_v3(meshmat[1]);
}
normalize_m3(meshmat);
invert_m3(meshmat);
meshcol3[0] = meshmat[0][2];
meshcol3[1] = meshmat[1][2];
meshcol3[2] = meshmat[2][2];
viewcol3[0] = vc->rv3d->viewmat[0][2];
viewcol3[1] = vc->rv3d->viewmat[1][2];
viewcol3[2] = vc->rv3d->viewmat[2][2];
bool mesh_facing = false;
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);
@ -265,7 +467,12 @@ static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel,
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;
@ -276,15 +483,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);
@ -297,7 +508,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;
@ -308,15 +524,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);
@ -329,7 +549,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;
@ -417,6 +642,7 @@ struct LassoSelectUserData {
int mcoords_len;
eSelectOp sel_op;
eBezTriple_Flag select_flag;
bool check_mesh_direction;
/* runtime */
int pass;
@ -719,7 +945,13 @@ static void do_lasso_select_mesh__doSelectVert(void *user_data,
(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;
@ -752,7 +984,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;
@ -780,7 +1018,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;
@ -798,7 +1042,13 @@ static void do_lasso_select_mesh__doSelectFace(void *user_data,
(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;
@ -849,9 +1099,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);
}
@ -867,6 +1119,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);
@ -883,9 +1143,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);
}
@ -3457,6 +3719,7 @@ struct BoxSelectUserData {
rctf _rect_fl;
eSelectOp sel_op;
eBezTriple_Flag select_flag;
bool check_mesh_direction;
/* runtime */
bool is_done;
@ -3718,7 +3981,13 @@ static void do_mesh_box_select__doSelectVert(void *user_data,
BoxSelectUserData *data = static_cast<BoxSelectUserData *>(user_data);
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;
@ -3750,7 +4019,13 @@ static void do_mesh_box_select__doSelectEdge_pass0(void *user_data,
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;
@ -3777,7 +4052,13 @@ static void do_mesh_box_select__doSelectEdge_pass1(void *user_data,
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;
@ -3791,7 +4072,13 @@ static void do_mesh_box_select__doSelectFace(void *user_data,
BoxSelectUserData *data = static_cast<BoxSelectUserData *>(user_data);
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;
@ -3834,9 +4121,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);
}
@ -3852,6 +4141,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);
@ -3868,9 +4165,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);
}
@ -4388,6 +4687,7 @@ struct CircleSelectUserData {
float radius;
float radius_squared;
eBezTriple_Flag select_flag;
bool check_mesh_direction;
/* runtime */
bool is_changed;
@ -4423,8 +4723,15 @@ static void mesh_circle_doSelectVert(void *user_data,
CircleSelectUserData *data = static_cast<CircleSelectUserData *>(user_data);
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 *user_data,
@ -4436,8 +4743,15 @@ static void mesh_circle_doSelectEdge(void *user_data,
CircleSelectUserData *data = static_cast<CircleSelectUserData *>(user_data);
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 *user_data,
@ -4448,8 +4762,15 @@ static void mesh_circle_doSelectFace(void *user_data,
CircleSelectUserData *data = static_cast<CircleSelectUserData *>(user_data);
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;
}
}
}
@ -4499,10 +4820,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);
}
}
@ -4511,10 +4834,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,
@ -4527,10 +4852,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

@ -398,6 +398,12 @@
/* Placement */ \
.snap_mode_tools = SCE_SNAP_TO_GEOM,\
.plane_axis = 2,\
\
/* Viewport-Facing Select */ \
.viewport_facing_select_mode = 1, \
.viewport_facing_select_vert = 1, \
.viewport_facing_select_edge = 1, \
.viewport_facing_select_face = 1, \
}
#define _DNA_DEFAULT_Sculpt \

View File

@ -1585,7 +1585,15 @@ typedef struct ToolSettings {
char gpencil_v3d_align;
/** General 2D Editor. */
char gpencil_v2d_align;
char _pad0[2];
/* Viewport-Facing 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. */
@ -2421,6 +2429,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 */
enum {
SCE_SELECT_VERTEX = 1 << 0, /* for mesh */

View File

@ -3101,6 +3101,108 @@ static void rna_def_tool_settings(BlenderRNA *brna)
{0, nullptr, 0, nullptr, nullptr},
};
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", nullptr);
RNA_def_struct_path_func(srna, "rna_ToolSettings_path");
RNA_def_struct_ui_text(srna, "Tool Settings", "");
@ -3829,6 +3931,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);
/* Viewport-Facing Select */
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.999999, 0.999999);
RNA_def_property_ui_range(prop, -0.999999, 0.999999, 1.0, 6);
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);