Wireframe: Add slider to hide edges from coplanar faces
authorClément Foucault <foucault.clem@gmail.com>
Tue, 5 Jun 2018 17:35:08 +0000 (19:35 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Tue, 5 Jun 2018 17:35:36 +0000 (19:35 +0200)
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.

13 files changed:
release/scripts/startup/bl_ui/space_view3d.py
source/blender/blenloader/intern/versioning_280.c
source/blender/draw/intern/draw_cache.c
source/blender/draw/intern/draw_cache.h
source/blender/draw/intern/draw_cache_impl.h
source/blender/draw/intern/draw_cache_impl_mesh.c
source/blender/draw/modes/overlay_mode.c
source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl
source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl
source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl
source/blender/editors/space_view3d/space_view3d.c
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesrna/intern/rna_space.c

index 4d680477151688978021821cbb4164fbc9abdb3e..1a70092eb211a6abfc48fa2e9d29233a23d6a25c 100644 (file)
@@ -3573,7 +3573,13 @@ class VIEW3D_PT_overlay(Panel):
         col.prop(overlay, "show_relationship_lines")
         col.prop(overlay, "show_motion_paths")
         col.prop(overlay, "show_face_orientation")
-        col.prop(overlay, "show_wireframes")
+
+        row = col.row()
+        row.prop(overlay, "show_wireframes")
+        sub = row.row()
+        sub.active = overlay.show_wireframes
+        sub.prop(overlay, "wireframe_threshold", text="")
+
         col.prop(overlay, "show_backface_culling")
 
         if shading.type == "MATERIAL":
index 37f308daa3ae0dc01c738071125608a9b5044be2..cbfcce963e3a26617d7f34aba2953702c2e5ccfe 100644 (file)
@@ -1553,5 +1553,17 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
                                }
                        }
                }
+               if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "wireframe_threshold")) {
+                       for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+                               for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+                                       for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+                                               if (sl->spacetype == SPACE_VIEW3D) {
+                                                       View3D *v3d = (View3D *)sl;
+                                                       v3d->overlay.wireframe_threshold = 0.5f;
+                                               }
+                                       }
+                               }
+                       }
+               }
        }
 }
index 14addfe9bcb952982bb958a7e18a6f9ddcb3a3e5..d6cea03d57340517b0740caa3a4575b1b5868657 100644 (file)
@@ -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) {
index 7a1c14b50765bf6517ff22404eac0825fb155cc1..705192653f5320c1b3fb9807d02ab21c6a7010f9 100644 (file)
@@ -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);
index 0f990c72d0172e68a760679e25e5bf334bba076a..2824021bb296d910b77f9d7a82fad0580baa3206 100644 (file)
@@ -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);
 
index e6dde8adc97ccab45790f28c22a0c21a4ba1fb91..fa78e143e9872d6d6c8707883c570723833f4095 100644 (file)
@@ -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);
index 131a9bc10db93298cc8a8a50554bb0983ca90d90..107d6347c767a4aa0e5b48265600dd7a7c2470d5 100644 (file)
@@ -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);
index a714de9579adc0ddc31ca0dd2e2792b4bfb12c58..5dfbb4352e4ffcbcd697d598af57449dc03bb69a 100644 (file)
@@ -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
 }
index 1cea418419e2e6f40547b6c0b827b463054742c0..8f5712cca039d390c6f4f65379476e7c5296832e 100644 (file)
@@ -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();
index 2cd888e7537da4f1f49a335b08bbbf64180b1f09..96afb8748b688f09c4774a6ff6da69bc3ca15f71 100644 (file)
@@ -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
 }
index d4fa98cfc88931139f8c5a8fbf4c0c9e7cdbfa1a..7d8df34264eb2159df839423bffc0f556e59dc43 100644 (file)
@@ -329,6 +329,7 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
        copy_v3_fl(v3d->shading.single_color, 0.8f);
 
        v3d->overlay.flag = V3D_OVERLAY_LOOK_DEV;
+       v3d->overlay.wireframe_threshold = 0.5f;
 
        v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR;
 
index 68da501d452be081ae7bb2497a24ad77cd4e3e8c..c0f13308df6459763beb2465b95c40440b9d1a49 100644 (file)
@@ -166,6 +166,9 @@ typedef struct View3DOverlay {
 
        /* Armature edit/pose mode settings */
        int arm_flag;
+
+       /* Other settings */
+       float wireframe_threshold, pad;
 } View3DOverlay;
 
 /* 3D ViewPort Struct */
index 8bc6391a7614905e427a424faf8ecc6b110dbf42..284e0ea20bc1836285ebdb3484c297737951a5f2 100644 (file)
@@ -2565,6 +2565,14 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Wireframes", "Show face edges wires");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 
+       prop = RNA_def_property(srna, "wireframe_threshold", PROP_FLOAT, PROP_FACTOR);
+       RNA_def_property_float_sdna(prop, NULL, "overlay.wireframe_threshold");
+       RNA_def_property_float_default(prop, 0.5f);
+       RNA_def_property_ui_text(prop, "Wireframe Threshold", "Adjust the number of wires displayed (1 for all wires)");
+       RNA_def_property_range(prop, 0.0f, 1.0f);
+       RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+       RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
        prop = RNA_def_property(srna, "show_paint_wire", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "overlay.paint_flag", V3D_OVERLAY_PAINT_WIRE);
        RNA_def_property_ui_text(prop, "Show Wire", "Use wireframe display in painting modes");