Fix various issues with modifiers and edge display in edit mode

Consistently use edge draw flag instead of original index to determine if an
edge should be drawn or not.

In GPU subdivision the edge original index was used for both edge optimal
display and selection mapping to coarse edges, but they are not the same.
Now match the CPU subdivision logic and use a separate edge draw flag VBO.

For cage display, match Blender 3.3 behavior more in showing/hiding of edges
in wireframe mode. That is edges without a mapping to an original edge are
always hidden when there is no distinct cage, and drawn otherwise. This is
not ideal for e.g. the bevel modifier where it will always show some edges on
corners despite all edges being hidden by the user. But we currently have
no good information to decide if these should be hidden or not, so err on
the side of showing too much as it did before.

Fie #103706: bevel modifier edges not drawn correctly
Fix #103700: optimal display can't be turned of with GPU subdivision
Fix wrong edge display with GPU subdivision preceded by other modifiers

Pull Request #105384
This commit is contained in:
Brecht Van Lommel
2023-03-03 16:38:27 +01:00
committed by Brecht Van Lommel
parent d66672e17a
commit 549cc568b0
9 changed files with 74 additions and 48 deletions

View File

@@ -459,6 +459,9 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage;
mr->edit_data = is_mode_active ? mr->me->runtime->edit_data : nullptr;
/* If there is no distinct cage, hide unmapped edges that can't be selected. */
mr->hide_unmapped_edges = !do_final || editmesh_eval_final == editmesh_eval_cage;
if (mr->edit_data) {
EditMeshData *emd = mr->edit_data;
if (emd->vertexCos) {
@@ -521,6 +524,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->me = me;
mr->edit_bmesh = nullptr;
mr->extract_type = MR_EXTRACT_MESH;
mr->hide_unmapped_edges = false;
if (is_paint_mode && mr->me) {
mr->v_origindex = static_cast<const int *>(

View File

@@ -654,6 +654,7 @@ static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache)
{
GPU_VERTBUF_DISCARD_SAFE(cache->verts_orig_index);
GPU_VERTBUF_DISCARD_SAFE(cache->edges_orig_index);
GPU_VERTBUF_DISCARD_SAFE(cache->edges_draw_flag);
GPU_VERTBUF_DISCARD_SAFE(cache->fdots_patch_coords);
}
@@ -877,11 +878,13 @@ struct DRWCacheBuildingContext {
int *subdiv_loop_vert_index;
int *subdiv_loop_subdiv_vert_index;
int *subdiv_loop_edge_index;
int *subdiv_loop_edge_draw_flag;
int *subdiv_loop_subdiv_edge_index;
int *subdiv_loop_poly_index;
/* Temporary buffers used during traversal. */
int *vert_origindex_map;
int *edge_draw_flag_map;
int *edge_origindex_map;
/* #CD_ORIGINDEX layers from the mesh to directly look up during traversal the original-index
@@ -941,6 +944,11 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
cache->edges_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(cache->edges_orig_index, cache->num_subdiv_loops);
cache->edges_draw_flag = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
cache->edges_draw_flag, get_origindex_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(cache->edges_draw_flag, cache->num_subdiv_loops);
cache->subdiv_loop_subdiv_vert_index = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_subdiv_vert_index"));
@@ -954,6 +962,7 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
ctx->patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(cache->patch_coords);
ctx->subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(cache->verts_orig_index);
ctx->subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(cache->edges_orig_index);
ctx->subdiv_loop_edge_draw_flag = (int *)GPU_vertbuf_get_data(cache->edges_draw_flag);
ctx->subdiv_loop_subdiv_vert_index = cache->subdiv_loop_subdiv_vert_index;
ctx->subdiv_loop_subdiv_edge_index = cache->subdiv_loop_subdiv_edge_index;
ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index;
@@ -978,6 +987,8 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
for (int i = 0; i < num_edges; i++) {
ctx->edge_origindex_map[i] = -1;
}
ctx->edge_draw_flag_map = static_cast<int *>(
MEM_callocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_draw_flag_map"));
}
return true;
@@ -1025,15 +1036,27 @@ static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context,
return;
}
int coarse_index = coarse_edge_index;
if (coarse_index != -1) {
if (ctx->e_origindex) {
coarse_index = ctx->e_origindex[coarse_index];
if (coarse_edge_index == ORIGINDEX_NONE) {
/* Not mapped to edge in the subdivision base mesh. */
ctx->edge_origindex_map[subdiv_edge_index] = ORIGINDEX_NONE;
if (!ctx->cache->optimal_display) {
ctx->edge_draw_flag_map[subdiv_edge_index] = 1;
}
}
else {
if (ctx->e_origindex) {
const int origindex = ctx->e_origindex[coarse_edge_index];
ctx->edge_origindex_map[subdiv_edge_index] = origindex;
if (!(origindex == ORIGINDEX_NONE && ctx->cache->hide_unmapped_edges)) {
/* Not mapped to edge in original mesh (generated by a preceding modifier). */
ctx->edge_draw_flag_map[subdiv_edge_index] = 1;
}
}
else {
ctx->edge_origindex_map[subdiv_edge_index] = coarse_edge_index;
ctx->edge_draw_flag_map[subdiv_edge_index] = 1;
}
}
ctx->edge_origindex_map[subdiv_edge_index] = coarse_index;
}
static void draw_subdiv_loop_cb(const SubdivForeachContext *foreach_context,
@@ -1084,9 +1107,11 @@ static void do_subdiv_traversal(DRWCacheBuildingContext *cache_building_context,
* subdiv-loop-to-coarse-edge map.
*/
for (int i = 0; i < cache_building_context->cache->num_subdiv_loops; i++) {
const int edge_index = cache_building_context->subdiv_loop_subdiv_edge_index[i];
cache_building_context->subdiv_loop_edge_index[i] =
cache_building_context
->edge_origindex_map[cache_building_context->subdiv_loop_subdiv_edge_index[i]];
cache_building_context->edge_origindex_map[edge_index];
cache_building_context->subdiv_loop_edge_draw_flag[i] =
cache_building_context->edge_draw_flag_map[edge_index];
}
}
@@ -1246,6 +1271,7 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
/* Cleanup. */
MEM_SAFE_FREE(cache_building_context.vert_origindex_map);
MEM_SAFE_FREE(cache_building_context.edge_origindex_map);
MEM_SAFE_FREE(cache_building_context.edge_draw_flag_map);
return true;
}
@@ -1276,11 +1302,6 @@ struct DRWSubdivUboStorage {
/* Refined topology information. */
uint num_subdiv_loops;
/* Subdivision settings, is int in C but bool in the GLSL code, as there, bools have the same
* size as ints, so we should use int in C to ensure that the size of the structure is what GLSL
* expects. */
int optimal_display;
/* The sculpt mask data layer may be null. */
int has_sculpt_mask;
@@ -1299,6 +1320,7 @@ struct DRWSubdivUboStorage {
int is_edit_mode;
int use_hide;
int _pad3;
int _pad4;
};
static_assert((sizeof(DRWSubdivUboStorage) % 16) == 0,
@@ -1318,7 +1340,6 @@ static void draw_subdiv_init_ubo_storage(const DRWSubdivCache *cache,
ubo->max_depth = cache->gpu_patch_map.max_depth;
ubo->patches_are_triangular = cache->gpu_patch_map.patches_are_triangular;
ubo->coarse_poly_count = cache->num_coarse_poly;
ubo->optimal_display = cache->optimal_display;
ubo->num_subdiv_loops = cache->num_subdiv_loops;
ubo->edge_loose_offset = cache->num_subdiv_loops * 2;
ubo->has_sculpt_mask = has_sculpt_mask;
@@ -1819,7 +1840,7 @@ void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, GPUIndexBuf *li
int binding_point = 0;
GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->edges_orig_index, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->edges_draw_flag, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
GPU_indexbuf_bind_as_ssbo(lines_indices, binding_point++);
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
@@ -1855,7 +1876,7 @@ void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
GPUVertBuf *pos_nor,
GPUVertBuf *edge_idx,
GPUVertBuf *edge_draw_flag,
GPUVertBuf *edge_fac)
{
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_EDGE_FAC);
@@ -1863,7 +1884,7 @@ void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
int binding_point = 0;
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
GPU_vertbuf_bind_as_ssbo(edge_idx, binding_point++);
GPU_vertbuf_bind_as_ssbo(edge_draw_flag, binding_point++);
GPU_vertbuf_bind_as_ssbo(edge_fac, binding_point++);
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
@@ -2113,17 +2134,18 @@ static bool draw_subdiv_create_requested_buffers(Object *ob,
}
DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache);
draw_cache->optimal_display = runtime_data->use_optimal_display;
/* If there is no distinct cage, hide unmapped edges that can't be selected. */
draw_cache->hide_unmapped_edges = is_editmode && !do_cage;
draw_cache->bm = bm;
draw_cache->mesh = mesh_eval;
draw_cache->subdiv = subdiv;
if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, runtime_data)) {
return false;
}
/* Edges which do not come from coarse edges should not be drawn in edit cage mode. */
const bool optimal_display = runtime_data->use_optimal_display || (is_editmode && !do_cage);
draw_cache->bm = bm;
draw_cache->mesh = mesh_eval;
draw_cache->subdiv = subdiv;
draw_cache->optimal_display = optimal_display;
draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops);
/* Copy topology information for stats display. */

