Overlay Engine: Simplify outline rendering by using the antialiasing pass

This use the overlay AA pass to antialias the selection outlines.

This also do all search and expand in one pass and reduce the computation
time and memory used (2 x 32bit/pixel buffer less).

Note that the aliasing is a bit worse than the old FXAA that we used to have.
This commit is contained in:
Clément Foucault 2019-12-04 01:31:36 +01:00
parent e203f69bc3
commit 6d3eb85f66
Notes: blender-bot 2023-02-13 23:36:23 +01:00
Referenced by issue #73494, Jagged Wireframes in 2.83 Alpha.
10 changed files with 352 additions and 284 deletions

View File

@ -360,12 +360,10 @@ data_to_c_simple(engines/overlay/shaders/motion_path_line_geom.glsl SRC)
data_to_c_simple(engines/overlay/shaders/motion_path_line_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/motion_path_point_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/outline_detect_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/outline_expand_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/outline_prepass_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/outline_prepass_geom.glsl SRC)
data_to_c_simple(engines/overlay/shaders/outline_prepass_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/outline_lightprobe_grid_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/outline_resolve_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/paint_face_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/paint_point_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/paint_texture_frag.glsl SRC)

View File

@ -60,12 +60,6 @@
#include "overlay_private.h"
void OVERLAY_antialiasing_reset(OVERLAY_Data *vedata)
{
OVERLAY_PrivateData *pd = vedata->stl->pd;
pd->antialiasing.sample = 0;
}
void OVERLAY_antialiasing_init(OVERLAY_Data *vedata)
{
OVERLAY_FramebufferList *fbl = vedata->fbl;

View File

@ -50,37 +50,27 @@ static void OVERLAY_engine_init(void *vedata)
}
OVERLAY_PrivateData *pd = stl->pd;
View3DOverlay overlay;
short v3d_flag, v3d_gridflag;
pd->hide_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) != 0;
pd->ctx_mode = CTX_data_mode_enum_ex(
draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
if (!pd->hide_overlays) {
overlay = v3d->overlay;
v3d_flag = v3d->flag;
v3d_gridflag = v3d->gridflag;
pd->overlay = v3d->overlay;
pd->v3d_flag = v3d->flag;
pd->v3d_gridflag = v3d->gridflag;
}
else {
memset(&overlay, 0, sizeof(overlay));
v3d_flag = 0;
v3d_gridflag = 0;
overlay.flag = V3D_OVERLAY_HIDE_TEXT | V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES |
V3D_OVERLAY_HIDE_OBJECT_XTRAS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
memset(&pd->overlay, 0, sizeof(pd->overlay));
pd->v3d_flag = 0;
pd->v3d_gridflag = 0;
pd->overlay.flag = V3D_OVERLAY_HIDE_TEXT | V3D_OVERLAY_HIDE_MOTION_PATHS |
V3D_OVERLAY_HIDE_BONES | V3D_OVERLAY_HIDE_OBJECT_XTRAS |
V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
}
if (v3d->shading.type == OB_WIRE) {
overlay.flag |= V3D_OVERLAY_WIREFRAMES;
}
/* Check if anything changed, and if so, reset AA. */
if (v3d_flag != pd->v3d_flag || pd->v3d_gridflag != v3d_gridflag ||
memcmp(&pd->overlay, &overlay, sizeof(overlay))) {
pd->overlay = overlay;
pd->v3d_flag = v3d_flag;
pd->v3d_gridflag = v3d_gridflag;
OVERLAY_antialiasing_reset(vedata);
pd->overlay.flag |= V3D_OVERLAY_WIREFRAMES;
}
pd->wireframe_mode = (v3d->shading.type == OB_WIRE);
@ -376,6 +366,9 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_antialiasing_start(vedata);
DRW_view_set_active(NULL);
OVERLAY_outline_draw(vedata);
DRW_view_set_active(pd->view_default);
OVERLAY_image_draw(vedata);
@ -387,9 +380,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_extra_draw(vedata);
DRW_view_set_active(NULL);
OVERLAY_grid_draw(vedata);
OVERLAY_outline_draw(vedata);
DRW_view_set_active(pd->view_default);

View File

@ -32,23 +32,28 @@ void OVERLAY_outline_init(OVERLAY_Data *vedata)
{
OVERLAY_FramebufferList *fbl = vedata->fbl;
OVERLAY_TextureList *txl = vedata->txl;
OVERLAY_PrivateData *pd = vedata->stl->pd;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
if (DRW_state_is_fbo()) {
/* TODO only alloc if needed. */
/* XXX TODO GPU_R16UI can overflow, it would cause no harm
* (only bad colored or missing outlines) but we should
* use 32bits only if the scene have that many objects */
DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0);
DRW_texture_ensure_fullscreen_2d(&txl->outlines_id_tx, GPU_R16UI, 0);
GPU_framebuffer_ensure_config(
&fbl->outlines_prepass_fb,
{GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->outlines_id_tx)});
for (int i = 0; i < 2; i++) {
DRW_texture_ensure_fullscreen_2d(&txl->outlines_color_tx[i], GPU_RGBA8, DRW_TEX_FILTER);
if (pd->antialiasing.enabled) {
GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb,
{GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx),
GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)});
}
else {
GPU_framebuffer_ensure_config(
&fbl->outlines_process_fb[i],
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->outlines_color_tx[i])});
&fbl->outlines_resolve_fb,
{GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
}
}
}
@ -133,9 +138,8 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
DRWShadingGroup *grp = NULL;
const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
const bool do_large_expand = ((U.pixelsize > 1.0) && (outline_width > 2.0f)) ||
(outline_width > 4.0f);
const bool do_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
{
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
DRW_PASS_CREATE(psl->outlines_prepass_ps, state | pd->clipping_state);
@ -164,50 +168,22 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
}
{
DRW_PASS_CREATE(psl->outlines_detect_ps, DRW_STATE_WRITE_COLOR);
DRW_PASS_CREATE(psl->outlines_expand_ps, DRW_STATE_WRITE_COLOR);
DRW_PASS_CREATE(psl->outlines_bleed_ps, DRW_STATE_WRITE_COLOR);
DRW_PASS_CREATE(psl->outlines_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
/* We can only do alpha blending with lineOutput just after clearing the buffer. */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
DRW_PASS_CREATE(psl->outlines_detect_ps, state);
GPUShader *sh = OVERLAY_shader_outline_detect(pd->xray_enabled_and_not_wire);
GPUShader *sh = OVERLAY_shader_outline_detect();
grp = DRW_shgroup_create(sh, psl->outlines_detect_ps);
/* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.35f);
DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.125f);
DRW_shgroup_uniform_bool_copy(grp, "doThickOutlines", do_expand);
DRW_shgroup_uniform_bool_copy(grp, "isXrayWires", pd->xray_enabled_and_not_wire);
DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx);
DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx);
DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
if (do_outline_expand) {
sh = OVERLAY_shader_outline_expand(do_large_expand);
grp = DRW_shgroup_create(sh, psl->outlines_expand_ps);
DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[0]);
DRW_shgroup_uniform_bool_copy(grp, "doExpand", true);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
sh = OVERLAY_shader_outline_expand(false);
grp = DRW_shgroup_create(sh, psl->outlines_bleed_ps);
DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[1]);
DRW_shgroup_uniform_bool_copy(grp, "doExpand", false);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
else {
sh = OVERLAY_shader_outline_expand(false);
grp = DRW_shgroup_create(sh, psl->outlines_expand_ps);
DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[0]);
DRW_shgroup_uniform_bool_copy(grp, "doExpand", false);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
GPUTexture **outline_tx = &txl->outlines_color_tx[do_outline_expand ? 0 : 1];
sh = OVERLAY_shader_outline_resolve();
grp = DRW_shgroup_create(sh, psl->outlines_resolve_ps);
DRW_shgroup_uniform_texture_ref(grp, "outlineBluredColor", outline_tx);
DRW_shgroup_uniform_vec2_copy(grp, "rcpDimensions", DRW_viewport_invert_size_get());
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
}
@ -331,25 +307,13 @@ void OVERLAY_outline_draw(OVERLAY_Data *vedata)
/* Render filled polygon on a separate framebuffer */
GPU_framebuffer_bind(fbl->outlines_prepass_fb);
GPU_framebuffer_clear_color_depth(fbl->outlines_prepass_fb, clearcol, 1.0f);
GPU_framebuffer_clear_color_depth_stencil(fbl->outlines_prepass_fb, clearcol, 1.0f, 0x00);
DRW_draw_pass(psl->outlines_prepass_ps);
/* Search outline pixels */
GPU_framebuffer_bind(fbl->outlines_process_fb[0]);
GPU_framebuffer_bind(fbl->outlines_resolve_fb);
DRW_draw_pass(psl->outlines_detect_ps);
/* Expand outline to form a 3px wide line */
GPU_framebuffer_bind(fbl->outlines_process_fb[1]);
DRW_draw_pass(psl->outlines_expand_ps);
/* Bleed color so the AA can do it's stuff */
GPU_framebuffer_bind(fbl->outlines_process_fb[0]);
DRW_draw_pass(psl->outlines_bleed_ps);
/* restore main framebuffer */
GPU_framebuffer_bind(fbl->overlay_default_fb);
DRW_draw_pass(psl->outlines_resolve_ps);
DRW_stats_group_end();
}
else if (DRW_state_is_select()) {

View File

@ -35,16 +35,14 @@ typedef struct OVERLAY_FramebufferList {
struct GPUFrameBuffer *overlay_color_only_fb;
struct GPUFrameBuffer *overlay_in_front_fb;
struct GPUFrameBuffer *outlines_prepass_fb;
struct GPUFrameBuffer *outlines_process_fb[2];
struct GPUFrameBuffer *outlines_resolve_fb;
} OVERLAY_FramebufferList;
typedef struct OVERLAY_TextureList {
struct GPUTexture *temp_depth_tx;
struct GPUTexture *dummy_depth_tx;
struct GPUTexture *outlines_id_tx;
struct GPUTexture *outlines_color_tx[2];
struct GPUTexture *overlay_color_tx;
struct GPUTexture *overlay_color_history_tx;
struct GPUTexture *overlay_line_tx;
struct GPUTexture *edit_mesh_occlude_wire_tx;
} OVERLAY_TextureList;
@ -87,8 +85,6 @@ typedef struct OVERLAY_PassList {
DRWPass *motion_paths_ps;
DRWPass *outlines_prepass_ps;
DRWPass *outlines_detect_ps;
DRWPass *outlines_expand_ps;
DRWPass *outlines_bleed_ps;
DRWPass *outlines_resolve_ps;
DRWPass *paint_color_ps;
DRWPass *paint_overlay_ps;
@ -278,9 +274,6 @@ typedef struct OVERLAY_PrivateData {
OVERLAY_ShadingData shdata;
struct {
short sample;
short target_sample;
float prev_persmat[4][4];
bool enabled;
} antialiasing;
struct {
@ -388,7 +381,6 @@ BLI_INLINE void pack_fl_in_mat4(float rmat[4][4], const float mat[4][4], float a
rmat[3][3] = a;
}
void OVERLAY_antialiasing_reset(OVERLAY_Data *vedata);
void OVERLAY_antialiasing_init(OVERLAY_Data *vedata);
void OVERLAY_antialiasing_cache_init(OVERLAY_Data *vedata);
void OVERLAY_antialiasing_cache_finish(OVERLAY_Data *vedata);
@ -562,9 +554,7 @@ GPUShader *OVERLAY_shader_motion_path_vert(void);
GPUShader *OVERLAY_shader_uniform_color(void);
GPUShader *OVERLAY_shader_outline_prepass(bool use_wire);
GPUShader *OVERLAY_shader_outline_prepass_grid(void);
GPUShader *OVERLAY_shader_outline_resolve(void);
GPUShader *OVERLAY_shader_outline_expand(bool high_dpi);
GPUShader *OVERLAY_shader_outline_detect(bool use_wire);
GPUShader *OVERLAY_shader_outline_detect(void);
GPUShader *OVERLAY_shader_paint_face(void);
GPUShader *OVERLAY_shader_paint_point(void);
GPUShader *OVERLAY_shader_paint_texture(void);

View File

@ -80,12 +80,10 @@ extern char datatoc_motion_path_line_vert_glsl[];
extern char datatoc_motion_path_line_geom_glsl[];
extern char datatoc_motion_path_point_vert_glsl[];
extern char datatoc_outline_detect_frag_glsl[];
extern char datatoc_outline_expand_frag_glsl[];
extern char datatoc_outline_prepass_frag_glsl[];
extern char datatoc_outline_prepass_geom_glsl[];
extern char datatoc_outline_prepass_vert_glsl[];
extern char datatoc_outline_lightprobe_grid_vert_glsl[];
extern char datatoc_outline_resolve_frag_glsl[];
extern char datatoc_paint_face_vert_glsl[];
extern char datatoc_paint_point_vert_glsl[];
extern char datatoc_paint_texture_frag_glsl[];
@ -159,11 +157,7 @@ typedef struct OVERLAY_Shaders {
GPUShader *outline_prepass;
GPUShader *outline_prepass_wire;
GPUShader *outline_prepass_lightprobe_grid;
GPUShader *outline_resolve;
GPUShader *outline_fade;
GPUShader *outline_fade_large;
GPUShader *outline_detect;
GPUShader *outline_detect_wire;
GPUShader *paint_face;
GPUShader *paint_point;
GPUShader *paint_texture;
@ -941,51 +935,19 @@ GPUShader *OVERLAY_shader_outline_prepass_grid(void)
return sh_data->outline_prepass_lightprobe_grid;
}
GPUShader *OVERLAY_shader_outline_resolve(void)
GPUShader *OVERLAY_shader_outline_detect(void)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
if (!sh_data->outline_resolve) {
sh_data->outline_resolve = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
NULL,
datatoc_outline_resolve_frag_glsl,
datatoc_common_fxaa_lib_glsl,
"#define FXAA_ALPHA\n"
"#define USE_FXAA\n");
if (!sh_data->outline_detect) {
sh_data->outline_detect = GPU_shader_create_from_arrays({
.vert = (const char *[]){datatoc_common_fullscreen_vert_glsl, NULL},
.frag = (const char *[]){datatoc_common_view_lib_glsl,
datatoc_common_globals_lib_glsl,
datatoc_outline_detect_frag_glsl,
NULL},
});
}
return sh_data->outline_resolve;
}
GPUShader *OVERLAY_shader_outline_expand(bool high_dpi)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
if (high_dpi && !sh_data->outline_fade_large) {
sh_data->outline_fade_large = DRW_shader_create_fullscreen(datatoc_outline_expand_frag_glsl,
"#define LARGE_OUTLINE\n");
}
else if (!sh_data->outline_fade) {
sh_data->outline_fade = DRW_shader_create_fullscreen(datatoc_outline_expand_frag_glsl, NULL);
}
return (high_dpi) ? sh_data->outline_fade_large : sh_data->outline_fade;
}
GPUShader *OVERLAY_shader_outline_detect(bool use_wire)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
if (use_wire && !sh_data->outline_detect_wire) {
sh_data->outline_detect_wire = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
NULL,
datatoc_outline_detect_frag_glsl,
datatoc_common_globals_lib_glsl,
"#define WIRE\n");
}
else if (!sh_data->outline_detect) {
sh_data->outline_detect = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
NULL,
datatoc_outline_detect_frag_glsl,
datatoc_common_globals_lib_glsl,
NULL);
}
return (use_wire) ? sh_data->outline_detect_wire : sh_data->outline_detect;
return sh_data->outline_detect;
}
GPUShader *OVERLAY_shader_paint_face(void)

