Mesh: Improvements to position and normal draw extraction #116902

Merged
Hans Goudey merged 23 commits from HooglyBoogly/blender:mesh-extract-normal-fix into main 2024-02-26 16:01:25 +01:00
12 changed files with 407 additions and 528 deletions

View File

@ -63,6 +63,7 @@ set(SRC
intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
intern/mesh_extractors/extract_mesh_vbo_tan.cc
intern/mesh_extractors/extract_mesh_vbo_uv.cc
intern/mesh_extractors/extract_mesh_vbo_vnor.cc
intern/mesh_extractors/extract_mesh_vbo_weights.cc
intern/draw_attributes.cc
intern/draw_cache_impl_curve.cc

View File

@ -74,8 +74,8 @@ struct MeshBufferList {
* (except fdots and skin roots). For some VBOs, it extends to (in this exact order) :
* loops + loose_edges * 2 + loose_verts */
struct {
GPUVertBuf *pos_nor; /* extend */
GPUVertBuf *lnor; /* extend */
GPUVertBuf *pos; /* extend */
GPUVertBuf *nor; /* extend */
GPUVertBuf *edge_fac; /* extend */
GPUVertBuf *weights; /* extend */
GPUVertBuf *uv;
@ -101,6 +101,7 @@ struct MeshBufferList {
GPUVertBuf *fdot_idx;
GPUVertBuf *attr[GPU_MAX_ATTR];
GPUVertBuf *attr_viewer;
GPUVertBuf *vnor;
} vbo;
/* Index Buffers:
* Only need to be updated when topology changes. */

View File

@ -627,8 +627,8 @@ void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
} \
} while (0)
EXTRACT_ADD_REQUESTED(vbo, pos_nor);
EXTRACT_ADD_REQUESTED(vbo, lnor);
EXTRACT_ADD_REQUESTED(vbo, pos);
EXTRACT_ADD_REQUESTED(vbo, nor);
EXTRACT_ADD_REQUESTED(vbo, uv);
EXTRACT_ADD_REQUESTED(vbo, tan);
EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
@ -653,6 +653,7 @@ void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
EXTRACT_ADD_REQUESTED(vbo, attr[i]);
}
EXTRACT_ADD_REQUESTED(vbo, attr_viewer);
EXTRACT_ADD_REQUESTED(vbo, vnor);
EXTRACT_ADD_REQUESTED(ibo, tris);
if (DRW_ibo_requested(mbuflist->ibo.lines_loose)) {
@ -808,11 +809,11 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
EXTRACT_ADD_REQUESTED(ibo, tris);
/* Orcos are extracted at the same time as positions. */
if (DRW_vbo_requested(mbuflist->vbo.pos_nor) || DRW_vbo_requested(mbuflist->vbo.orco)) {
extractors.append(&extract_pos_nor);
if (DRW_vbo_requested(mbuflist->vbo.pos) || DRW_vbo_requested(mbuflist->vbo.orco)) {
extractors.append(&extract_pos);
}
EXTRACT_ADD_REQUESTED(vbo, lnor);
EXTRACT_ADD_REQUESTED(vbo, nor);
for (int i = 0; i < GPU_MAX_ATTR; i++) {
EXTRACT_ADD_REQUESTED(vbo, attr[i]);
}

View File

@ -678,13 +678,15 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->material_indices = *attributes.lookup<int>("material_index", bke::AttrDomain::Face);
mr->hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
mr->hide_edge = *attributes.lookup<bool>(".hide_edge", bke::AttrDomain::Edge);
mr->hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
if (is_mode_active || is_paint_mode) {
mr->hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
mr->hide_edge = *attributes.lookup<bool>(".hide_edge", bke::AttrDomain::Edge);
mr->hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
mr->select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
mr->select_edge = *attributes.lookup<bool>(".select_edge", bke::AttrDomain::Edge);
mr->select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
mr->select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
mr->select_edge = *attributes.lookup<bool>(".select_edge", bke::AttrDomain::Edge);
mr->select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
}
mr->sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
}

View File

@ -97,14 +97,14 @@ namespace blender::draw {
static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index)
{
switch (buffer_index) {
case BUFFER_INDEX(vbo.pos_nor):
case BUFFER_INDEX(vbo.pos):
return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_VERTICES |
MBC_EDIT_EDGES | MBC_EDIT_VNOR | MBC_EDIT_LNOR | MBC_EDIT_MESH_ANALYSIS |
MBC_EDIT_SELECTION_VERTS | MBC_EDIT_SELECTION_EDGES | MBC_EDIT_SELECTION_FACES |
MBC_ALL_VERTS | MBC_ALL_EDGES | MBC_LOOSE_EDGES | MBC_EDGE_DETECTION |
MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_VIEWER_ATTRIBUTE_OVERLAY |
MBC_SURFACE_PER_MAT;
case BUFFER_INDEX(vbo.lnor):
case BUFFER_INDEX(vbo.nor):
return MBC_SURFACE | MBC_EDIT_LNOR | MBC_WIRE_LOOPS | MBC_SURFACE_PER_MAT;
case BUFFER_INDEX(vbo.edge_fac):
return MBC_WIRE_EDGES;
@ -167,6 +167,8 @@ static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index)
return MBC_SURFACE | MBC_SURFACE_PER_MAT;
case BUFFER_INDEX(vbo.attr_viewer):
return MBC_VIEWER_ATTRIBUTE_OVERLAY;
case BUFFER_INDEX(vbo.vnor):
return MBC_EDIT_VNOR;
case BUFFER_INDEX(ibo.tris):
return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR |
MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_FACES | MBC_SCULPT_OVERLAYS |
@ -748,10 +750,10 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *mesh, eMeshBatchDirtyMode mode)
* Note that it can be slow if auto smooth is enabled. (see #63946) */
FOREACH_MESH_BUFFER_CACHE (cache, mbc) {
GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.lines_paint_mask);
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.pos_nor);
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.lnor);
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.pos);
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.nor);
}
batch_map = BATCH_MAP(ibo.lines_paint_mask, vbo.pos_nor, vbo.lnor);
batch_map = BATCH_MAP(ibo.lines_paint_mask, vbo.pos, vbo.nor);
mesh_batch_cache_discard_batch(cache, batch_map);
break;
case BKE_MESH_BATCH_DIRTY_ALL:
@ -1070,8 +1072,8 @@ GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *mesh)
/* Request surface to trigger the vbo filling. Otherwise it may do nothing. */
mesh_batch_cache_request_surface_batches(cache);
DRW_vbo_request(nullptr, &cache.final.buff.vbo.pos_nor);
return cache.final.buff.vbo.pos_nor;
DRW_vbo_request(nullptr, &cache.final.buff.vbo.pos);
return cache.final.buff.vbo.pos;
}
/** \} */
@ -1525,8 +1527,8 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
/* Initialize batches and request VBO's & IBO's. */
assert_deps_valid(MBC_SURFACE,
{BUFFER_INDEX(ibo.tris),
BUFFER_INDEX(vbo.lnor),
BUFFER_INDEX(vbo.pos_nor),
BUFFER_INDEX(vbo.nor),
BUFFER_INDEX(vbo.pos),
BUFFER_INDEX(vbo.uv),
BUFFER_INDEX(vbo.attr[0]),
BUFFER_INDEX(vbo.attr[1]),
@ -1546,65 +1548,63 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
if (DRW_batch_requested(cache.batch.surface, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache.batch.surface, &mbuflist->ibo.tris);
/* Order matters. First ones override latest VBO's attributes. */
DRW_vbo_request(cache.batch.surface, &mbuflist->vbo.lnor);
DRW_vbo_request(cache.batch.surface, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.surface, &mbuflist->vbo.nor);
DRW_vbo_request(cache.batch.surface, &mbuflist->vbo.pos);
if (cache.cd_used.uv != 0) {
DRW_vbo_request(cache.batch.surface, &mbuflist->vbo.uv);
}
drw_add_attributes_vbo(cache.batch.surface, mbuflist, &cache.attr_used);
}
assert_deps_valid(MBC_ALL_VERTS, {BUFFER_INDEX(vbo.pos_nor)});
assert_deps_valid(MBC_ALL_VERTS, {BUFFER_INDEX(vbo.pos)});
if (DRW_batch_requested(cache.batch.all_verts, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache.batch.all_verts, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.all_verts, &mbuflist->vbo.pos);
}
assert_deps_valid(
MBC_SCULPT_OVERLAYS,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.sculpt_data)});
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.sculpt_data)});
if (DRW_batch_requested(cache.batch.sculpt_overlays, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache.batch.sculpt_overlays, &mbuflist->ibo.tris);
DRW_vbo_request(cache.batch.sculpt_overlays, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.sculpt_overlays, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.sculpt_overlays, &mbuflist->vbo.sculpt_data);
}
assert_deps_valid(MBC_ALL_EDGES, {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor)});
assert_deps_valid(MBC_ALL_EDGES, {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos)});
if (DRW_batch_requested(cache.batch.all_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache.batch.all_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache.batch.all_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.all_edges, &mbuflist->vbo.pos);
}
assert_deps_valid(MBC_LOOSE_EDGES, {BUFFER_INDEX(ibo.lines_loose), BUFFER_INDEX(vbo.pos_nor)});
assert_deps_valid(MBC_LOOSE_EDGES, {BUFFER_INDEX(ibo.lines_loose), BUFFER_INDEX(vbo.pos)});
if (DRW_batch_requested(cache.batch.loose_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(nullptr, &mbuflist->ibo.lines);
DRW_ibo_request(cache.batch.loose_edges, &mbuflist->ibo.lines_loose);
DRW_vbo_request(cache.batch.loose_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.loose_edges, &mbuflist->vbo.pos);
}
assert_deps_valid(MBC_EDGE_DETECTION,
{BUFFER_INDEX(ibo.lines_adjacency), BUFFER_INDEX(vbo.pos_nor)});
{BUFFER_INDEX(ibo.lines_adjacency), BUFFER_INDEX(vbo.pos)});
if (DRW_batch_requested(cache.batch.edge_detection, GPU_PRIM_LINES_ADJ)) {
DRW_ibo_request(cache.batch.edge_detection, &mbuflist->ibo.lines_adjacency);
DRW_vbo_request(cache.batch.edge_detection, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.edge_detection, &mbuflist->vbo.pos);
}
assert_deps_valid(
MBC_SURFACE_WEIGHTS,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.weights)});
assert_deps_valid(MBC_SURFACE_WEIGHTS,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.weights)});
if (DRW_batch_requested(cache.batch.surface_weights, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache.batch.surface_weights, &mbuflist->ibo.tris);
DRW_vbo_request(cache.batch.surface_weights, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.surface_weights, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.surface_weights, &mbuflist->vbo.weights);
}
assert_deps_valid(
MBC_WIRE_LOOPS,
{BUFFER_INDEX(ibo.lines_paint_mask), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor)});
{BUFFER_INDEX(ibo.lines_paint_mask), BUFFER_INDEX(vbo.nor), BUFFER_INDEX(vbo.pos)});
if (DRW_batch_requested(cache.batch.wire_loops, GPU_PRIM_LINES)) {
DRW_ibo_request(cache.batch.wire_loops, &mbuflist->ibo.lines_paint_mask);
/* Order matters. First ones override latest VBO's attributes. */
DRW_vbo_request(cache.batch.wire_loops, &mbuflist->vbo.lnor);
DRW_vbo_request(cache.batch.wire_loops, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.wire_loops, &mbuflist->vbo.nor);
DRW_vbo_request(cache.batch.wire_loops, &mbuflist->vbo.pos);
}
assert_deps_valid(
MBC_WIRE_EDGES,
{BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_fac)});
assert_deps_valid(MBC_WIRE_EDGES,
{BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.edge_fac)});
if (DRW_batch_requested(cache.batch.wire_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache.batch.wire_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache.batch.wire_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.wire_edges, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.wire_edges, &mbuflist->vbo.edge_fac);
}
assert_deps_valid(MBC_WIRE_LOOPS_UVS, {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv)});
@ -1617,17 +1617,17 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
}
assert_deps_valid(
MBC_EDIT_MESH_ANALYSIS,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.mesh_analysis)});
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.mesh_analysis)});
if (DRW_batch_requested(cache.batch.edit_mesh_analysis, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache.batch.edit_mesh_analysis, &mbuflist->ibo.tris);
DRW_vbo_request(cache.batch.edit_mesh_analysis, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.edit_mesh_analysis, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.edit_mesh_analysis, &mbuflist->vbo.mesh_analysis);
}
/* Per Material */
assert_deps_valid(
MBC_SURFACE_PER_MAT,
{BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.uv),
{BUFFER_INDEX(vbo.nor), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.uv),
BUFFER_INDEX(vbo.tan), BUFFER_INDEX(vbo.orco), BUFFER_INDEX(vbo.attr[0]),
BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]), BUFFER_INDEX(vbo.attr[3]),
BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]), BUFFER_INDEX(vbo.attr[6]),
@ -1639,8 +1639,8 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
if (DRW_batch_requested(cache.surface_per_mat[i], GPU_PRIM_TRIS)) {
DRW_ibo_request(cache.surface_per_mat[i], &cache.tris_per_mat[i]);
/* Order matters. First ones override latest VBO's attributes. */
DRW_vbo_request(cache.surface_per_mat[i], &mbuflist->vbo.lnor);
DRW_vbo_request(cache.surface_per_mat[i], &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.surface_per_mat[i], &mbuflist->vbo.nor);
DRW_vbo_request(cache.surface_per_mat[i], &mbuflist->vbo.pos);
if (cache.cd_used.uv != 0) {
DRW_vbo_request(cache.surface_per_mat[i], &mbuflist->vbo.uv);
}
@ -1657,41 +1657,44 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
mbuflist = (do_cage) ? &cache.cage.buff : &cache.final.buff;
/* Edit Mesh */
assert_deps_valid(
MBC_EDIT_TRIANGLES,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
assert_deps_valid(MBC_EDIT_TRIANGLES,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache.batch.edit_triangles, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache.batch.edit_triangles, &mbuflist->ibo.tris);
DRW_vbo_request(cache.batch.edit_triangles, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.edit_triangles, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.edit_triangles, &mbuflist->vbo.edit_data);
}
assert_deps_valid(
MBC_EDIT_VERTICES,
{BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
{BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache.batch.edit_vertices, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache.batch.edit_vertices, &mbuflist->ibo.points);
DRW_vbo_request(cache.batch.edit_vertices, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.edit_vertices, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.edit_vertices, &mbuflist->vbo.edit_data);
}
assert_deps_valid(
MBC_EDIT_EDGES,
{BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
assert_deps_valid(MBC_EDIT_EDGES,
{BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache.batch.edit_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache.batch.edit_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache.batch.edit_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.edit_edges, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.edit_edges, &mbuflist->vbo.edit_data);
}
assert_deps_valid(MBC_EDIT_VNOR, {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor)});
assert_deps_valid(MBC_EDIT_VNOR,
{BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.vnor)});
if (DRW_batch_requested(cache.batch.edit_vnor, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache.batch.edit_vnor, &mbuflist->ibo.points);
DRW_vbo_request(cache.batch.edit_vnor, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.edit_vnor, &mbuflist->vbo.pos);
if (!do_subdivision) {
/* For GPU subdivision, vertex normals are included in the `pos` VBO. */
DRW_vbo_request(cache.batch.edit_vnor, &mbuflist->vbo.vnor);
}
}
assert_deps_valid(MBC_EDIT_LNOR,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.lnor)});
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.nor)});
if (DRW_batch_requested(cache.batch.edit_lnor, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache.batch.edit_lnor, &mbuflist->ibo.tris);
DRW_vbo_request(cache.batch.edit_lnor, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.edit_lnor, &mbuflist->vbo.lnor);
DRW_vbo_request(cache.batch.edit_lnor, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.edit_lnor, &mbuflist->vbo.nor);
}
assert_deps_valid(
MBC_EDIT_FACEDOTS,
@ -1707,28 +1710,25 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
}
/* Selection */
assert_deps_valid(
MBC_EDIT_SELECTION_VERTS,
{BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.vert_idx)});
assert_deps_valid(MBC_EDIT_SELECTION_VERTS,
{BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.vert_idx)});
if (DRW_batch_requested(cache.batch.edit_selection_verts, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache.batch.edit_selection_verts, &mbuflist->ibo.points);
DRW_vbo_request(cache.batch.edit_selection_verts, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.edit_selection_verts, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.edit_selection_verts, &mbuflist->vbo.vert_idx);
}
assert_deps_valid(
MBC_EDIT_SELECTION_EDGES,
{BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_idx)});
assert_deps_valid(MBC_EDIT_SELECTION_EDGES,
{BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.edge_idx)});
if (DRW_batch_requested(cache.batch.edit_selection_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache.batch.edit_selection_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache.batch.edit_selection_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.edit_selection_edges, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.edit_selection_edges, &mbuflist->vbo.edge_idx);
}
assert_deps_valid(
MBC_EDIT_SELECTION_FACES,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.face_idx)});
assert_deps_valid(MBC_EDIT_SELECTION_FACES,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.face_idx)});
if (DRW_batch_requested(cache.batch.edit_selection_faces, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache.batch.edit_selection_faces, &mbuflist->ibo.tris);
DRW_vbo_request(cache.batch.edit_selection_faces, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.edit_selection_faces, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.edit_selection_faces, &mbuflist->vbo.face_idx);
}
assert_deps_valid(
@ -1805,10 +1805,10 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
}
assert_deps_valid(
MBC_VIEWER_ATTRIBUTE_OVERLAY,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.attr_viewer)});
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.attr_viewer)});
if (DRW_batch_requested(cache.batch.surface_viewer_attribute, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache.batch.surface_viewer_attribute, &mbuflist->ibo.tris);
DRW_vbo_request(cache.batch.surface_viewer_attribute, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache.batch.surface_viewer_attribute, &mbuflist->vbo.pos);
DRW_vbo_request(cache.batch.surface_viewer_attribute, &mbuflist->vbo.attr_viewer);
}
@ -1817,8 +1817,8 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
BLI_assert(batches_that_use_buffer(buffer_index) ==
batches_that_use_buffer_local.lookup(buffer_index));
};
assert_final_deps_valid(BUFFER_INDEX(vbo.lnor));
assert_final_deps_valid(BUFFER_INDEX(vbo.pos_nor));
assert_final_deps_valid(BUFFER_INDEX(vbo.nor));
assert_final_deps_valid(BUFFER_INDEX(vbo.pos));
assert_final_deps_valid(BUFFER_INDEX(vbo.uv));
assert_final_deps_valid(BUFFER_INDEX(vbo.sculpt_data));
assert_final_deps_valid(BUFFER_INDEX(vbo.weights));
@ -1843,6 +1843,7 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
assert_final_deps_valid(BUFFER_INDEX(vbo.attr[i]));
}
assert_final_deps_valid(BUFFER_INDEX(vbo.attr_viewer));
assert_final_deps_valid(BUFFER_INDEX(vbo.vnor));
assert_final_deps_valid(BUFFER_INDEX(ibo.tris));
assert_final_deps_valid(BUFFER_INDEX(ibo.lines));

