Selection: Add conservative rasterization to select really small objects

The conservative depth shader is ~4.5x slower than the normal one as it
uses geometry shader and fragment shader discard.

This patch also includes a hack to also fix the view parallel planar
geometry and the really small wire objects.

For some reason, the conservative raster fix does not work with normal
selection but does with box select.

This is a fix for T63356.

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D6714
This commit is contained in:
Clément Foucault 2020-02-04 15:19:28 +01:00
parent cd0a028624
commit 3685347b41
Notes: blender-bot 2023-02-14 08:47:25 +01:00
Referenced by commit 24140444f2, Fix T75556: Select Emitter Object via Hair
Referenced by commit 849672a991, Fix T75556: Select Emitter Object via Hair
Referenced by issue #75556, Particle Hair cannot be selected anymore
Referenced by issue #72842, Box and Lasso select is extremely unreliable in Face or Edge select mode (selects non-visible faces or edges)
8 changed files with 129 additions and 24 deletions

View File

@ -307,6 +307,10 @@ data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl SRC)
data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC)
data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC)
data_to_c_simple(engines/basic/shaders/conservative_depth_geom.glsl SRC)
data_to_c_simple(engines/basic/shaders/conservative_depth_vert.glsl SRC)
data_to_c_simple(engines/basic/shaders/conservative_depth_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/antialiasing_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/antialiasing_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/armature_dof_vert.glsl SRC)

View File

@ -37,6 +37,12 @@
#define BASIC_ENGINE "BLENDER_BASIC"
extern char datatoc_conservative_depth_frag_glsl[];
extern char datatoc_conservative_depth_vert_glsl[];
extern char datatoc_conservative_depth_geom_glsl[];
extern char datatoc_common_view_lib_glsl[];
/* *********** LISTS *********** */
/* GPUViewport.storage
@ -61,6 +67,7 @@ typedef struct BASIC_Data {
typedef struct BASIC_Shaders {
/* Depth Pre Pass */
struct GPUShader *depth;
struct GPUShader *depth_conservative;
} BASIC_Shaders;
/* *********** STATIC *********** */
@ -84,6 +91,22 @@ static void basic_engine_init(void *UNUSED(vedata))
/* Depth prepass */
if (!sh_data->depth) {
sh_data->depth = DRW_shader_create_3d_depth_only(draw_ctx->sh_cfg);
const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
sh_data->depth_conservative = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
datatoc_common_view_lib_glsl,
datatoc_conservative_depth_vert_glsl,
NULL},
.geom = (const char *[]){sh_cfg->lib,
datatoc_common_view_lib_glsl,
datatoc_conservative_depth_geom_glsl,
NULL},
.frag = (const char *[]){datatoc_common_view_lib_glsl,
datatoc_conservative_depth_frag_glsl,
NULL},
.defs = (const char *[]){sh_cfg->def, NULL},
});
}
}
@ -91,6 +114,7 @@ static void basic_cache_init(void *vedata)
{
BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
DRWShadingGroup *grp;
const DRWContextState *draw_ctx = DRW_context_state_get();
BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
@ -106,12 +130,18 @@ static void basic_cache_init(void *vedata)
DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
GPUShader *sh = DRW_state_is_select() ? sh_data->depth_conservative : sh_data->depth;
DRW_PASS_CREATE(psl->depth_pass[i], state | clip_state | infront_state);
stl->g_data->depth_shgrp[i] = DRW_shgroup_create(sh_data->depth, psl->depth_pass[i]);
stl->g_data->depth_shgrp[i] = grp = DRW_shgroup_create(sh, psl->depth_pass[i]);
DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1);
DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1);
state |= DRW_STATE_CULL_BACK;
DRW_PASS_CREATE(psl->depth_pass_cull[i], state | clip_state | infront_state);
stl->g_data->depth_shgrp_cull[i] = DRW_shgroup_create(sh_data->depth, psl->depth_pass_cull[i]);
stl->g_data->depth_shgrp_cull[i] = grp = DRW_shgroup_create(sh, psl->depth_pass_cull[i]);
DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1);
DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1);
}
}
@ -197,7 +227,10 @@ static void basic_draw_scene(void *vedata)
static void basic_engine_free(void)
{
/* all shaders are builtin */
for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) {
BASIC_Shaders *sh_data = &e_data.sh_data[i];
DRW_SHADER_FREE_SAFE(sh_data->depth_conservative);
}
}
static const DrawEngineDataSize basic_data_size = DRW_VIEWPORT_DATA_SIZE(BASIC_Data);
@ -219,23 +252,4 @@ DrawEngineType draw_engine_basic_type = {
NULL,
};
/* Note: currently unused, we may want to register so we can see this when debugging the view. */
RenderEngineType DRW_engine_viewport_basic_type = {
NULL,
NULL,
BASIC_ENGINE,
N_("Basic"),
RE_INTERNAL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&draw_engine_basic_type,
{NULL, NULL, NULL},
};
#undef BASIC_ENGINE

