Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2017-03-08 21:17:55 +0300
committerCampbell Barton <ideasman42@gmail.com>2017-03-08 22:22:02 +0300
commit45b764e95b9e34cb17dece1cd37eb80dafa1924f (patch)
treeeb5507c581ae586a20b4585693b694859827fa00 /source/blender/editors
parent817e975dee27640947bf7d083db39d1d70120385 (diff)
3D View: new nethod of opengl selection
Intended to replace legacy GL_SELECT, without the limitations of sample queries which can't access depth information. This commit adds VIEW3D_SELECT_PICK_NEAREST and VIEW3D_SELECT_PICK_ALL which access the depth buffers to detect whats under the pointer, so initial selection is always the closest item. The performance of this method depends a lot on the OpenGL implementations glReadPixels. Since reading depth can be slow, buffers are cached for object picking so selecting re-uses depth data, performing 1 draw instead of 3 (for 24, 18, 10 px regions, picking with many items under the pointer). Occlusion queries draw twice when picking nearest, so worst case 6x draw calls per selection. Even with these improvements occlusion queries is faster on AMD hardware. Depth selection is disabled by default, toggle option under select method. May enable by default if this works well on different hardware. Reviewed as D2543
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/armature/armature_select.c32
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c2
-rw-r--r--source/blender/editors/include/ED_view3d.h14
-rw-r--r--source/blender/editors/metaball/mball_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c61
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c57
6 files changed, 128 insertions, 40 deletions
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index ec0f193e780..3a0d07c02ee 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -177,7 +177,7 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
rect.xmin = rect.xmax = xy[0];
rect.ymin = rect.ymax = xy[1];
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
if (hits > 0)
return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel, true);
@@ -279,7 +279,7 @@ void ARMATURE_OT_select_linked(wmOperatorType *ot)
/* note that BONE ROOT only gets drawn for root bones (or without IK) */
static EditBone *get_nearest_editbonepoint(
ViewContext *vc, const int mval[2],
- ListBase *edbo, bool findunsel, int *r_selmask)
+ ListBase *edbo, bool findunsel, bool use_cycle, int *r_selmask)
{
bArmature *arm = (bArmature *)vc->obedit->data;
EditBone *ebone_next_act = arm->act_edbone;
@@ -290,6 +290,7 @@ static EditBone *get_nearest_editbonepoint(
unsigned int hitresult, besthitresult = BONESEL_NOSEL;
int i, mindep = 5;
short hits;
+ static int last_mval[2] = {-100, -100};
/* find the bone after the current active bone, so as to bump up its chances in selection.
* this way overlapping bones will cycle selection state as with objects. */
@@ -303,12 +304,33 @@ static EditBone *get_nearest_editbonepoint(
ebone_next_act = NULL;
}
+ bool do_nearest = false;
+
+ /* define if we use solid nearest select or not */
+ if (use_cycle) {
+ if (vc->v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
+ if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
+ do_nearest = false;
+ }
+ }
+ copy_v2_v2_int(last_mval, mval);
+ }
+ else {
+ if (vc->v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
+ }
+ }
+
+ const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
+
+ /* TODO: select larger region first (so we can use GPU_select_cache) */
BLI_rcti_init_pt_radius(&rect, mval, 5);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true);
if (hits == 0) {
BLI_rcti_init_pt_radius(&rect, mval, 12);
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
}
/* See if there are any selected bones in this group */
if (hits > 0) {
@@ -434,7 +456,7 @@ bool ED_armature_select_pick(bContext *C, const int mval[2], bool extend, bool d
return true;
}
- nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, true, &selmask);
+ nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, true, true, &selmask);
if (nearBone) {
if (!extend && !deselect && !toggle) {
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index 8690072ca85..bba486bc65c 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -1909,7 +1909,7 @@ static bool sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], c
BLI_rcti_init_pt_radius(&rect, mval, 5);
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
if (hits > 0) {
int besthitresult = -1;
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 5514dc0d3df..af6f37d937c 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -302,7 +302,19 @@ bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], con
/* select */
#define MAXPICKELEMS 2500
#define MAXPICKBUF (4 * MAXPICKELEMS)
-short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, bool do_nearest);
+
+enum {
+ /* all elements in the region, ignore depth */
+ VIEW3D_SELECT_ALL = 0,
+ /* pick also depth sorts (only for small regions!) */
+ VIEW3D_SELECT_PICK_ALL = 1,
+ /* sorts and only returns visible objects (only for small regions!) */
+ VIEW3D_SELECT_PICK_NEAREST = 2,
+};
+
+int view3d_opengl_select(
+ struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input,
+ int select_mode);
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index fff53d6885e..bc42717b69f 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -594,7 +594,7 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
BLI_rcti_init_pt_radius(&rect, mval, 12);
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
/* does startelem exist? */
ml = mb->editelems->first;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 49f24ef634f..0b3468f2c23 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -96,8 +96,12 @@
#include "GPU_draw.h"
+#include "GPU_select.h"
+
#include "view3d_intern.h" /* own include */
+// #include "PIL_time_utildefines.h"
+
float ED_view3d_select_dist_px(void)
{
return 75.0f * U.pixelsize;
@@ -1091,7 +1095,7 @@ static Base *object_mouse_select_menu(
bContext *C, ViewContext *vc, unsigned int *buffer, int hits,
const int mval[2], bool toggle)
{
- int baseCount = 0;
+ short baseCount = 0;
bool ok;
LinkNode *linklist = NULL;
@@ -1236,44 +1240,56 @@ static int mixed_bones_object_selectbuffer(
do_nearest = do_nearest && !enumerate;
+ const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
+ int hits = 0;
+
+ /* we _must_ end cache before return, use 'goto finally' */
+ GPU_select_cache_begin();
+
BLI_rcti_init_pt_radius(&rect, mval, 14);
- hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, do_nearest);
+ hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
if (hits15 == 1) {
- return selectbuffer_ret_hits_15(buffer, hits15);
+ hits = selectbuffer_ret_hits_15(buffer, hits15);
+ goto finally;
}
else if (hits15 > 0) {
has_bones15 = selectbuffer_has_bones(buffer, hits15);
offs = 4 * hits15;
BLI_rcti_init_pt_radius(&rect, mval, 9);
- hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
+ hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
if (hits9 == 1) {
- return selectbuffer_ret_hits_9(buffer, hits15, hits9);
+ hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
+ goto finally;
}
else if (hits9 > 0) {
has_bones9 = selectbuffer_has_bones(buffer + offs, hits9);
offs += 4 * hits9;
BLI_rcti_init_pt_radius(&rect, mval, 5);
- hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
+ hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
if (hits5 == 1) {
- return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
+ hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
+ goto finally;
}
else if (hits5 > 0) {
has_bones5 = selectbuffer_has_bones(buffer + offs, hits5);
}
}
- if (has_bones5) return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
- else if (has_bones9) return selectbuffer_ret_hits_9(buffer, hits15, hits9);
- else if (has_bones15) return selectbuffer_ret_hits_15(buffer, hits15);
-
- if (hits5 > 0) return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
- else if (hits9 > 0) return selectbuffer_ret_hits_9(buffer, hits15, hits9);
- else return selectbuffer_ret_hits_15(buffer, hits15);
+ if (has_bones5) { hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); goto finally; }
+ else if (has_bones9) { hits = selectbuffer_ret_hits_9(buffer, hits15, hits9); goto finally; }
+ else if (has_bones15) { hits = selectbuffer_ret_hits_15(buffer, hits15); goto finally; }
+
+ if (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); goto finally; }
+ else if (hits9 > 0) { hits = selectbuffer_ret_hits_9(buffer, hits15, hits9); goto finally; }
+ else { hits = selectbuffer_ret_hits_15(buffer, hits15); goto finally; }
}
-
- return 0;
+
+finally:
+ GPU_select_cache_end();
+
+ return hits;
}
/* returns basact */
@@ -1466,10 +1482,13 @@ static bool ed_object_select_pick(
unsigned int buffer[MAXPICKBUF];
bool do_nearest;
+ // TIMEIT_START(select_time);
+
/* if objects have posemode set, the bones are in the same selection buffer */
-
hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, true, enumerate, &do_nearest);
-
+
+ // TIMEIT_END(select_time);
+
if (hits > 0) {
/* note: bundles are handling in the same way as bones */
const bool has_bones = selectbuffer_has_bones(buffer, hits);
@@ -1908,7 +1927,7 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool ext
unsigned int buffer[MAXPICKBUF];
int hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
if (extend == false && select)
BKE_mball_deselect_all(mb);
@@ -1942,7 +1961,7 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
unsigned int buffer[MAXPICKBUF];
int hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
/* clear flag we use to detect point was affected */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next)
@@ -2039,7 +2058,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
/* selection buffer now has bones potentially too, so we add MAXPICKBUF */
vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(unsigned int), "selection buffer");
- hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, false);
+ hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL);
/*
* LOGIC NOTES (theeth):
* The buffer and ListBase have the same relative order, which makes the selection
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 20361b73e78..9d1a3633786 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -1170,18 +1170,24 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi
*
* \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
*/
-short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest)
+int view3d_opengl_select(
+ ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input,
+ int select_mode)
{
Scene *scene = vc->scene;
View3D *v3d = vc->v3d;
ARegion *ar = vc->ar;
rcti rect;
- short hits;
+ int hits;
const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL);
- const bool do_passes = do_nearest && GPU_select_query_check_active();
+ const bool is_pick_select = (U.gpu_select_pick_deph != 0);
+ const bool do_passes = (
+ (is_pick_select == false) &&
+ (select_mode == VIEW3D_SELECT_PICK_NEAREST) &&
+ GPU_select_query_check_active());
+
+ char gpu_select_mode;
- G.f |= G_PICKSEL;
-
/* case not a border select */
if (input->xmin == input->xmax) {
/* seems to be default value for bones only now */
@@ -1190,7 +1196,38 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
else {
rect = *input;
}
-
+
+ if (is_pick_select) {
+ if (is_pick_select && select_mode == VIEW3D_SELECT_PICK_NEAREST) {
+ gpu_select_mode = GPU_SELECT_PICK_NEAREST;
+ }
+ else if (is_pick_select && select_mode == VIEW3D_SELECT_PICK_ALL) {
+ gpu_select_mode = GPU_SELECT_PICK_ALL;
+ }
+ else {
+ gpu_select_mode = GPU_SELECT_ALL;
+ }
+ }
+ else {
+ if (do_passes) {
+ gpu_select_mode = GPU_SELECT_NEAREST_FIRST_PASS;
+ }
+ else {
+ gpu_select_mode = GPU_SELECT_ALL;
+ }
+ }
+
+ /* Re-use cache (rect must be smaller then the cached)
+ * other context is assumed to be unchanged */
+ if (GPU_select_is_cached()) {
+ GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
+ GPU_select_cache_load_id();
+ hits = GPU_select_end();
+ goto finally;
+ }
+
+ G.f |= G_PICKSEL;
+
view3d_winmatrix_set(ar, v3d, &rect);
mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
@@ -1202,10 +1239,7 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_set(vc->rv3d);
- if (do_passes)
- GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
- else
- GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_ALL, 0);
+ GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
@@ -1231,7 +1265,8 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_disable();
-
+
+finally:
if (hits < 0) printf("Too many objects in select buffer\n"); /* XXX make error message */
return hits;