View File

@ -52,11 +52,8 @@ eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *extractor)
{
if (extractor == &extract_pos_nor) {
return &extract_pos_nor_hq;
}
if (extractor == &extract_lnor) {
return &extract_lnor_hq;
if (extractor == &extract_nor) {
return &extract_nor_hq;
}
if (extractor == &extract_tan) {
return &extract_tan_hq;

View File

@ -329,6 +329,9 @@ void mesh_render_data_loop_edge_flag(const MeshRenderData &mr,
BMUVOffsets offsets,
EditLoopData *eattr);
template<typename GPUType>
void extract_vert_normals(const MeshRenderData &mr, MutableSpan<GPUType> normals);
extern const MeshExtract extract_tris;
extern const MeshExtract extract_tris_single_mat;
extern const MeshExtract extract_lines;
@ -342,10 +345,9 @@ extern const MeshExtract extract_edituv_tris;
extern const MeshExtract extract_edituv_lines;
extern const MeshExtract extract_edituv_points;
extern const MeshExtract extract_edituv_fdots;
extern const MeshExtract extract_pos_nor;
extern const MeshExtract extract_pos_nor_hq;
extern const MeshExtract extract_lnor_hq;
extern const MeshExtract extract_lnor;
extern const MeshExtract extract_pos;
extern const MeshExtract extract_nor_hq;
extern const MeshExtract extract_nor;
extern const MeshExtract extract_uv;
extern const MeshExtract extract_tan;
extern const MeshExtract extract_tan_hq;
@ -371,5 +373,6 @@ extern const MeshExtract extract_vert_idx;
extern const MeshExtract extract_fdot_idx;
extern const MeshExtract extract_attr[GPU_MAX_ATTR];
extern const MeshExtract extract_attr_viewer;
extern const MeshExtract extract_vnor;
} // namespace blender::draw

View File

@ -291,7 +291,7 @@ static void extract_edge_fac_init_subdiv(const DRWSubdivCache &subdiv_cache,
GPU_vertbuf_init_build_on_device(
vbo, get_subdiv_edge_fac_format(), subdiv_cache.num_subdiv_loops + loose_geom.loop_len);
GPUVertBuf *pos_nor = cache.final.buff.vbo.pos_nor;
GPUVertBuf *pos_nor = cache.final.buff.vbo.pos;
GPUVertBuf *poly_other_map = build_poly_other_map_vbo(subdiv_cache);
draw_subdiv_build_edge_fac_buffer(

View File

@ -233,7 +233,7 @@ static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache &subdi
GPU_vertbuf_init_build_on_device(
refined_vbo, get_edituv_stretch_angle_format_subdiv(), subdiv_cache.num_subdiv_loops);
GPUVertBuf *pos_nor = cache.final.buff.vbo.pos_nor;
GPUVertBuf *pos_nor = cache.final.buff.vbo.pos;
GPUVertBuf *uvs = cache.final.buff.vbo.uv;
/* It may happen that the data for the UV editor is requested before (as a separate draw update)
@ -282,7 +282,7 @@ static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache &subdi
draw_subdiv_build_edituv_stretch_angle_buffer(
subdiv_cache, pos_nor, uvs, uvs_offset, refined_vbo);
if (!cache.final.buff.vbo.pos_nor) {
if (!cache.final.buff.vbo.pos) {
GPU_vertbuf_discard(pos_nor);
}
}

View File

@ -6,6 +6,8 @@
* \ingroup draw
*/
#include "BLI_array_utils.hh"
#include "extract_mesh.hh"
#include "draw_subdivision.hh"
@ -16,6 +18,139 @@ namespace blender::draw {
/** \name Extract Loop Normal
* \{ */
template<typename GPUType> inline GPUType convert_normal(const float3 &src);
template<> inline GPUPackedNormal convert_normal(const float3 &src)
{
return GPU_normal_convert_i10_v3(src);
}
template<> inline short4 convert_normal(const float3 &src)
{
short4 dst;
normal_float_to_short_v3(dst, src);
return dst;
}
template<typename GPUType>
static void extract_normals(const Span<float3> src, MutableSpan<GPUType> dst)
{
threading::parallel_for(src.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
dst[i] = convert_normal<GPUType>(src[i]);
}
});
}
template<typename GPUType>
static void extract_vert_normals_impl(const MeshRenderData &mr, MutableSpan<GPUType> normals)
{
Array<GPUType> vert_normals_converted(mr.vert_normals.size());
extract_normals(mr.vert_normals, vert_normals_converted.as_mutable_span());
array_utils::gather(vert_normals_converted.as_span(), mr.corner_verts, normals);
}
template<>
void extract_vert_normals(const MeshRenderData &mr, MutableSpan<GPUPackedNormal> normals)
{
extract_vert_normals_impl(mr, normals);
}
template<> void extract_vert_normals(const MeshRenderData &mr, MutableSpan<short4> normals)
{
extract_vert_normals_impl(mr, normals);
}
template<typename GPUType>
static void extract_face_normals(const MeshRenderData &mr, MutableSpan<GPUType> normals)
{
const OffsetIndices faces = mr.faces;
const Span<float3> face_normals = mr.face_normals;
threading::parallel_for(faces.index_range(), 4096, [&](const IndexRange range) {
for (const int face : range) {
normals.slice(faces[face]).fill(convert_normal<GPUType>(face_normals[face]));
}
});
}
template<typename GPUType>
static void extract_normals_mesh(const MeshRenderData &mr, MutableSpan<GPUType> normals)
{
if (mr.normals_domain == bke::MeshNormalDomain::Face) {
extract_face_normals(mr, normals);
}
else if (mr.normals_domain == bke::MeshNormalDomain::Point) {
extract_vert_normals(mr, normals);
}
else if (!mr.corner_normals.is_empty()) {
extract_normals(mr.corner_normals, normals);
}
else if (mr.sharp_faces.is_empty()) {
extract_vert_normals(mr, normals);
}
else {
const OffsetIndices faces = mr.faces;
const Span<int> corner_verts = mr.corner_verts;
const Span<bool> sharp_faces = mr.sharp_faces;
const Span<float3> vert_normals = mr.vert_normals;
const Span<float3> face_normals = mr.face_normals;
threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
for (const int face : range) {
if (sharp_faces[face]) {
normals.slice(faces[face]).fill(convert_normal<GPUType>(face_normals[face]));
}
else {
for (const int corner : faces[face]) {
normals[corner] = convert_normal<GPUType>(vert_normals[corner_verts[corner]]);
}
}
}
});
}
}
template<typename GPUType>
static void extract_paint_overlay_flags(const MeshRenderData &mr, MutableSpan<GPUType> normals)
{
if (mr.select_poly.is_empty() && mr.hide_poly.is_empty() && (!mr.edit_bmesh || !mr.v_origindex))
{
return;
}
const OffsetIndices faces = mr.faces;
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
if (!mr.select_poly.is_empty()) {
const Span<bool> select_poly = mr.select_poly;
for (const int face : range) {
if (select_poly[face]) {
for (const int corner : faces[face]) {
normals[corner].w = 1;
}
}
}
}
if (!mr.hide_poly.is_empty()) {
const Span<bool> hide_poly = mr.hide_poly;
for (const int face : range) {
if (hide_poly[face]) {
for (const int corner : faces[face]) {
normals[corner].w = -1;
}
}
}
}
if (mr.edit_bmesh && mr.v_origindex) {
const Span<int> corner_verts = mr.corner_verts;
const Span<int> orig_indices(mr.v_origindex, mr.vert_len);
for (const int face : range) {
for (const int corner : faces[face]) {
if (orig_indices[corner_verts[corner]] == ORIGINDEX_NONE) {
normals[corner].w = -1;
}
}
}
}
});
}
static void extract_lnor_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
@ -30,76 +165,51 @@ static void extract_lnor_init(const MeshRenderData &mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr.loop_len);
*(GPUPackedNormal **)tls_data = static_cast<GPUPackedNormal *>(GPU_vertbuf_get_data(vbo));
if (mr.extract_type == MR_EXTRACT_MESH) {
MutableSpan vbo_data(static_cast<GPUPackedNormal *>(GPU_vertbuf_get_data(vbo)), mr.loop_len);
extract_normals_mesh(mr, vbo_data);
extract_paint_overlay_flags(mr, vbo_data);
}
else {
*static_cast<GPUPackedNormal **>(tls_data) = static_cast<GPUPackedNormal *>(
GPU_vertbuf_get_data(vbo));
}
}
static void extract_lnor_iter_face_bm(const MeshRenderData &mr,
const BMFace *f,
const int /*f_index*/,
void *data)
void *data_v)
{
GPUPackedNormal *data = *(GPUPackedNormal **)data_v;
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
const int l_index = BM_elem_index_get(l_iter);
GPUPackedNormal *lnor_data = &(*(GPUPackedNormal **)data)[l_index];
if (!mr.corner_normals.is_empty()) {
*lnor_data = GPU_normal_convert_i10_v3(mr.corner_normals[l_index]);
data[l_index] = GPU_normal_convert_i10_v3(mr.corner_normals[l_index]);
}
else {
if (mr.normals_domain == bke::MeshNormalDomain::Face ||
!BM_elem_flag_test(f, BM_ELEM_SMOOTH))
{
*lnor_data = GPU_normal_convert_i10_v3(bm_face_no_get(mr, f));
data[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, f));
}
else {
*lnor_data = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, l_iter->v));
data[l_index] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, l_iter->v));
}
}
lnor_data->w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0;
data[l_index].w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0;
} while ((l_iter = l_iter->next) != l_first);
}
static void extract_lnor_iter_face_mesh(const MeshRenderData &mr, const int face_index, void *data)
{
const bool hidden = !mr.hide_poly.is_empty() && mr.hide_poly[face_index];
for (const int corner : mr.faces[face_index]) {
const int vert = mr.corner_verts[corner];
GPUPackedNormal *lnor_data = &(*(GPUPackedNormal **)data)[corner];
if (!mr.corner_normals.is_empty()) {
*lnor_data = GPU_normal_convert_i10_v3(mr.corner_normals[corner]);
}
else if (mr.normals_domain == bke::MeshNormalDomain::Face ||
(!mr.sharp_faces.is_empty() && mr.sharp_faces[face_index]))
{
*lnor_data = GPU_normal_convert_i10_v3(mr.face_normals[face_index]);
}
else {
*lnor_data = GPU_normal_convert_i10_v3(mr.vert_normals[vert]);
}
/* Flag for paint mode overlay.
* Only use origindex in edit mode where it is used to display the edge-normals.
* In paint mode it will use the un-mapped data to draw the wire-frame. */
if (hidden || (mr.edit_bmesh && (mr.v_origindex) && mr.v_origindex[vert] == ORIGINDEX_NONE)) {
lnor_data->w = -1;
}
else if (!mr.select_poly.is_empty() && mr.select_poly[face_index]) {
lnor_data->w = 1;
}
else {
lnor_data->w = 0;
}
}
}
static GPUVertFormat *get_subdiv_lnor_format()
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPU_vertformat_alias_add(&format, "lnor");
GPU_vertformat_alias_add(&format, "vnor");
}
return &format;
}
@ -111,7 +221,7 @@ static void extract_lnor_init_subdiv(const DRWSubdivCache &subdiv_cache,
void * /*data*/)
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
GPUVertBuf *pos_nor = cache.final.buff.vbo.pos_nor;
GPUVertBuf *pos_nor = cache.final.buff.vbo.pos;
BLI_assert(pos_nor);
GPU_vertbuf_init_build_on_device(vbo, get_subdiv_lnor_format(), subdiv_cache.num_subdiv_loops);
draw_subdiv_build_lnor_buffer(subdiv_cache, pos_nor, vbo);
@ -123,11 +233,10 @@ constexpr MeshExtract create_extractor_lnor()
extractor.init = extract_lnor_init;
extractor.init_subdiv = extract_lnor_init_subdiv;
extractor.iter_face_bm = extract_lnor_iter_face_bm;
extractor.iter_face_mesh = extract_lnor_iter_face_mesh;
extractor.data_type = MR_DATA_LOOP_NOR;
extractor.data_size = sizeof(GPUPackedNormal *);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.lnor);
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.nor);
return extractor;
}
@ -137,10 +246,6 @@ constexpr MeshExtract create_extractor_lnor()
/** \name Extract HQ Loop Normal
* \{ */
struct gpuHQNor {
short x, y, z, w;
};
static void extract_lnor_hq_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
@ -155,7 +260,14 @@ static void extract_lnor_hq_init(const MeshRenderData &mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr.loop_len);
*(gpuHQNor **)tls_data = static_cast<gpuHQNor *>(GPU_vertbuf_get_data(vbo));
if (mr.extract_type == MR_EXTRACT_MESH) {
MutableSpan vbo_data(static_cast<short4 *>(GPU_vertbuf_get_data(vbo)), mr.loop_len);
extract_normals_mesh(mr, vbo_data);
extract_paint_overlay_flags(mr, vbo_data);
}
else {
*(short4 **)tls_data = static_cast<short4 *>(GPU_vertbuf_get_data(vbo));
}
}
static void extract_lnor_hq_iter_face_bm(const MeshRenderData &mr,
@ -168,72 +280,35 @@ static void extract_lnor_hq_iter_face_bm(const MeshRenderData &mr,
do {
const int l_index = BM_elem_index_get(l_iter);
if (!mr.corner_normals.is_empty()) {
normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, mr.corner_normals[l_index]);
normal_float_to_short_v3(&(*(short4 **)data)[l_index].x, mr.corner_normals[l_index]);
}
else {
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, bm_vert_no_get(mr, l_iter->v));
normal_float_to_short_v3(&(*(short4 **)data)[l_index].x, bm_vert_no_get(mr, l_iter->v));
}
else {
normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, bm_face_no_get(mr, f));
normal_float_to_short_v3(&(*(short4 **)data)[l_index].x, bm_face_no_get(mr, f));
}
}
} while ((l_iter = l_iter->next) != l_first);
}
static void extract_lnor_hq_iter_face_mesh(const MeshRenderData &mr,
const int face_index,
void *data)
{
const bool hidden = !mr.hide_poly.is_empty() && mr.hide_poly[face_index];
for (const int corner : mr.faces[face_index]) {
const int vert = mr.corner_verts[corner];
gpuHQNor *lnor_data = &(*(gpuHQNor **)data)[corner];
if (!mr.corner_normals.is_empty()) {
normal_float_to_short_v3(&lnor_data->x, mr.corner_normals[corner]);
}
else if (mr.normals_domain == bke::MeshNormalDomain::Face ||
(!mr.sharp_faces.is_empty() && mr.sharp_faces[face_index]))
{
normal_float_to_short_v3(&lnor_data->x, mr.face_normals[face_index]);
}
else {
normal_float_to_short_v3(&lnor_data->x, mr.vert_normals[vert]);
}
/* Flag for paint mode overlay.
* Only use origindex in edit mode where it is used to display the edge-normals.
* In paint mode it will use the un-mapped data to draw the wire-frame. */
if (hidden || (mr.edit_bmesh && (mr.v_origindex) && mr.v_origindex[vert] == ORIGINDEX_NONE)) {
lnor_data->w = -1;
}
else if (!mr.select_poly.is_empty() && mr.select_poly[face_index]) {
lnor_data->w = 1;
}
else {
lnor_data->w = 0;
}
}
}
constexpr MeshExtract create_extractor_lnor_hq()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_lnor_hq_init;
extractor.init_subdiv = extract_lnor_init_subdiv;
extractor.iter_face_bm = extract_lnor_hq_iter_face_bm;
extractor.iter_face_mesh = extract_lnor_hq_iter_face_mesh;
extractor.data_type = MR_DATA_LOOP_NOR;
extractor.data_size = sizeof(gpuHQNor *);
extractor.data_size = sizeof(short4 *);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.lnor);
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.nor);
return extractor;
}
/** \} */
const MeshExtract extract_lnor = create_extractor_lnor();
const MeshExtract extract_lnor_hq = create_extractor_lnor_hq();
const MeshExtract extract_nor = create_extractor_lnor();
const MeshExtract extract_nor_hq = create_extractor_lnor_hq();
} // namespace blender::draw