View File

@ -24,6 +24,5 @@
#define __BASIC_ENGINE_H__
extern DrawEngineType draw_engine_basic_type;
extern RenderEngineType DRW_engine_viewport_basic_type;
#endif /* __BASIC_ENGINE_H__ */

View File

@ -0,0 +1,5 @@
void main()
{
/* Passthrough shader. */
}

View File

@ -0,0 +1,59 @@
/* Adaptation of Conservative Rasterization
* from GPU Gems 2
* Using method 2.
*
* Actual final implementation does not do conservative rasterization and only
* avoids triangles producing no fragments.
*/
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
RESOURCE_ID_VARYING
uniform vec2 sizeViewport;
uniform vec2 sizeViewportInv;
void main()
{
/* Compute plane normal in ndc space. */
vec3 pos0 = gl_in[0].gl_Position.xyz / gl_in[0].gl_Position.w;
vec3 pos1 = gl_in[1].gl_Position.xyz / gl_in[1].gl_Position.w;
vec3 pos2 = gl_in[2].gl_Position.xyz / gl_in[2].gl_Position.w;
vec3 plane = normalize(cross(pos1 - pos0, pos2 - pos0));
/* Compute NDC bound box. */
vec4 bbox = vec4(min(min(pos0.xy, pos1.xy), pos2.xy), max(max(pos0.xy, pos1.xy), pos2.xy));
/* Convert to pixel space. */
bbox = (bbox * 0.5 + 0.5) * sizeViewport.xyxy;
/* Detect failure cases where triangles would produce no fragments. */
bvec2 is_subpixel = lessThan(bbox.zw - bbox.xy, vec2(1.0));
/* View aligned triangle. */
const float threshold = 0.00001;
bool is_coplanar = abs(plane.z) < threshold;
for (int i = 0; i < 3; i++) {
gl_Position = gl_in[i].gl_Position;
if (all(is_subpixel)) {
vec2 ofs = (i == 0) ? vec2(-1.0) : ((i == 1) ? vec2(2.0, -1.0) : vec2(-1.0, 2.0));
/* HACK: Fix cases where the triangle is too small make it cover at least one pixel. */
gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ofs;
}
/* Test if the triangle is almost parralele with the view to avoid precision issues. */
else if (any(is_subpixel) || is_coplanar) {
/* HACK: Fix cases where the triangle is Parallel to the view by deforming it slightly. */
vec2 ofs = (i == 0) ? vec2(-1.0) : ((i == 1) ? vec2(1.0, -1.0) : vec2(1.0));
gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ofs;
}
else {
/* Triangle expansion should happen here, but we decide to not implement it for
* depth precision & performance reasons. */
}
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[i].gl_ClipDistance);
#endif
EmitVertex();
}
EndPrimitive();
}

View File

@ -0,0 +1,17 @@
RESOURCE_ID_VARYING
in vec3 pos;
void main()
{
GPU_INTEL_VERTEX_SHADER_WORKAROUND
PASS_RESOURCE_ID
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
}

View File

@ -148,6 +148,12 @@ void main()
edgeStart = vec2(-1.0);
}
#ifdef SELECT_EDGES
/* HACK: to avoid loosing sub pixel object in selections, we add a bit of randomness to the
* wire to at least create one fragment that will pass the occlusion query. */
gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0);
#endif
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(wpos);
#endif

View File

@ -1378,7 +1378,7 @@ static void drw_engines_enable_overlays(void)
*/
static void drw_engines_enable_basic(void)
{
use_drw_engine(DRW_engine_viewport_basic_type.draw_engine);
use_drw_engine(&draw_engine_basic_type);
}
static void drw_engines_enable(ViewLayer *UNUSED(view_layer),
@ -2830,6 +2830,7 @@ void DRW_engines_register(void)
DRW_engine_register(&draw_engine_overlay_type);
DRW_engine_register(&draw_engine_select_type);
DRW_engine_register(&draw_engine_basic_type);
/* setup callbacks */
{