diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d.py | 8 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_280.c | 12 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 11 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl.h | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_mesh.c | 151 | ||||
-rw-r--r-- | source/blender/draw/modes/overlay_mode.c | 54 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl | 21 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl | 34 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl | 68 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/space_view3d.c | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_view3d_types.h | 3 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_space.c | 8 |
13 files changed, 342 insertions, 33 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 4d680477151..1a70092eb21 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -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": diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 37f308daa3a..cbfcce963e3 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -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; + } + } + } + } + } } } 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 } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index d4fa98cfc88..7d8df34264e 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -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; diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 68da501d452..c0f13308df6 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -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 */ diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 8bc6391a761..284e0ea20bc 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -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"); |