View File

@ -6,7 +6,7 @@
* \ingroup draw
*/
#include "MEM_guardedalloc.h"
#include "BLI_array_utils.hh"
#include "extract_mesh.hh"
@ -18,162 +18,84 @@ namespace blender::draw {
/** \name Extract Position and Vertex Normal
* \{ */
struct PosNorLoop {
float pos[3];
GPUPackedNormal nor;
};
static void extract_mesh_loose_edge_positions(const Span<float3> vert_positions,
const Span<int2> edges,
const Span<int> loose_edge_indices,
MutableSpan<float3> positions)
{
threading::parallel_for(loose_edge_indices.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
const int2 edge = edges[loose_edge_indices[i]];
positions[i * 2 + 0] = vert_positions[edge[0]];
positions[i * 2 + 1] = vert_positions[edge[1]];
}
});
}
struct MeshExtract_PosNor_Data {
PosNorLoop *vbo_data;
GPUNormal *normals;
};
static void extract_pos_nor_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void *tls_data)
static void extract_pos_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void *tls_data)
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING Adjust #PosNorLoop struct accordingly. */
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "vnor");
}

vnor should be kept as alias to vertex normal for edit mode. I don't know where this resides after this patch.

Here, removing GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); makes the alias vnor and alias of pos

If nor is present in multiple VBO, the latest VBO in a GPUBatch takes predecence.
I guess this is no longer wanted after this patch, where only one of the normal (vnor/lnor) would be bound to a GPUBatch.