View File

@ -96,6 +96,8 @@ void main()
fragColor = texelFetch(colorTex, center_texel, 0);
bool original_col_has_alpha = fragColor.a < 1.0;
float depth = texelFetch(depthTex, center_texel, 0).r;
float dist_raw = texelFetch(lineTex, center_texel, 0).b;
@ -138,7 +140,7 @@ void main()
#if 1
/* Fix aliasing issue with really dense meshes and 1 pixel sized lines. */
if (dist_raw > 0.0 && line_kernel < 0.45) {
if (!original_col_has_alpha && dist_raw > 0.0 && line_kernel < 0.45) {
vec4 lines = vec4(neightbor_line0.z, neightbor_line1.z, neightbor_line2.z, neightbor_line3.z);
/* Count number of line neighbors. */
float blend = dot(vec4(0.25), step(0.001, lines));

View File

@ -1,86 +1,325 @@
in vec4 uvcoordsvar;
out vec4 FragColor;
uniform float alphaOcclu;
uniform bool isXrayWires;
uniform bool doThickOutlines;
uniform usampler2D outlineId;
uniform sampler2D outlineDepth;
uniform sampler2D sceneDepth;
uniform float alphaOcclu;
in vec4 uvcoordsvar;
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec4 lineOutput;
#define XPOS 1
#define XNEG 2
#define YPOS 4
#define YNEG 8
#define ALL (XPOS | XNEG | YPOS | YNEG)
#define NONE 0
#define DIAG_XNEG_YPOS (XNEG | YPOS)
#define DIAG_XPOS_YPOS (XPOS | YPOS)
#define DIAG_XPOS_YNEG (XPOS | YNEG)
#define DIAG_XNEG_YNEG (XNEG | YNEG)
#define APEX_XPOS (ALL & (~XPOS))
#define APEX_XNEG (ALL & (~XNEG))
#define APEX_YPOS (ALL & (~YPOS))
#define APEX_YNEG (ALL & (~YNEG))
bool has_edge(uint id, vec2 uv, uint ref, inout uint ref_col, inout vec2 depth_uv)
{
if (ref_col == 0u) {
/* Make outline bleed on the background. */
ref_col = id;
depth_uv = uv;
}
return (id != ref);
}
/* A gather4 + check against ref. */
bvec4 gather_edges(vec2 uv, uint ref)
{
uvec4 ids;
#ifdef GPU_ARB_texture_gather
ids = textureGather(outlineId, uv);
#else
vec3 ofs = vec3(0.5, 0.5, -0.5) * sizeViewportInv.xyy;
ids.x = textureLod(outlineId, uv - ofs.xz, 0.0).r;
ids.y = textureLod(outlineId, uv + ofs.xy, 0.0).r;
ids.z = textureLod(outlineId, uv + ofs.xz, 0.0).r;
ids.w = textureLod(outlineId, uv - ofs.xy, 0.0).r;
#endif
return notEqual(ids, uvec4(ref));
}
/* Apply offset to line endpoint based on surrounding edges infos. */
bool line_offset(bvec2 edges, vec2 ofs, inout vec2 line_point)
{
if (all(edges.xy)) {
line_point.y -= ofs.y;
}
else if (!edges.x) {
line_point.y += ofs.y;
}
else /* !edges.y */ {
line_point.x += ofs.x;
return true;
}
return false;
}
/* Changes Antialiasing pattern and makes line thicker. 0.0 is thin. */
#define PROXIMITY_OFS -0.35
/* Use surrounding edges to approximate the outline direction to create smooth lines. */
void straight_line_dir(bvec4 edges1, bvec4 edges2, out vec2 line_start, out vec2 line_end)
{
line_end = vec2(1.5, 0.5 + PROXIMITY_OFS);
line_start = vec2(-line_end.x, line_end.y);
vec2 line_ofs = vec2(1.0, 0.5);
if (line_offset(edges1.xw, line_ofs, line_end)) {
line_offset(edges1.yz, line_ofs, line_end);
}
line_ofs = vec2(-line_ofs.x, line_ofs.y);
if (line_offset(edges2.yz, line_ofs, line_start)) {
line_offset(edges2.xw, line_ofs, line_start);
}
}
/* Compute line direction vector from the bottom left corner. */
void diag_dir(bvec4 edges, out vec2 line_start, out vec2 line_end)
{
/* TODO Improve diagonal antialiasing. */
if (all(edges.wz)) {
line_start = vec2(-3.0, -0.5 + PROXIMITY_OFS);
line_end = vec2(3.0, 0.5 + PROXIMITY_OFS);
}
else if (all(not(edges.xw))) {
line_start = vec2(-0.5 - PROXIMITY_OFS, -3.0);
line_end = vec2(0.5 - PROXIMITY_OFS, 3.0);
}
else if (edges.w) {
line_start = vec2(-1.0, -0.5 - PROXIMITY_OFS);
line_end = vec2(2.0, 0.5 - PROXIMITY_OFS);
}
else {
line_start = vec2(-0.6, -0.5 + PROXIMITY_OFS);
line_end = vec2(0.6 - PROXIMITY_OFS, 0.5);
}
}
/* Clockwise */
vec2 rotate_90(vec2 v)
{
return vec2(v.y, -v.x);
}
vec2 rotate_180(vec2 v)
{
return vec2(-v.x, -v.y);
}
vec2 rotate_270(vec2 v)
{
return vec2(-v.y, v.x);
}
/* Counter-Clockwise */
bvec4 rotate_90(bvec4 v)
{
return v.yzwx;
}
bvec4 rotate_180(bvec4 v)
{
return v.zwxy;
}
bvec4 rotate_270(bvec4 v)
{
return v.wxyz;
}
void main()
{
ivec2 texel = ivec2(gl_FragCoord.xy);
uint ref = textureLod(outlineId, uvcoordsvar.st, 0.0).r;
uint ref_col = ref;
vec2 uvs = gl_FragCoord.xy * sizeViewportInv.xy;
vec3 ofs = vec3(1.0, 1.0, 0.0) * sizeViewportInv.xyy;
vec2 depth_uv = uvs;
uvec4 ids;
#ifdef GPU_ARB_texture_gather
vec2 texel_size = 1.0 / vec2(textureSize(outlineId, 0).xy);
vec2 uv = ceil(gl_FragCoord.xy) * texel_size;
/* Samples order is CW starting from top left. */
uvec4 tmp1 = textureGather(outlineId, uv - texel_size);
uvec4 tmp2 = textureGather(outlineId, uv);
uint ref_id = tmp1.y;
uvec4 id = uvec4(tmp1.xz, tmp2.xz);
/* Reminder: Samples order is CW starting from top left. */
uvec2 tmp1, tmp2, tmp3, tmp4;
if (doThickOutlines) {
tmp1 = textureGather(outlineId, uvs + ofs.xy * vec2(1.5, -0.5)).xy;
tmp2 = textureGather(outlineId, uvs + ofs.xy * vec2(-1.5, -0.5)).yx;
tmp3 = textureGather(outlineId, uvs + ofs.xy * vec2(0.5, 1.5)).wx;
tmp4 = textureGather(outlineId, uvs + ofs.xy * vec2(0.5, -1.5)).xw;
ids.x = tmp1.x;
ids.y = tmp2.x;
ids.z = tmp3.x;
ids.w = tmp4.x;
}
else {
ids.xz = textureGather(outlineId, uvs + ofs.xy * 0.5).zx;
ids.yw = textureGather(outlineId, uvs - ofs.xy * 0.5).xz;
}
#else
uvec4 id;
uint ref_id = texelFetch(outlineId, texel, 0).r;
id.x = texelFetchOffset(outlineId, texel, 0, ivec2(-1, 0)).r;
id.y = texelFetchOffset(outlineId, texel, 0, ivec2(0, -1)).r;
id.z = texelFetchOffset(outlineId, texel, 0, ivec2(0, 1)).r;
id.w = texelFetchOffset(outlineId, texel, 0, ivec2(1, 0)).r;
ids.x = textureLod(outlineId, uvs + ofs.xz, 0.0).r;
ids.y = textureLod(outlineId, uvs - ofs.xz, 0.0).r;
ids.z = textureLod(outlineId, uvs + ofs.zy, 0.0).r;
ids.w = textureLod(outlineId, uvs - ofs.zy, 0.0).r;
#endif
#ifdef WIRE
/* We want only 2px outlines. */
/* TODO optimize, don't sample if we don't need to. */
id.xy = uvec2(ref_id);
bool has_edge_pos_x = has_edge(ids.x, uvs + ofs.xz, ref, ref_col, depth_uv);
bool has_edge_neg_x = has_edge(ids.y, uvs - ofs.xz, ref, ref_col, depth_uv);
bool has_edge_pos_y = has_edge(ids.z, uvs + ofs.zy, ref, ref_col, depth_uv);
bool has_edge_neg_y = has_edge(ids.w, uvs - ofs.zy, ref, ref_col, depth_uv);
if (doThickOutlines) {
if (!any(bvec4(has_edge_pos_x, has_edge_neg_x, has_edge_pos_y, has_edge_neg_y))) {
#ifdef GPU_ARB_texture_gather
ids.x = tmp1.y;
ids.y = tmp2.y;
ids.z = tmp3.y;
ids.w = tmp4.y;
#else
ids.x = textureLod(outlineId, uvs + 2.0 * ofs.xz, 0.0).r;
ids.y = textureLod(outlineId, uvs - 2.0 * ofs.xz, 0.0).r;
ids.z = textureLod(outlineId, uvs + 2.0 * ofs.zy, 0.0).r;
ids.w = textureLod(outlineId, uvs - 2.0 * ofs.zy, 0.0).r;
#endif
bool outline = any(notEqual(id, uvec4(ref_id)));
ivec2 depth_texel = texel;
/* If texel is an outline but has no valid id ...
* replace id and depth texel by a valid one.
* This keeps the outline thickness consistent everywhere. */
if (ref_id == 0u && outline) {
depth_texel = (id.x != 0u) ? texel + ivec2(-1, 0) : depth_texel;
depth_texel = (id.y != 0u) ? texel + ivec2(0, -1) : depth_texel;
depth_texel = (id.z != 0u) ? texel + ivec2(0, 1) : depth_texel;
depth_texel = (id.w != 0u) ? texel + ivec2(1, 0) : depth_texel;
ref_id = (id.x != 0u) ? id.x : ref_id;
ref_id = (id.y != 0u) ? id.y : ref_id;
ref_id = (id.z != 0u) ? id.z : ref_id;
ref_id = (id.w != 0u) ? id.w : ref_id;
has_edge_pos_x = has_edge(ids.x, uvs + 2.0 * ofs.xz, ref, ref_col, depth_uv);
has_edge_neg_x = has_edge(ids.y, uvs - 2.0 * ofs.xz, ref, ref_col, depth_uv);
has_edge_pos_y = has_edge(ids.z, uvs + 2.0 * ofs.zy, ref, ref_col, depth_uv);
has_edge_neg_y = has_edge(ids.w, uvs - 2.0 * ofs.zy, ref, ref_col, depth_uv);
}
}
float ref_depth = texelFetch(outlineDepth, depth_texel, 0).r;
float scene_depth = texelFetch(sceneDepth, depth_texel, 0).r;
if (isXrayWires) {
/* Don't inflate the wire outlines too much. */
has_edge_neg_x = has_edge_neg_y = false;
}
/* WATCH: Keep in sync with outlineId of the prepass. */
uint color_id = ref_col >> 14u;
if (ref_col == 0u) {
fragColor = vec4(0.0);
}
else if (color_id == 1u) {
fragColor = colorSelect;
}
else if (color_id == 2u) {
fragColor = colorDupliSelect;
}
else if (color_id == 3u) {
fragColor = colorActive;
}
else {
fragColor = colorTransform;
}
float ref_depth = textureLod(outlineDepth, depth_uv, 0.0).r;
float scene_depth = textureLod(sceneDepth, depth_uv, 0.0).r;
/* Avoid bad cases of zfighting for occlusion only. */
const float epsilon = 3.0 / 8388608.0;
bool occluded = (ref_depth > scene_depth + epsilon);
/* WATCH: Keep in sync with outlineId of the prepass. */
uint color_id = ref_id >> 14u;
if (ref_id == 0u) {
FragColor = vec4(0.0);
}
else if (color_id == 1u) {
FragColor = colorSelect;
}
else if (color_id == 2u) {
FragColor = colorDupliSelect;
}
else if (color_id == 3u) {
FragColor = colorActive;
}
else {
FragColor = colorTransform;
/* NOTE: We never set alpha to 1.0 to avoid Antialiasing destroying the line. */
fragColor *= (occluded) ? alphaOcclu : (254.0 / 255.0);
float edge_case = 0.0;
edge_case += float(has_edge_pos_x) * 1.0;
edge_case += float(has_edge_neg_x) * 2.0;
edge_case += float(has_edge_pos_y) * 4.0;
edge_case += float(has_edge_neg_y) * 8.0;
vec2 line_start, line_end;
vec2 line_ofs;
bvec4 extra_edges, extra_edges2;
/* TODO simplify this branching hell. */
switch (int(edge_case)) {
/* Straight lines. */
case YPOS:
extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(2.5, 0.5), ref);
extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(-2.5, 0.5), ref);
straight_line_dir(extra_edges, extra_edges2, line_start, line_end);
break;
case YNEG:
extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(-2.5, -0.5), ref);
extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(2.5, -0.5), ref);
extra_edges = rotate_180(extra_edges);
extra_edges2 = rotate_180(extra_edges2);
straight_line_dir(extra_edges, extra_edges2, line_start, line_end);
line_start = rotate_180(line_start);
line_end = rotate_180(line_end);
break;
case XPOS:
extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(0.5, 2.5), ref);
extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(0.5, -2.5), ref);
extra_edges = rotate_90(extra_edges);
extra_edges2 = rotate_90(extra_edges2);
straight_line_dir(extra_edges, extra_edges2, line_start, line_end);
line_start = rotate_90(line_start);
line_end = rotate_90(line_end);
break;
case XNEG:
extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(-0.5, 2.5), ref);
extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(-0.5, -2.5), ref);
extra_edges = rotate_270(extra_edges);
extra_edges2 = rotate_270(extra_edges2);
straight_line_dir(extra_edges, extra_edges2, line_start, line_end);
line_start = rotate_270(line_start);
line_end = rotate_270(line_end);
break;
/* Diagonal */
case DIAG_XNEG_YPOS:
extra_edges = gather_edges(uvs + ofs.xy * vec2(1.5), ref);
diag_dir(extra_edges, line_start, line_end);
break;
case DIAG_XPOS_YNEG:
extra_edges = gather_edges(uvs - ofs.xy * vec2(1.5), ref);
extra_edges = rotate_180(extra_edges);
diag_dir(extra_edges, line_start, line_end);
line_start = rotate_180(line_start);
line_end = rotate_180(line_end);
break;
case DIAG_XPOS_YPOS:
extra_edges = gather_edges(uvs + ofs.xy * vec2(1.5, -1.5), ref);
extra_edges = rotate_90(extra_edges);
diag_dir(extra_edges, line_start, line_end);
line_start = rotate_90(line_start);
line_end = rotate_90(line_end);
break;
case DIAG_XNEG_YNEG:
extra_edges = gather_edges(uvs - ofs.xy * vec2(1.5, -1.5), ref);
extra_edges = rotate_270(extra_edges);
diag_dir(extra_edges, line_start, line_end);
line_start = rotate_270(line_start);
line_end = rotate_270(line_end);
break;
/* Apex */
case APEX_XPOS:
case APEX_XNEG:
line_start = vec2(-0.5, 0.0);
line_end = vec2(0.5, 0.0);
break;
case APEX_YPOS:
case APEX_YNEG:
line_start = vec2(0.0, -0.5);
line_end = vec2(0.0, 0.5);
break;
default:
discard;
}
FragColor.a *= (occluded) ? alphaOcclu : 1.0;
FragColor.a = (outline) ? FragColor.a : 0.0;
lineOutput = pack_line_data(vec2(0.0), line_start, line_end);
}

