Revert "Gizmo: optimize intersection tests, fix selection bias"
Manually revert commit [0] as it caused problems macOS (reported T96435). - Includes fixes from [1] & [2]. - T98037 TODO has been created to keep track of this feature. Thanks to @jbakker & @sergey for investigating this issue as I wasn't able to reproduce the bug. [0]:0cb5eae9d0
[1]:cb986446e2
[2]:cc8fe1a1cb
This commit is contained in:
parent
49173399f3
commit
5045968f24
Notes:
blender-bot
2023-02-14 07:39:44 +01:00
Referenced by issue #100321, Regression: Extrude Tool XYZ Handles overlap on orthographic view and small world scale Referenced by issue #98932, Regression: Unable to move camera/area light with gizmo (intel GPU) Referenced by issue #98058, Gizmos do not work with cameras in 3D viewport Referenced by issue #98046, Object doens´t mode, scale, rotate on 3.3.0 Referenced by issue #96435, Regression: very long input delay when dragging some gizmos handles in macOS
|
@ -492,7 +492,8 @@ void WM_gizmomap_draw(wmGizmoMap *gzmap,
|
|||
|
||||
static void gizmo_draw_select_3d_loop(const bContext *C,
|
||||
wmGizmo **visible_gizmos,
|
||||
const int visible_gizmos_len)
|
||||
const int visible_gizmos_len,
|
||||
bool *r_use_select_bias)
|
||||
{
|
||||
|
||||
/* TODO(campbell): this depends on depth buffer being written to,
|
||||
|
@ -528,6 +529,10 @@ static void gizmo_draw_select_3d_loop(const bContext *C,
|
|||
is_depth_skip_prev = is_depth_skip;
|
||||
}
|
||||
|
||||
if (gz->select_bias != 0.0) {
|
||||
*r_use_select_bias = true;
|
||||
}
|
||||
|
||||
/* pass the selection id shifted by 8 bits. Last 8 bits are used for selected gizmo part id */
|
||||
|
||||
gz->type->draw_select(C, gz, select_id << 8);
|
||||
|
@ -545,10 +550,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
|
|||
const int visible_gizmos_len,
|
||||
const bContext *C,
|
||||
const int co[2],
|
||||
const int hotspot,
|
||||
const bool use_depth_test,
|
||||
const bool has_3d_select_bias,
|
||||
int *r_hits)
|
||||
const int hotspot)
|
||||
{
|
||||
const wmWindowManager *wm = CTX_wm_manager(C);
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
|
@ -562,76 +564,30 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
|
|||
|
||||
BLI_rcti_init_pt_radius(&rect, co, hotspot);
|
||||
|
||||
/* The selection mode is assigned for the following reasons:
|
||||
*
|
||||
* - #GPU_SELECT_ALL: Use it to check if there is anything at the cursor location
|
||||
* (only ever runs once).
|
||||
* - #GPU_SELECT_PICK_NEAREST: Use if there are more than 1 item at the cursor location,
|
||||
* pick the nearest one.
|
||||
* - #GPU_SELECT_PICK_ALL: Use for the same purpose as #GPU_SELECT_PICK_NEAREST
|
||||
* when the selection depths need to re-ordered based on a bias.
|
||||
* */
|
||||
const eGPUSelectMode gpu_select_mode =
|
||||
(use_depth_test ? (has_3d_select_bias ?
|
||||
/* Using select bias means the depths need to be
|
||||
* re-calculated based on the bias to pick the best. */
|
||||
GPU_SELECT_PICK_ALL :
|
||||
/* No bias, just pick the closest. */
|
||||
GPU_SELECT_PICK_NEAREST) :
|
||||
/* Fast-path (occlusion queries). */
|
||||
GPU_SELECT_ALL);
|
||||
ED_view3d_draw_setup_view(
|
||||
wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
|
||||
|
||||
/* When switching between modes and the mouse pointer is over a gizmo, the highlight test is
|
||||
* performed before the viewport is fully initialized (region->draw_buffer = NULL).
|
||||
* When this is the case we should not use depth testing. */
|
||||
GPUViewport *gpu_viewport = WM_draw_region_get_viewport(region);
|
||||
if (use_depth_test && gpu_viewport == NULL) {
|
||||
return -1;
|
||||
bool use_select_bias = false;
|
||||
|
||||
/* TODO: waiting for the GPU in the middle of the event loop for every
|
||||
* mouse move is bad for performance, we need to find a solution to not
|
||||
* use the GPU or draw something once. (see T61474) */
|
||||
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
|
||||
/* do the drawing */
|
||||
gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
|
||||
|
||||
hits = GPU_select_end();
|
||||
|
||||
if (hits > 0) {
|
||||
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
|
||||
gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
|
||||
GPU_select_end();
|
||||
}
|
||||
|
||||
if (GPU_select_is_cached()) {
|
||||
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0);
|
||||
GPU_select_cache_load_id();
|
||||
hits = GPU_select_end();
|
||||
}
|
||||
else {
|
||||
/* TODO: waiting for the GPU in the middle of the event loop for every
|
||||
* mouse move is bad for performance, we need to find a solution to not
|
||||
* use the GPU or draw something once. (see T61474) */
|
||||
ED_view3d_draw_setup_view(
|
||||
wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
|
||||
|
||||
ED_view3d_draw_setup_view(
|
||||
wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
|
||||
|
||||
/* There is no need to bind to the depth buffer outside this function
|
||||
* because all future passes the will use the cached depths. */
|
||||
GPUFrameBuffer *depth_read_fb = NULL;
|
||||
if (use_depth_test) {
|
||||
GPUTexture *depth_tx = GPU_viewport_depth_texture(gpu_viewport);
|
||||
GPU_framebuffer_ensure_config(&depth_read_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_TEXTURE(depth_tx),
|
||||
GPU_ATTACHMENT_NONE,
|
||||
});
|
||||
GPU_framebuffer_bind(depth_read_fb);
|
||||
}
|
||||
|
||||
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0);
|
||||
gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len);
|
||||
hits = GPU_select_end();
|
||||
|
||||
if (use_depth_test) {
|
||||
GPU_framebuffer_restore();
|
||||
GPU_framebuffer_free(depth_read_fb);
|
||||
}
|
||||
|
||||
ED_view3d_draw_setup_view(
|
||||
wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/* When selection bias is needed, this function will run again with `use_depth_test` enabled. */
|
||||
int hit_found = -1;
|
||||
|
||||
if (has_3d_select_bias && use_depth_test && (hits > 1)) {
|
||||
if (use_select_bias && (hits > 1)) {
|
||||
float co_direction[3];
|
||||
float co_screen[3] = {co[0], co[1], 0.0f};
|
||||
ED_view3d_win_to_vector(region, (float[2]){UNPACK2(co)}, co_direction);
|
||||
|
@ -643,6 +599,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
|
|||
GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin);
|
||||
|
||||
GPUSelectResult *buf_iter = buffer;
|
||||
int hit_found = -1;
|
||||
float dot_best = FLT_MAX;
|
||||
|
||||
for (int i = 0; i < hits; i++, buf_iter++) {
|
||||
|
@ -662,16 +619,11 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
|
|||
hit_found = buf_iter->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits);
|
||||
if (hit_near) {
|
||||
hit_found = hit_near->id;
|
||||
}
|
||||
return hit_found;
|
||||
}
|
||||
|
||||
*r_hits = hits;
|
||||
return hit_found;
|
||||
const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits);
|
||||
return hit_near ? hit_near->id : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -694,7 +646,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
|
|||
|
||||
/* Search for 3D gizmo's that use the 2D callback for checking intersections. */
|
||||
bool has_3d = false;
|
||||
bool has_3d_select_bias = false;
|
||||
{
|
||||
for (int select_id = 0; select_id < visible_gizmos_len; select_id++) {
|
||||
wmGizmo *gz = visible_gizmos[select_id];
|
||||
|
@ -710,9 +661,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
|
|||
}
|
||||
else if (gz->type->draw_select != NULL) {
|
||||
has_3d = true;
|
||||
if (gz->select_bias != 0.0f) {
|
||||
has_3d_select_bias = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -721,86 +669,39 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
|
|||
* This way we always use the first hit. */
|
||||
if (has_3d) {
|
||||
|
||||
/* NOTE(@campbellbarton): The selection logic here uses a fast-path that exits early
|
||||
* where possible. This is important as this runs on cursor-motion in the 3D view-port.
|
||||
*
|
||||
* - First, don't use the depth buffer at all, use occlusion queries to detect any gizmos.
|
||||
* If there are no gizmos or only one - early exit, otherwise.
|
||||
*
|
||||
* - Bind the depth buffer and use selection picking logic.
|
||||
* This is much slower than occlusion queries (since it's reading depths while drawing).
|
||||
* When there is a single gizmo under the cursor (quite common), early exit, otherwise.
|
||||
*
|
||||
* - Perform another pass at a reduced size (see: `hotspot_radii`),
|
||||
* since the result depths are cached this pass is practically free.
|
||||
*
|
||||
* Other notes:
|
||||
*
|
||||
* - If any of these passes fail, use the nearest result from the previous pass.
|
||||
*
|
||||
* - Drawing is only ever done twice.
|
||||
*/
|
||||
/* The depth buffer is needed for for gizmos to obscure eachother. */
|
||||
GPUViewport *viewport = WM_draw_region_get_viewport(CTX_wm_region(C));
|
||||
|
||||
/* Order largest to smallest so the first pass can be used as cache for
|
||||
* later passes (when `use_depth_test == true`). */
|
||||
const int hotspot_radii[] = {
|
||||
10 * U.pixelsize,
|
||||
/* This runs on mouse move, careful doing too many tests! */
|
||||
3 * U.pixelsize,
|
||||
};
|
||||
|
||||
/* Narrowing may assign zero to `hit`, allow falling back to the previous test. */
|
||||
int hit_prev = -1;
|
||||
|
||||
bool use_depth_test = false;
|
||||
bool use_depth_cache = false;
|
||||
|
||||
/* Workaround for MS-Windows & NVidia failing to detect any gizmo undo the cursor unless the
|
||||
* depth test is enabled, see: T97124.
|
||||
* NOTE(@campbellbarton): Ideally the exact cause of this could be tracked down,
|
||||
* disable as I don't have a system to test this configuration. */
|
||||
if (GPU_type_matches(GPU_DEVICE_NVIDIA | GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_ANY)) {
|
||||
use_depth_test = true;
|
||||
/* When switching between modes and the mouse pointer is over a gizmo, the highlight test is
|
||||
* performed before the viewport is fully initialized (region->draw_buffer = NULL).
|
||||
* When this is the case we should not use depth testing. */
|
||||
if (viewport == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport);
|
||||
GPUFrameBuffer *depth_read_fb = NULL;
|
||||
GPU_framebuffer_ensure_config(&depth_read_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_TEXTURE(depth_tx),
|
||||
GPU_ATTACHMENT_NONE,
|
||||
});
|
||||
GPU_framebuffer_bind(depth_read_fb);
|
||||
|
||||
const int hotspot_radii[] = {
|
||||
3 * U.pixelsize,
|
||||
/* This runs on mouse move, careful doing too many tests! */
|
||||
10 * U.pixelsize,
|
||||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(hotspot_radii); i++) {
|
||||
|
||||
if (use_depth_test && (use_depth_cache == false)) {
|
||||
GPU_select_cache_begin();
|
||||
use_depth_cache = true;
|
||||
}
|
||||
|
||||
int hit_count;
|
||||
hit = gizmo_find_intersected_3d_intern(visible_gizmos,
|
||||
visible_gizmos_len_trim,
|
||||
C,
|
||||
co,
|
||||
hotspot_radii[i],
|
||||
use_depth_test,
|
||||
has_3d_select_bias,
|
||||
&hit_count);
|
||||
/* Only continue searching when there are multiple options to narrow down. */
|
||||
if (hit_count < 2) {
|
||||
hit = gizmo_find_intersected_3d_intern(
|
||||
visible_gizmos, visible_gizmos_len_trim, C, co, hotspot_radii[i]);
|
||||
if (hit != -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fast path for simple case, one item or nothing. */
|
||||
if (use_depth_test == false) {
|
||||
/* Restart, using depth buffer (slower). */
|
||||
use_depth_test = true;
|
||||
i = -1;
|
||||
}
|
||||
hit_prev = hit;
|
||||
}
|
||||
/* Narrowing the search area may yield no hits,
|
||||
* in this case fall back to the previous search. */
|
||||
if (hit == -1) {
|
||||
hit = hit_prev;
|
||||
}
|
||||
|
||||
if (use_depth_cache) {
|
||||
GPU_select_cache_end();
|
||||
}
|
||||
GPU_framebuffer_restore();
|
||||
GPU_framebuffer_free(depth_read_fb);
|
||||
|
||||
if (hit != -1) {
|
||||
const int select_id = hit >> 8;
|
||||
|
|
Loading…
Reference in New Issue