`vnor` should be kept as alias to vertex normal for edit mode. I don't know where this resides after this patch. Here, removing `GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);` makes the alias `vnor` and alias of `pos` If `nor` is present in multiple VBO, the latest VBO in a `GPUBatch` takes predecence. I guess this is no longer wanted after this patch, where only one of the normal (vnor/lnor) would be bound to a `GPUBatch`.
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr.loop_len + mr.loop_loose_len);
/* Pack normals per vert, reduce amount of computation. */
MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(tls_data);
data->vbo_data = static_cast<PosNorLoop *>(GPU_vertbuf_get_data(vbo));
data->normals = (GPUNormal *)MEM_mallocN(sizeof(GPUNormal) * mr.vert_len, __func__);
/* Quicker than doing it for each loop. */
if (mr.extract_type == MR_EXTRACT_BMESH) {
BMIter iter;
BMVert *eve;
int v;
BM_ITER_MESH_INDEX (eve, &iter, mr.bm, BM_VERTS_OF_MESH, v) {
data->normals[v].low = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, eve));
}
MutableSpan vbo_data(static_cast<float3 *>(GPU_vertbuf_get_data(vbo)),
GPU_vertbuf_get_vertex_len(vbo));
if (mr.extract_type == MR_EXTRACT_MESH) {
array_utils::gather(
mr.vert_positions, mr.corner_verts, vbo_data.take_front(mr.corner_verts.size()));
extract_mesh_loose_edge_positions(mr.vert_positions,
mr.edges,
mr.loose_edges,
vbo_data.slice(mr.loop_len, mr.loose_edges.size() * 2));
array_utils::gather(
mr.vert_positions, mr.loose_verts, vbo_data.take_back(mr.loose_verts.size()));
}
else {
for (int v = 0; v < mr.vert_len; v++) {
data->normals[v].low = GPU_normal_convert_i10_v3(mr.vert_normals[v]);
}
*static_cast<float3 **>(tls_data) = vbo_data.data();
}
}
static void extract_pos_nor_iter_face_bm(const MeshRenderData &mr,
const BMFace *f,
const int /*f_index*/,
void *_data)
static void extract_pos_iter_face_bm(const MeshRenderData &mr,
const BMFace *f,
const int /*f_index*/,
void *_data)
{
MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data);
float3 *data = *static_cast<float3 **>(_data);
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
const int l_index = BM_elem_index_get(l_iter);
PosNorLoop *vert = &data->vbo_data[l_index];
copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v));
vert->nor = data->normals[BM_elem_index_get(l_iter->v)].low;
vert->nor.w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0;
data[l_index] = bm_vert_co_get(mr, l_iter->v);
} while ((l_iter = l_iter->next) != l_first);
}
static void extract_pos_nor_iter_face_mesh(const MeshRenderData &mr,
const int face_index,
static void extract_pos_iter_loose_edge_bm(const MeshRenderData &mr,
const BMEdge *eed,
const int loose_edge_i,
void *_data)
{
MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data);
const bool poly_hidden = !mr.hide_poly.is_empty() && mr.hide_poly[face_index];
for (const int corner : mr.faces[face_index]) {
const int vert_i = mr.corner_verts[corner];
PosNorLoop *vert = &data->vbo_data[corner];
const bool vert_hidden = !mr.hide_vert.is_empty() && mr.hide_vert[vert_i];
copy_v3_v3(vert->pos, mr.vert_positions[vert_i]);
vert->nor = data->normals[vert_i].low;
/* Flag for paint mode overlay. */
if (poly_hidden || vert_hidden ||
((mr.v_origindex) && (mr.v_origindex[vert_i] == ORIGINDEX_NONE)))
{
vert->nor.w = -1;
}
else if (!mr.select_vert.is_empty() && mr.select_vert[vert_i]) {
vert->nor.w = 1;
}
else {
vert->nor.w = 0;
}
}
float3 *data = *static_cast<float3 **>(_data);
int index = mr.loop_len + loose_edge_i * 2;
data[index + 0] = bm_vert_co_get(mr, eed->v1);
data[index + 1] = bm_vert_co_get(mr, eed->v2);
}
static void extract_pos_nor_iter_loose_edge_bm(const MeshRenderData &mr,
const BMEdge *eed,
const int loose_edge_i,
void *_data)
static void extract_pos_iter_loose_vert_bm(const MeshRenderData &mr,
const BMVert *eve,
const int loose_vert_i,
void *_data)
{
MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data);
int l_index = mr.loop_len + loose_edge_i * 2;
PosNorLoop *vert = &data->vbo_data[l_index];
copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
vert[0].nor = data->normals[BM_elem_index_get(eed->v1)].low;
vert[1].nor = data->normals[BM_elem_index_get(eed->v2)].low;
}
static void extract_pos_nor_iter_loose_edge_mesh(const MeshRenderData &mr,
const int2 edge,
const int loose_edge_i,
void *_data)
{
MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data);
const int index = mr.loop_len + loose_edge_i * 2;
PosNorLoop *vert = &data->vbo_data[index];
copy_v3_v3(vert[0].pos, mr.vert_positions[edge[0]]);
copy_v3_v3(vert[1].pos, mr.vert_positions[edge[1]]);
vert[0].nor = data->normals[edge[0]].low;
vert[1].nor = data->normals[edge[1]].low;
}
static void extract_pos_nor_iter_loose_vert_bm(const MeshRenderData &mr,
const BMVert *eve,
const int loose_vert_i,
void *_data)
{
MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data);
float3 *data = *static_cast<float3 **>(_data);
const int offset = mr.loop_len + (mr.edge_loose_len * 2);
const int l_index = offset + loose_vert_i;
PosNorLoop *vert = &data->vbo_data[l_index];
copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
vert->nor = data->normals[BM_elem_index_get(eve)].low;
}
static void extract_pos_nor_iter_loose_vert_mesh(const MeshRenderData &mr,
const int loose_vert_i,
void *_data)
{
MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data);
const int offset = mr.loop_len + (mr.edge_loose_len * 2);
const int index = offset + loose_vert_i;
const int v_index = mr.loose_verts[loose_vert_i];
PosNorLoop *vert = &data->vbo_data[index];
copy_v3_v3(vert->pos, mr.vert_positions[v_index]);
vert->nor = data->normals[v_index].low;
}
static void extract_pos_nor_finish(const MeshRenderData & /*mr*/,
MeshBatchCache & /*cache*/,
void * /*buf*/,
void *_data)
{
MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data);
MEM_freeN(data->normals);
data[index] = bm_vert_co_get(mr, eve);
}
static GPUVertFormat *get_normals_format()
@ -214,11 +136,11 @@ static void extract_vertex_flags(const MeshRenderData &mr, char *flags)
}
}
static void extract_pos_nor_init_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
MeshBatchCache &cache,
void *buffer,
void * /*data*/)
static void extract_pos_init_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
MeshBatchCache &cache,
void *buffer,
void * /*data*/)
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
const DRWSubdivLooseGeom &loose_geom = subdiv_cache.loose_geom;
@ -307,10 +229,10 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache &subdiv_cache,
GPU_vertbuf_discard(flags_buffer);
}
static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData & /*mr*/,
void *buffer,
void * /*data*/)
static void extract_pos_loose_geom_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData & /*mr*/,
void *buffer,
void * /*data*/)
{
const DRWSubdivLooseGeom &loose_geom = subdiv_cache.loose_geom;
if (loose_geom.loop_len == 0) {
@ -361,220 +283,24 @@ static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache &subdiv_cache
}
}
constexpr MeshExtract create_extractor_pos_nor()
constexpr MeshExtract create_extractor_pos()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_pos_nor_init;
extractor.iter_face_bm = extract_pos_nor_iter_face_bm;
extractor.iter_face_mesh = extract_pos_nor_iter_face_mesh;
extractor.iter_loose_edge_bm = extract_pos_nor_iter_loose_edge_bm;
extractor.iter_loose_edge_mesh = extract_pos_nor_iter_loose_edge_mesh;
extractor.iter_loose_vert_bm = extract_pos_nor_iter_loose_vert_bm;
extractor.iter_loose_vert_mesh = extract_pos_nor_iter_loose_vert_mesh;
extractor.finish = extract_pos_nor_finish;
extractor.init_subdiv = extract_pos_nor_init_subdiv;
extractor.iter_loose_geom_subdiv = extract_pos_nor_loose_geom_subdiv;
extractor.init = extract_pos_init;
extractor.iter_face_bm = extract_pos_iter_face_bm;
extractor.iter_loose_edge_bm = extract_pos_iter_loose_edge_bm;
extractor.iter_loose_vert_bm = extract_pos_iter_loose_vert_bm;
extractor.init_subdiv = extract_pos_init_subdiv;
extractor.iter_loose_geom_subdiv = extract_pos_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_PosNor_Data);
extractor.data_size = sizeof(float3 *);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.pos_nor);
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.pos);
return extractor;
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Extract Position and High Quality Vertex Normal
* \{ */
struct PosNorHQLoop {
float pos[3];
short nor[4];
};
struct MeshExtract_PosNorHQ_Data {
PosNorHQLoop *vbo_data;
GPUNormal *normals;
};
static void extract_pos_nor_hq_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void *tls_data)
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING Adjust #PosNorHQLoop struct accordingly. */
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "vnor");
}
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr.loop_len + mr.loop_loose_len);
/* Pack normals per vert, reduce amount of computation. */
MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(tls_data);
data->vbo_data = static_cast<PosNorHQLoop *>(GPU_vertbuf_get_data(vbo));
data->normals = (GPUNormal *)MEM_mallocN(sizeof(GPUNormal) * mr.vert_len, __func__);
/* Quicker than doing it for each loop. */
if (mr.extract_type == MR_EXTRACT_BMESH) {
BMIter iter;
BMVert *eve;
int v;
BM_ITER_MESH_INDEX (eve, &iter, mr.bm, BM_VERTS_OF_MESH, v) {
normal_float_to_short_v3(data->normals[v].high, bm_vert_no_get(mr, eve));
}
}
else {
for (int v = 0; v < mr.vert_len; v++) {
normal_float_to_short_v3(data->normals[v].high, mr.vert_normals[v]);
}
}
}
static void extract_pos_nor_hq_iter_face_bm(const MeshRenderData &mr,
const BMFace *f,
const int /*f_index*/,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data);
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
const int l_index = BM_elem_index_get(l_iter);
PosNorHQLoop *vert = &data->vbo_data[l_index];
copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v));
copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(l_iter->v)].high);
vert->nor[3] = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0;
} while ((l_iter = l_iter->next) != l_first);
}
static void extract_pos_nor_hq_iter_face_mesh(const MeshRenderData &mr,
const int face_index,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data);
const bool poly_hidden = !mr.hide_poly.is_empty() && mr.hide_poly[face_index];
for (const int corner : mr.faces[face_index]) {
const int vert_i = mr.corner_verts[corner];
const bool vert_hidden = !mr.hide_vert.is_empty() && mr.hide_vert[vert_i];
PosNorHQLoop *vert = &data->vbo_data[corner];
copy_v3_v3(vert->pos, mr.vert_positions[vert_i]);
copy_v3_v3_short(vert->nor, data->normals[vert_i].high);
/* Flag for paint mode overlay. */
if (poly_hidden || vert_hidden ||
((mr.v_origindex) && (mr.v_origindex[vert_i] == ORIGINDEX_NONE)))
{
vert->nor[3] = -1;
}
else if (!mr.select_vert.is_empty() && mr.select_vert[vert_i]) {
vert->nor[3] = 1;
}
else {
vert->nor[3] = 0;
}
}
}
static void extract_pos_nor_hq_iter_loose_edge_bm(const MeshRenderData &mr,
const BMEdge *eed,
const int loose_edge_i,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data);
int l_index = mr.loop_len + loose_edge_i * 2;
PosNorHQLoop *vert = &data->vbo_data[l_index];
copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
copy_v3_v3_short(vert[0].nor, data->normals[BM_elem_index_get(eed->v1)].high);
vert[0].nor[3] = 0;
copy_v3_v3_short(vert[1].nor, data->normals[BM_elem_index_get(eed->v2)].high);
vert[1].nor[3] = 0;
}
static void extract_pos_nor_hq_iter_loose_edge_mesh(const MeshRenderData &mr,
const int2 edge,
const int loose_edge_i,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data);
const int index = mr.loop_len + loose_edge_i * 2;
PosNorHQLoop *vert = &data->vbo_data[index];
copy_v3_v3(vert[0].pos, mr.vert_positions[edge[0]]);
copy_v3_v3(vert[1].pos, mr.vert_positions[edge[1]]);
copy_v3_v3_short(vert[0].nor, data->normals[edge[0]].high);
vert[0].nor[3] = 0;
copy_v3_v3_short(vert[1].nor, data->normals[edge[1]].high);
vert[1].nor[3] = 0;
}
static void extract_pos_nor_hq_iter_loose_vert_bm(const MeshRenderData &mr,
const BMVert *eve,
const int loose_vert_i,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data);
const int offset = mr.loop_len + (mr.edge_loose_len * 2);
const int l_index = offset + loose_vert_i;
PosNorHQLoop *vert = &data->vbo_data[l_index];
copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(eve)].high);
vert->nor[3] = 0;
}
static void extract_pos_nor_hq_iter_loose_vert_mesh(const MeshRenderData &mr,
const int loose_vert_i,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data);
const int offset = mr.loop_len + (mr.edge_loose_len * 2);
const int index = offset + loose_vert_i;
const int v_index = mr.loose_verts[loose_vert_i];
PosNorHQLoop *vert = &data->vbo_data[index];
copy_v3_v3(vert->pos, mr.vert_positions[v_index]);
copy_v3_v3_short(vert->nor, data->normals[v_index].high);
vert->nor[3] = 0;
}
static void extract_pos_nor_hq_finish(const MeshRenderData & /*mr*/,
MeshBatchCache & /*cache*/,
void * /*buf*/,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data);
MEM_freeN(data->normals);
}
constexpr MeshExtract create_extractor_pos_nor_hq()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_pos_nor_hq_init;
extractor.init_subdiv = extract_pos_nor_init_subdiv;
extractor.iter_face_bm = extract_pos_nor_hq_iter_face_bm;
extractor.iter_face_mesh = extract_pos_nor_hq_iter_face_mesh;
extractor.iter_loose_edge_bm = extract_pos_nor_hq_iter_loose_edge_bm;
extractor.iter_loose_edge_mesh = extract_pos_nor_hq_iter_loose_edge_mesh;
extractor.iter_loose_vert_bm = extract_pos_nor_hq_iter_loose_vert_bm;
extractor.iter_loose_vert_mesh = extract_pos_nor_hq_iter_loose_vert_mesh;
extractor.finish = extract_pos_nor_hq_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_PosNorHQ_Data);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.pos_nor);
return extractor;
}
/** \} */
const MeshExtract extract_pos_nor = create_extractor_pos_nor();
const MeshExtract extract_pos_nor_hq = create_extractor_pos_nor_hq();
const MeshExtract extract_pos = create_extractor_pos();
} // namespace blender::draw