View File

@@ -101,6 +101,7 @@ typedef struct DRWSubdivCache {
struct BMesh *bm;
struct Subdiv *subdiv;
bool optimal_display;
bool hide_unmapped_edges;
bool use_custom_loop_normals;
/* Coordinates used to evaluate patches for positions and normals. */
@@ -148,6 +149,8 @@ typedef struct DRWSubdivCache {
struct GPUVertBuf *verts_orig_index;
/* Maps subdivision loop to original coarse edge index, only really useful for edit mode. */
struct GPUVertBuf *edges_orig_index;
/* Indicates if edge should be drawn in optimal display mode. */
struct GPUVertBuf *edges_draw_flag;
/* Owned by #Subdiv. Indexed by coarse polygon index, difference between value (i + 1) and (i)
* gives the number of ptex faces for coarse polygon (i). */
@@ -259,7 +262,7 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
struct GPUVertBuf *pos_nor,
struct GPUVertBuf *edge_idx,
struct GPUVertBuf *edge_draw_flag,
struct GPUVertBuf *edge_fac);
void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,

View File

@@ -49,6 +49,7 @@ struct MeshRenderData {
bool use_hide;
bool use_subsurf_fdots;
bool use_final_mesh;
bool hide_unmapped_edges;
/** Use for #MeshStatVis calculation which use world-space coords. */
float obmat[4][4];

View File

@@ -58,7 +58,7 @@ static void extract_lines_iter_poly_mesh(const MeshRenderData *mr,
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
/* Using poly & loop iterator would complicate accessing the adjacent loop. */
const MLoop *mloop = mr->mloop;
const int *e_origindex = (mr->edit_bmesh) ? mr->e_origindex : nullptr;
const int *e_origindex = (mr->hide_unmapped_edges) ? mr->e_origindex : nullptr;
if (mr->use_hide || (e_origindex != nullptr)) {
const int ml_index_last = mp->loopstart + (mp->totloop - 1);
int ml_index = ml_index_last, ml_index_next = mp->loopstart;
@@ -109,7 +109,7 @@ static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr,
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
const int l_index_offset = mr->edge_len + ledge_index;
const int e_index = mr->ledges[ledge_index];
const int *e_origindex = (mr->edit_bmesh) ? mr->e_origindex : nullptr;
const int *e_origindex = (mr->hide_unmapped_edges) ? mr->e_origindex : nullptr;
if (!((mr->use_hide && mr->hide_edge && mr->hide_edge[med - mr->medge]) ||
((e_origindex) && (e_origindex[e_index] == ORIGINDEX_NONE)))) {
const int l_index = mr->loop_len + ledge_index * 2;
@@ -183,8 +183,8 @@ static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
switch (mr->extract_type) {
case MR_EXTRACT_MESH: {
const int *e_origindex = (mr->edit_bmesh) ? mr->e_origindex : nullptr;
if (mr->e_origindex == nullptr) {
const int *e_origindex = (mr->hide_unmapped_edges) ? mr->e_origindex : nullptr;
if (e_origindex == nullptr) {
const bool *hide_edge = mr->hide_edge;
if (hide_edge) {
for (DRWSubdivLooseEdge edge : loose_edges) {

View File

@@ -223,23 +223,23 @@ static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
/* Create a temporary buffer for the edge original indices if it was not requested. */
const bool has_edge_idx = edge_idx != nullptr;
GPUVertBuf *loop_edge_idx = nullptr;
GPUVertBuf *loop_edge_draw_flag = nullptr;
if (has_edge_idx) {
loop_edge_idx = edge_idx;
loop_edge_draw_flag = edge_idx;
}
else {
loop_edge_idx = GPU_vertbuf_calloc();
loop_edge_draw_flag = GPU_vertbuf_calloc();
draw_subdiv_init_origindex_buffer(
loop_edge_idx,
static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)),
loop_edge_draw_flag,
static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_draw_flag)),
subdiv_cache->num_subdiv_loops,
0);
}
draw_subdiv_build_edge_fac_buffer(subdiv_cache, pos_nor, loop_edge_idx, vbo);
draw_subdiv_build_edge_fac_buffer(subdiv_cache, pos_nor, loop_edge_draw_flag, vbo);
if (!has_edge_idx) {
GPU_vertbuf_discard(loop_edge_idx);
GPU_vertbuf_discard(loop_edge_draw_flag);
}
}

View File

@@ -1,9 +1,9 @@
/* To be compiled with common_subdiv_lib.glsl */
layout(std430, binding = 1) readonly buffer inputEdgeOrigIndex
layout(std430, binding = 1) readonly buffer inputEdgeDrawFlag
{
int input_origindex[];
int input_edge_draw_flag[];
};
layout(std430, binding = 2) readonly restrict buffer extraCoarseFaceData
@@ -35,8 +35,7 @@ void emit_line(uint line_offset, uint quad_index, uint start_loop_index, uint co
uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
coarse_poly_count);
if (use_hide && is_face_hidden(coarse_quad_index) ||
(input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display)) {
if (use_hide && is_face_hidden(coarse_quad_index) || (input_edge_draw_flag[vertex_index] == 0)) {
output_lines[line_offset + 0] = 0xffffffff;
output_lines[line_offset + 1] = 0xffffffff;
}

View File

@@ -21,9 +21,6 @@ layout(std140) uniform shader_data
/* Subdiv topology information. */
uint num_subdiv_loops;
/* Subdivision settings. */
bool optimal_display;
/* Sculpt data. */
bool has_sculpt_mask;

View File

@@ -6,9 +6,9 @@ layout(std430, binding = 0) readonly buffer inputVertexData
PosNorLoop pos_nor[];
};
layout(std430, binding = 1) readonly buffer inputEdgeIndex
layout(std430, binding = 1) readonly buffer inputEdgeDrawFlag
{
uint input_edge_index[];
uint input_edge_draw_flag[];
};
layout(std430, binding = 2) writeonly buffer outputEdgeFactors
@@ -51,9 +51,9 @@ float loop_edge_factor_get(vec3 f_no, vec3 v_co, vec3 v_no, vec3 v_next_co)
float compute_line_factor(uint start_loop_index, uint corner_index, vec3 face_normal)
{
uint vertex_index = start_loop_index + corner_index;
uint edge_index = input_edge_index[vertex_index];
uint edge_draw_flag = input_edge_draw_flag[vertex_index];
if (edge_index == -1 && optimal_display) {
if (edge_draw_flag == 0) {
return 0.0;
}