View File

@ -1,51 +0,0 @@
in vec4 uvcoordsvar;
out vec4 FragColor;
uniform sampler2D outlineColor;
uniform float alpha;
uniform bool doExpand;
void main()
{
ivec2 uv = ivec2(gl_FragCoord.xy);
FragColor = texelFetch(outlineColor, uv, 0).rgba;
vec4 color[4];
color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2(1, 0)).rgba;
color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, 1)).rgba;
color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-1, 0)).rgba;
color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, -1)).rgba;
vec4 values = vec4(color[0].a, color[1].a, color[2].a, color[3].a);
vec4 tests = step(vec4(1e-6), values); /* (color.a != 0.0) */
bvec4 btests = equal(tests, vec4(1.0));
if (FragColor.a != 0.0) {
return;
}
#ifdef LARGE_OUTLINE
if (!any(btests)) {
color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2(2, 0)).rgba;
color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, 2)).rgba;
color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-2, 0)).rgba;
color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, -2)).rgba;
values = vec4(color[0].a, color[1].a, color[2].a, color[3].a);
tests = step(vec4(1e-6), values); /* (color.a != 0.0) */
btests = equal(tests, vec4(1.0));
}
#endif
FragColor = (btests.x) ? color[0] : FragColor;
FragColor = (btests.y) ? color[1] : FragColor;
FragColor = (btests.z) ? color[2] : FragColor;
FragColor = (btests.w) ? color[3] : FragColor;
FragColor.a *= (!doExpand) ? 0.0 : 1.0;
}

View File

@ -1,21 +0,0 @@
in vec4 uvcoordsvar;
out vec4 FragColor;
uniform sampler2D outlineBluredColor;
uniform vec2 rcpDimensions;
void main()
{
#ifdef USE_FXAA
float aa_alpha =
FxaaPixelShader(uvcoordsvar.st, outlineBluredColor, rcpDimensions, 1.0, 0.166, 0.0833).r;
#endif
FragColor = texture(outlineBluredColor, uvcoordsvar.st).rgba;
#ifdef USE_FXAA
FragColor.a = aa_alpha;
#endif
}