View File

@ -0,0 +1,72 @@
/* SPDX-FileCopyrightText: 2021 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup draw
*/
#include "extract_mesh.hh"
#include "draw_subdivision.hh"
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Vertex Normal
* \{ */
static void extract_vnor_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void *tls_data)
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "vnor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr.loop_len);
if (mr.extract_type == MR_EXTRACT_MESH) {
MutableSpan vbo_data(static_cast<GPUPackedNormal *>(GPU_vertbuf_get_data(vbo)), mr.loop_len);
extract_vert_normals(mr, vbo_data);
}
else {
*static_cast<GPUPackedNormal **>(tls_data) = static_cast<GPUPackedNormal *>(
GPU_vertbuf_get_data(vbo));
}
}
static void extract_vnor_iter_face_bm(const MeshRenderData &mr,
const BMFace *face,
const int /*f_index*/,
void *data_v)
{
GPUPackedNormal *data = *static_cast<GPUPackedNormal **>(data_v);
const BMLoop *loop = BM_FACE_FIRST_LOOP(face);
for ([[maybe_unused]] const int i : IndexRange(face->len)) {
const int index = BM_elem_index_get(loop);
data[index] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, loop->v));
loop = loop->next;
}
}
constexpr MeshExtract create_extractor_vnor()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_vnor_init;
extractor.iter_face_bm = extract_vnor_iter_face_bm;
extractor.data_type = MR_DATA_LOOP_NOR;
extractor.data_size = sizeof(GPUPackedNormal *);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.vnor);
return extractor;
}
/** \} */
const MeshExtract extract_vnor = create_extractor_vnor();
} // namespace blender::draw