diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-06-05 20:35:08 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-06-05 20:35:36 +0300 |
commit | d5ce40a5ed627e9fd37ab094094b2ff5ef286dd2 (patch) | |
tree | 9a9044a73e916eedba2f3ddb2e31048e9babba1a /source/blender/draw | |
parent | 7ff07ddd01af7923f32cfff087ec1f566cb4a0a8 (diff) |
Wireframe: Add slider to hide edges from coplanar faces
The default behaviour is to show the same amount of edges as 2.7.
The slider makes it possible to show all edges or even less.
Diffstat (limited to 'source/blender/draw')
8 files changed, 311 insertions, 32 deletions
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 14addfe9bcb..d6cea03d573 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -526,6 +526,17 @@ void DRW_cache_object_face_wireframe_get( } } +void DRW_cache_object_face_wireframe_pretty_get( + Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count) +{ + switch (ob->type) { + case OB_MESH: + DRW_mesh_batch_cache_get_pretty_wireframes_face_texbuf((Mesh *)ob->data, r_vert_tx, r_faceid_tx, r_tri_count); + + /* TODO, should match 'DRW_cache_object_surface_get' */ + } +} + Gwn_Batch *DRW_cache_object_loose_edges_get(struct Object *ob) { switch (ob->type) { diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 7a1c14b5076..705192653f5 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -56,6 +56,8 @@ struct Gwn_Batch **DRW_cache_object_surface_material_get( char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count); void DRW_cache_object_face_wireframe_get( Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count); +void DRW_cache_object_face_wireframe_pretty_get( + Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count); /* Empties */ struct Gwn_Batch *DRW_cache_plain_axes_get(void); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 0f990c72d01..2824021bb29 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -126,6 +126,8 @@ struct Gwn_Batch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me, /* Object mode Wireframe overlays */ void DRW_mesh_batch_cache_get_wireframes_face_texbuf( struct Mesh *me, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count); +void DRW_mesh_batch_cache_get_pretty_wireframes_face_texbuf( + struct Mesh *me, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count); void DRW_mesh_cache_sculpt_coords_ensure(struct Mesh *me); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index e6dde8adc97..fa78e143e98 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -112,6 +112,10 @@ typedef struct EdgeAdjacentPolys { int face_index[2]; } EdgeAdjacentPolys; +typedef struct EdgeAdjacentVerts { + int vert_index[2]; /* -1 if none */ +} EdgeAdjacentVerts; + typedef struct EdgeDrawAttr { unsigned char v_flag; unsigned char e_flag; @@ -1588,8 +1592,10 @@ typedef struct MeshBatchCache { Gwn_Batch *edge_detection; Gwn_VertBuf *edges_face_overlay; + Gwn_VertBuf *edges_face_overlay_adj; GPUTexture *edges_face_overlay_tx; - int edges_face_overlay_tri_count; /* Number of tri in edges_face_overlay_tx */ + GPUTexture *edges_face_overlay_adj_tx; + int edges_face_overlay_tri_count; /* Number of tri in edges_face_overlay(_adj)_tx */ /* Maybe have shaded_triangles_data split into pos_nor and uv_tangent * to minimise data transfer for skinned mesh. */ @@ -1871,7 +1877,9 @@ static void mesh_batch_cache_clear(Mesh *me) GWN_BATCH_DISCARD_SAFE(cache->edge_detection); GWN_VERTBUF_DISCARD_SAFE(cache->edges_face_overlay); + GWN_VERTBUF_DISCARD_SAFE(cache->edges_face_overlay_adj); DRW_TEXTURE_FREE_SAFE(cache->edges_face_overlay_tx); + DRW_TEXTURE_FREE_SAFE(cache->edges_face_overlay_adj_tx); GWN_VERTBUF_DISCARD_SAFE(cache->shaded_triangles_data); if (cache->shaded_triangles_in_order) { @@ -3341,30 +3349,68 @@ static Gwn_IndexBuf *mesh_batch_cache_get_edges_adjacency(MeshRenderData *rdata, } #undef NO_EDGE -static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData *rdata, MeshBatchCache *cache) +static EdgeHash *create_looptri_edge_adjacency_hash(MeshRenderData *rdata) { - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI)); - - BLI_assert(rdata->edit_bmesh == NULL); /* Not supported in edit mode */ + const int tri_len = mesh_render_data_looptri_len_get(rdata); + /* Create adjacency info in looptri */ + EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3); + /* Create edges for each pair of triangles sharing an edge. */ + for (int i = 0; i < tri_len; i++) { + for (int e = 0; e < 3; ++e) { + uint v0, v1, v2; + if (rdata->edit_bmesh) { + const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; + if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { + break; + } + v0 = BM_elem_index_get(bm_looptri[e]->v); + v1 = BM_elem_index_get(bm_looptri[(e + 1) % 3]->v); + v2 = BM_elem_index_get(bm_looptri[(e + 2) % 3]->v); + } + else { + MLoop *mloop = rdata->mloop; + MLoopTri *mlt = rdata->mlooptri + i; + v0 = mloop[mlt->tri[e]].v; + v1 = mloop[mlt->tri[(e + 1) % 3]].v; + v2 = mloop[mlt->tri[(e + 2) % 3]].v; + } - if (cache->edges_face_overlay_tx != NULL) { - return cache->edges_face_overlay_tx; + EdgeAdjacentVerts **eav; + bool value_is_init = BLI_edgehash_ensure_p(eh, v1, v2, (void ***)&eav); + if (!value_is_init) { + *eav = MEM_mallocN(sizeof(**eav), "EdgeAdjacentVerts"); + (*eav)->vert_index[0] = v0; + (*eav)->vert_index[1] = -1; + } + else { + if ((*eav)->vert_index[1] == -1) { + (*eav)->vert_index[1] = v0; + } + else { + /* Not a manifold edge. */ + } + } + } } + return eh; +} +static Gwn_VertBuf *mesh_batch_cache_create_edges_overlay_adj_texture_buf(MeshRenderData *rdata, bool do_adjacency) +{ const int tri_len = mesh_render_data_looptri_len_get(rdata); - cache->is_manifold = true; - Gwn_VertFormat format = {0}; uint index_id = GWN_vertformat_attr_add(&format, "index", GWN_COMP_I32, 1, GWN_FETCH_INT); Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - cache->edges_face_overlay = vbo; - int vbo_len_capacity = tri_len * 3; + int vbo_len_capacity = tri_len * ((do_adjacency) ? 6 : 3); GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); int vidx = 0; - + EdgeHash *eh = NULL; + if (do_adjacency) { + eh = create_looptri_edge_adjacency_hash(rdata); + } for (int i = 0; i < tri_len; i++) { bool edge_is_real[3] = {false, false, false}; @@ -3386,11 +3432,32 @@ static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData for (int e = 0; e < 3; ++e) { /* Save if there is an edge or not inside the sign bit. */ - int value = (int)mloop[mlt->tri[e]].v + 1; /* Int 0 cannot be signed */ + int v0 = mloop[mlt->tri[e]].v; + int value = (int)v0 + 1; /* Int 0 cannot be signed */ value = (edge_is_real[e]) ? -value : value; GWN_vertbuf_attr_set(vbo, index_id, vidx++, &value); + + if (do_adjacency) { + int v1 = mloop[mlt->tri[(e+1) % 3]].v; + int v2 = mloop[mlt->tri[(e+2) % 3]].v; + EdgeAdjacentVerts *eav = BLI_edgehash_lookup(eh, v0, v1); + int adj_v; + if (eav->vert_index[0] != v2) { + adj_v = eav->vert_index[0]; + } + else if (eav->vert_index[1] != -1) { + adj_v = eav->vert_index[1]; + } + else { + adj_v = v2; /* Non-manifold edge */ + } + GWN_vertbuf_attr_set(vbo, index_id, vidx++, &adj_v); + } } } + if (do_adjacency) { + BLI_edgehash_free(eh, MEM_freeN); + } int vbo_len_used = vidx; @@ -3398,10 +3465,45 @@ static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData GWN_vertbuf_data_resize(vbo, vbo_len_used); } + return vbo; +} + +static GPUTexture *mesh_batch_cache_get_edges_overlay_adj_texture_buf(MeshRenderData *rdata, MeshBatchCache *cache) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI)); + + BLI_assert(rdata->edit_bmesh == NULL); /* Not supported in edit mode */ + + if (cache->edges_face_overlay_adj_tx != NULL) { + return cache->edges_face_overlay_adj_tx; + } + + Gwn_VertBuf *vbo = cache->edges_face_overlay_adj = mesh_batch_cache_create_edges_overlay_adj_texture_buf(rdata, true); + + /* Upload data early because we need to create the texture for it. */ + GWN_vertbuf_use(vbo); + cache->edges_face_overlay_adj_tx = GPU_texture_create_from_vertbuf(vbo); + cache->edges_face_overlay_tri_count = vbo->vertex_alloc / 6; + + return cache->edges_face_overlay_adj_tx; +} + +static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData *rdata, MeshBatchCache *cache) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI)); + + BLI_assert(rdata->edit_bmesh == NULL); /* Not supported in edit mode */ + + if (cache->edges_face_overlay_tx != NULL) { + return cache->edges_face_overlay_tx; + } + + Gwn_VertBuf *vbo = cache->edges_face_overlay = mesh_batch_cache_create_edges_overlay_adj_texture_buf(rdata, false); + /* Upload data early because we need to create the texture for it. */ GWN_vertbuf_use(vbo); cache->edges_face_overlay_tx = GPU_texture_create_from_vertbuf(vbo); - cache->edges_face_overlay_tri_count = vbo_len_used / 3; + cache->edges_face_overlay_tri_count = vbo->vertex_alloc / 3; return cache->edges_face_overlay_tx; } @@ -4027,6 +4129,27 @@ void DRW_mesh_batch_cache_get_wireframes_face_texbuf( *verts_data = cache->pos_in_order_tx; } +void DRW_mesh_batch_cache_get_pretty_wireframes_face_texbuf( + Mesh *me, GPUTexture **verts_data, GPUTexture **face_indices, int *tri_count) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->edges_face_overlay_adj_tx == NULL || cache->pos_in_order_tx == NULL) { + const int options = MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI; + + MeshRenderData *rdata = mesh_render_data_create(me, options); + + mesh_batch_cache_get_edges_overlay_adj_texture_buf(rdata, cache); + mesh_batch_cache_get_vert_pos_and_nor_in_order_buf(rdata, cache); + + mesh_render_data_free(rdata); + } + + *tri_count = cache->edges_face_overlay_tri_count; + *face_indices = cache->edges_face_overlay_adj_tx; + *verts_data = cache->pos_in_order_tx; +} + static void mesh_batch_cache_create_overlay_batches(Mesh *me) { BLI_assert(me->edit_btmesh != NULL); diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c index 131a9bc10db..107d6347c76 100644 --- a/source/blender/draw/modes/overlay_mode.c +++ b/source/blender/draw/modes/overlay_mode.c @@ -52,8 +52,10 @@ typedef struct OVERLAY_Data { } OVERLAY_Data; typedef struct OVERLAY_PrivateData { + GPUShader *wire_sh; /* reference */ DRWShadingGroup *face_orientation_shgrp; View3DOverlay overlay; + float wire_step_param[2]; } OVERLAY_PrivateData; /* Transient data */ /* *********** STATIC *********** */ @@ -62,6 +64,7 @@ static struct { struct GPUShader *face_orientation_sh; /* Wireframe shader */ struct GPUShader *face_wireframe_sh; + struct GPUShader *face_wireframe_pretty_sh; } e_data = {NULL}; /* Shaders */ @@ -93,14 +96,22 @@ static void overlay_engine_init(void *vedata) } if (!e_data.face_wireframe_sh) { - char *wireframe_geom = NULL; - if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { - wireframe_geom = datatoc_overlay_face_wireframe_geom_glsl; - } + bool use_geom = GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY); + e_data.face_wireframe_sh = DRW_shader_create( datatoc_overlay_face_wireframe_vert_glsl, - wireframe_geom, - datatoc_overlay_face_wireframe_frag_glsl, NULL); + use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL, + datatoc_overlay_face_wireframe_frag_glsl, + use_geom ? "#define USE_GEOM_SHADER\n" + : NULL); + + e_data.face_wireframe_pretty_sh = DRW_shader_create( + datatoc_overlay_face_wireframe_vert_glsl, + use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL, + datatoc_overlay_face_wireframe_frag_glsl, + use_geom ? "#define USE_GEOM_SHADER\n" + "#define LIGHT_EDGES\n" + : "#define LIGHT_EDGES\n"); } } @@ -130,6 +141,25 @@ static void overlay_cache_init(void *vedata) if (stl->g_data->overlay.flag & V3D_OVERLAY_WIREFRAMES) { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND; psl->face_wireframe_pass = DRW_pass_create("Face Wires", state); + /* Sticky uniforms (don't need to respecify each time since shader does not change). */ + stl->g_data->wire_sh = (stl->g_data->overlay.wireframe_threshold == 1.0f) ? e_data.face_wireframe_sh + : e_data.face_wireframe_pretty_sh; + DRWShadingGroup *shgrp = DRW_shgroup_create(stl->g_data->wire_sh, psl->face_wireframe_pass); + DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(shgrp, "wireStepParam", stl->g_data->wire_step_param, 1); + + /** + * The wireframe threshold ranges from 0.0 to 1.0 + * When 1.0 we show all the edges, when 0.5 we show as many as 2.7. + * + * If we wanted 0.0 to match 2.7, factor would need to be 0.003f. + * The range controls the falloff effect. If range was 0.0f we would get a hard cut (as in 2.7). + * That said we are using a different algorithm so the results will always differ. + */ + const float factor = 0.006f; + const float range = 0.0025f; + stl->g_data->wire_step_param[1] = (1.0f - factor) + stl->g_data->overlay.wireframe_threshold * factor; + stl->g_data->wire_step_param[0] = stl->g_data->wire_step_param[1] + range; } } @@ -156,19 +186,22 @@ static void overlay_cache_populate(void *vedata, Object *ob) if ((ob != draw_ctx->object_edit) && !BKE_object_is_in_editmode(ob)) { int tri_count; GPUTexture *verts = NULL, *faceids; - DRW_cache_object_face_wireframe_get(ob, &verts, &faceids, &tri_count); + if (stl->g_data->overlay.wireframe_threshold == 1.0f) { + DRW_cache_object_face_wireframe_get(ob, &verts, &faceids, &tri_count); + } + else { + DRW_cache_object_face_wireframe_pretty_get(ob, &verts, &faceids, &tri_count); + } if (verts) { float *rim_col = ts.colorWire; if ((ob->base_flag & BASE_SELECTED) != 0) { rim_col = (ob == draw_ctx->obact) ? ts.colorActive : ts.colorSelect; } - /* TODO(fclem): Compare performance with a geom shader based approach. */ - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.face_wireframe_sh, psl->face_wireframe_pass); + DRWShadingGroup *shgrp = DRW_shgroup_create(stl->g_data->wire_sh, psl->face_wireframe_pass); DRW_shgroup_uniform_texture(shgrp, "vertData", verts); DRW_shgroup_uniform_texture(shgrp, "faceIds", faceids); DRW_shgroup_uniform_vec3(shgrp, "wireColor", ts.colorWire, 1); DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1); - DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1); DRW_shgroup_call_procedural_triangles_add(shgrp, tri_count, ob->obmat); } } @@ -198,6 +231,7 @@ static void overlay_engine_free(void) { DRW_SHADER_FREE_SAFE(e_data.face_orientation_sh); DRW_SHADER_FREE_SAFE(e_data.face_wireframe_sh); + DRW_SHADER_FREE_SAFE(e_data.face_wireframe_pretty_sh); } static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data); diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl index a714de9579a..5dfbb4352e4 100644 --- a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl @@ -6,9 +6,14 @@ flat in vec3 ssVec1; flat in vec3 ssVec2; in float facing; +#ifdef LIGHT_EDGES +flat in vec3 edgeSharpness; +#endif + out vec4 fragColor; float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); } +float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); } /* In pixels */ const float wire_size = 0.0; /* Expands the core of the wire (part that is 100% wire color) */ @@ -27,10 +32,22 @@ void main() dot(ss_pos, ssVec2) ); - float fac = smoothstep(wire_size, wire_size + wire_smooth, min_v3(abs(dist_to_edge))); +#ifdef LIGHT_EDGES + vec3 fac = abs(dist_to_edge); +#else + float fac = min_v3(abs(dist_to_edge)); +#endif + + fac = smoothstep(wire_size + wire_smooth, wire_size, fac); + float facing_clamped = clamp((gl_FrontFacing) ? facing : -facing, 0.0, 1.0); vec3 final_front_col = mix(rimColor, wireColor, 0.05); fragColor = mix(vec4(rimColor, rim_alpha), vec4(final_front_col, front_alpha), facing_clamped); - fragColor.a *= (1.0 - fac); + +#ifdef LIGHT_EDGES + fragColor.a *= max_v3(fac * edgeSharpness); +#else + fragColor.a *= fac; +#endif } diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl index 1cea418419e..8f5712cca03 100644 --- a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl @@ -1,7 +1,12 @@ +/* This shader is only used for intel GPU where the Geom shader is faster + * than doing everything thrice in the vertex shader. */ + layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; +uniform vec2 wireStepParam; + in vec2 ssPos[]; in float facingOut[]; @@ -10,8 +15,16 @@ flat out vec3 ssVec1; flat out vec3 ssVec2; out float facing; +#ifdef LIGHT_EDGES +in vec3 obPos[]; +in vec3 edgeAdj[]; + +flat out vec3 edgeSharpness; +#endif + #define NO_EDGE vec3(10000.0); +/* TODO(fclem) remove code duplication. */ vec3 compute_vec(vec2 v0, vec2 v1) { vec2 v = normalize(v1 - v0); @@ -19,6 +32,13 @@ vec3 compute_vec(vec2 v0, vec2 v1) return vec3(v, -dot(v, v0)); } +float get_edge_sharpness(vec3 e0, vec3 e1, vec3 e2) +{ + vec3 n0 = normalize(cross(e0, e1)); + vec3 n1 = normalize(cross(e1, e2)); + return dot(n0, n1); +} + void main(void) { vec3 facings = vec3(facingOut[0], facingOut[1], facingOut[2]); @@ -29,6 +49,20 @@ void main(void) ssVec1 = do_edge.y ? compute_vec(ssPos[1], ssPos[2]) : NO_EDGE; ssVec2 = do_edge.z ? compute_vec(ssPos[2], ssPos[0]) : NO_EDGE; +#ifdef LIGHT_EDGES + vec3 edges[3]; + edges[0] = obPos[1] - obPos[0]; + edges[1] = obPos[2] - obPos[1]; + edges[2] = obPos[0] - obPos[2]; + + edgeSharpness.x = get_edge_sharpness(edgeAdj[0] - obPos[0], edges[0], -edges[2]); + edgeSharpness.y = get_edge_sharpness(edgeAdj[1] - obPos[1], edges[1], -edges[0]); + edgeSharpness.z = get_edge_sharpness(edgeAdj[2] - obPos[2], edges[2], -edges[1]); + + /* Easy to adjust parameters. */ + edgeSharpness = smoothstep(wireStepParam.xxx, wireStepParam.yyy, edgeSharpness); +#endif + gl_Position = gl_in[0].gl_Position; facing = facings.x; EmitVertex(); diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl index 2cd888e7537..96afb8748b6 100644 --- a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl @@ -1,13 +1,10 @@ -#ifdef GPU_INTEL -#define USE_GEOM_SHADER -#endif - uniform mat4 ModelViewProjectionMatrix; uniform mat4 ModelViewMatrix; uniform mat4 ProjectionMatrix; uniform mat3 NormalMatrix; +uniform vec2 wireStepParam; uniform vec2 viewportSize; uniform float nearDist; @@ -24,6 +21,15 @@ flat out vec3 ssVec2; out float facing; #endif +#ifdef LIGHT_EDGES +#ifdef USE_GEOM_SHADER +out vec3 obPos; +out vec3 edgeAdj; +#else +flat out vec3 edgeSharpness; +#endif +#endif + /* project to screen space */ vec2 proj(vec4 pos) { @@ -73,12 +79,24 @@ vec3 get_vertex_pos(int v_id) return pos; } +float get_edge_sharpness(vec3 e0, vec3 e1, vec3 e2) +{ + vec3 n0 = normalize(cross(e0, e1)); + vec3 n1 = normalize(cross(e1, e2)); + return dot(n0, n1); +} + #define NO_EDGE vec3(10000.0); void main() { #ifdef USE_GEOM_SHADER + +# ifdef LIGHT_EDGES + int v_id = texelFetch(faceIds, gl_VertexID * 2).r; +# else int v_id = texelFetch(faceIds, gl_VertexID).r; +# endif bool do_edge = v_id < 0; v_id = abs(v_id) - 1; @@ -91,15 +109,28 @@ void main() gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); ssPos = proj(gl_Position); +# ifdef LIGHT_EDGES + int adj_id = texelFetch(faceIds, gl_VertexID * 2 + 1).r; + obPos = pos; + edgeAdj = get_vertex_pos(adj_id); +# endif + #else +# ifdef LIGHT_EDGES + int v_0 = (gl_VertexID / 3) * 6; + ivec2 ofs = ivec2(2, 4); /* GL_TRIANGLE_ADJACENCY */ +# else int v_0 = (gl_VertexID / 3) * 3; + ivec2 ofs = ivec2(1, 2); /* GL_TRIANGLES */ +# endif int v_n = gl_VertexID % 3; + /* Getting the same positions for each of the 3 verts. */ ivec3 v_id; v_id.x = texelFetch(faceIds, v_0).r; - v_id.y = texelFetch(faceIds, v_0 + 1).r; - v_id.z = texelFetch(faceIds, v_0 + 2).r; + v_id.y = texelFetch(faceIds, v_0 + ofs.x).r; + v_id.z = texelFetch(faceIds, v_0 + ofs.y).r; bvec3 do_edge = lessThan(v_id, ivec3(0)); v_id = abs(v_id) - 1; @@ -128,5 +159,30 @@ void main() vec3 nor = get_vertex_nor(v_id[v_n]); facing = normalize(NormalMatrix * nor).z; + +# ifdef LIGHT_EDGES + ivec3 adj_id; + adj_id.x = texelFetch(faceIds, v_0 + 1).r; + adj_id.y = texelFetch(faceIds, v_0 + 3).r; + adj_id.z = texelFetch(faceIds, v_0 + 5).r; + + vec3 adj_pos[3]; + adj_pos[0] = get_vertex_pos(adj_id.x); + adj_pos[1] = get_vertex_pos(adj_id.y); + adj_pos[2] = get_vertex_pos(adj_id.z); + + vec3 edges[3]; + edges[0] = pos[1] - pos[0]; + edges[1] = pos[2] - pos[1]; + edges[2] = pos[0] - pos[2]; + + edgeSharpness.x = get_edge_sharpness(adj_pos[0] - pos[0], edges[0], -edges[2]); + edgeSharpness.y = get_edge_sharpness(adj_pos[1] - pos[1], edges[1], -edges[0]); + edgeSharpness.z = get_edge_sharpness(adj_pos[2] - pos[2], edges[2], -edges[1]); + + /* Easy to adjust parameters. */ + edgeSharpness = smoothstep(wireStepParam.xxx, wireStepParam.yyy, edgeSharpness); +# endif + #endif } |