Fix T94729: GPU subdivision does not support meshes without polygons

There are two issues revealed in the bug report:
- the GPU subdivision does not support meshes with only loose geometry
- the loose geometry is not subdivided

For the first case, checks are added to ensure we still fill the
buffers with loose geometry even if no polygons are present.

For the second case, this adds
`BKE_subdiv_mesh_interpolate_position_on_edge` which encapsulates the
loose vertex interpolation mechanism previously found in
`subdiv_mesh_vertex_of_loose_edge`.

The subdivided loose geometry is stored in a new specific data structure
`DRWSubdivLooseGeom` so as to not pollute `MeshExtractLooseGeom`. These
structures store the corresponding coarse element data, which will be
used for filling GPU buffers appropriately.

Differential Revision: https://developer.blender.org/D14171
This commit is contained in:
Kévin Dietrich 2022-03-02 15:10:26 +01:00
parent 4a95c3466f
commit 6883c47bb5
Notes: blender-bot 2023-02-13 16:34:27 +01:00
Referenced by issue #94729, GPU subdivision does not support wireframe subdivision (no faces)
12 changed files with 518 additions and 213 deletions

View File

@ -30,6 +30,7 @@ extern "C" {
#endif
struct Mesh;
struct MEdge;
struct Subdiv;
typedef struct SubdivToMeshSettings {
@ -49,6 +50,14 @@ struct Mesh *BKE_subdiv_to_mesh(struct Subdiv *subdiv,
const SubdivToMeshSettings *settings,
const struct Mesh *coarse_mesh);
/* Interpolate a position along the `coarse_edge` at the relative `u` coordinate. If `is_simple` is
* false, this will perform a B-Spline interpolation using the edge neighbors, otherwise a linear
* interpolation will be done base on the edge vertices. */
void BKE_subdiv_mesh_interpolate_position_on_edge(const struct Mesh *coarse_mesh,
const struct MEdge *coarse_edge,
bool is_simple,
float u,
float pos_r[3]);
#ifdef __cplusplus
}
#endif

View File

@ -946,11 +946,10 @@ static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context
/* Get neighbor edges of the given one.
* - neighbors[0] is an edge adjacent to edge->v1.
* - neighbors[1] is an edge adjacent to edge->v2. */
static void find_edge_neighbors(const SubdivMeshContext *ctx,
static void find_edge_neighbors(const Mesh *coarse_mesh,
const MEdge *edge,
const MEdge *neighbors[2])
{
const Mesh *coarse_mesh = ctx->coarse_mesh;
const MEdge *coarse_medge = coarse_mesh->medge;
neighbors[0] = NULL;
neighbors[1] = NULL;
@ -980,12 +979,11 @@ static void find_edge_neighbors(const SubdivMeshContext *ctx,
}
}
static void points_for_loose_edges_interpolation_get(SubdivMeshContext *ctx,
static void points_for_loose_edges_interpolation_get(const Mesh *coarse_mesh,
const MEdge *coarse_edge,
const MEdge *neighbors[2],
float points_r[4][3])
{
const Mesh *coarse_mesh = ctx->coarse_mesh;
const MVert *coarse_mvert = coarse_mesh->mvert;
/* Middle points corresponds to the edge. */
copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co);
@ -1018,6 +1016,30 @@ static void points_for_loose_edges_interpolation_get(SubdivMeshContext *ctx,
}
}
void BKE_subdiv_mesh_interpolate_position_on_edge(const Mesh *coarse_mesh,
const MEdge *coarse_edge,
const bool is_simple,
const float u,
float pos_r[3])
{
if (is_simple) {
const MVert *coarse_mvert = coarse_mesh->mvert;
const MVert *vert_1 = &coarse_mvert[coarse_edge->v1];
const MVert *vert_2 = &coarse_mvert[coarse_edge->v2];
interp_v3_v3v3(pos_r, vert_1->co, vert_2->co, u);
}
else {
/* Find neighbors of the coarse edge. */
const MEdge *neighbors[2];
find_edge_neighbors(coarse_mesh, coarse_edge, neighbors);
float points[4][3];
points_for_loose_edges_interpolation_get(coarse_mesh, coarse_edge, neighbors, points);
float weights[4];
key_curve_position_weights(u, weights, KEY_BSPLINE);
interp_v3_v3v3v3v3(pos_r, points[0], points[1], points[2], points[3], weights);
}
}
static void subdiv_mesh_vertex_of_loose_edge_interpolate(SubdivMeshContext *ctx,
const MEdge *coarse_edge,
const float u,
@ -1054,9 +1076,6 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
Mesh *subdiv_mesh = ctx->subdiv_mesh;
MVert *subdiv_mvert = subdiv_mesh->mvert;
const bool is_simple = ctx->subdiv->settings.is_simple;
/* Find neighbors of the current loose edge. */
const MEdge *neighbors[2];
find_edge_neighbors(ctx, coarse_edge, neighbors);
/* Interpolate custom data when not an end point.
* This data has already been copied from the original vertex by #subdiv_mesh_vertex_loose. */
if (!ELEM(u, 0.0, 1.0)) {
@ -1064,19 +1083,8 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
}
/* Interpolate coordinate. */
MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
if (is_simple) {
const MVert *coarse_mvert = coarse_mesh->mvert;
const MVert *vert_1 = &coarse_mvert[coarse_edge->v1];
const MVert *vert_2 = &coarse_mvert[coarse_edge->v2];
interp_v3_v3v3(subdiv_vertex->co, vert_1->co, vert_2->co, u);
}
else {
float points[4][3];
points_for_loose_edges_interpolation_get(ctx, coarse_edge, neighbors, points);
float weights[4];
key_curve_position_weights(u, weights, KEY_BSPLINE);
interp_v3_v3v3v3v3(subdiv_vertex->co, points[0], points[1], points[2], points[3], weights);
}
BKE_subdiv_mesh_interpolate_position_on_edge(
coarse_mesh, coarse_edge, is_simple, u, subdiv_vertex->co);
/* Reset flags and such. */
subdiv_vertex->flag = 0;
/* TODO(sergey): This matches old behavior, but we can as well interpolate

View File

@ -822,7 +822,27 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
extractors.append(&extract_fdots_pos);
}
EXTRACT_ADD_REQUESTED(ibo, lines);
if (DRW_ibo_requested(mbuflist->ibo.lines_loose)) {
/* `ibo.lines_loose` require the `ibo.lines` buffer. */
if (mbuflist->ibo.lines == nullptr) {
DRW_ibo_request(nullptr, &mbuflist->ibo.lines);
}
const MeshExtract *extractor = DRW_ibo_requested(mbuflist->ibo.lines) ?
&extract_lines_with_lines_loose :
&extract_lines_loose_only;
extractors.append(extractor);
}
else if (DRW_ibo_requested(mbuflist->ibo.lines)) {
const MeshExtract *extractor;
if (mbuflist->ibo.lines_loose != nullptr) {
/* Update `ibo.lines_loose` as it depends on `ibo.lines`. */
extractor = &extract_lines_with_lines_loose;
}
else {
extractor = &extract_lines;
}
extractors.append(extractor);
}
EXTRACT_ADD_REQUESTED(ibo, edituv_points);
EXTRACT_ADD_REQUESTED(ibo, edituv_tris);
EXTRACT_ADD_REQUESTED(ibo, edituv_lines);
@ -851,6 +871,7 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
mesh_render_data_update_looptris(mr, MR_ITER_LOOPTRI, MR_DATA_LOOPTRI);
mesh_render_data_update_loose_geom(mr, mbc, MR_ITER_LEDGE | MR_ITER_LVERT, MR_DATA_LOOSE_GEOM);
DRW_subdivide_loose_geom(subdiv_cache, mbc);
void *data_stack = MEM_mallocN(extractors.data_size_total(), __func__);
uint32_t data_offset = 0;
@ -884,7 +905,7 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
}
if (extractor->iter_loose_geom_subdiv) {
extractor->iter_loose_geom_subdiv(subdiv_cache, mr, &mbc->loose_geom, buffer, data);
extractor->iter_loose_geom_subdiv(subdiv_cache, mr, buffer, data);
}
if (extractor->finish_subdiv) {

View File

@ -533,6 +533,11 @@ static void draw_patch_map_free(DRWPatchMap *gpu_patch_map)
/** \name DRWSubdivCache
* \{ */
static bool draw_subdiv_cache_need_polygon_data(const DRWSubdivCache *cache)
{
return cache->subdiv && cache->subdiv->evaluator && cache->num_subdiv_loops != 0;
}
static void draw_subdiv_cache_free_material_data(DRWSubdivCache *cache)
{
GPU_VERTBUF_DISCARD_SAFE(cache->polygon_mat_offset);
@ -565,6 +570,7 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache)
cache->num_subdiv_triangles = 0;
cache->num_coarse_poly = 0;
cache->num_subdiv_quads = 0;
cache->may_have_loose_geom = false;
draw_subdiv_free_edit_mode_cache(cache);
draw_subdiv_cache_free_material_data(cache);
draw_patch_map_free(&cache->gpu_patch_map);
@ -572,6 +578,11 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache)
GPU_uniformbuf_free(cache->ubo);
cache->ubo = nullptr;
}
MEM_SAFE_FREE(cache->loose_geom.edges);
MEM_SAFE_FREE(cache->loose_geom.verts);
cache->loose_geom.edge_len = 0;
cache->loose_geom.vert_len = 0;
cache->loose_geom.loop_len = 0;
}
/* Flags used in #DRWSubdivCache.extra_coarse_face_data. The flags are packed in the upper bits of
@ -744,19 +755,25 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
const int num_polygons,
const int *subdiv_polygon_offset)
{
if (num_loops == 0) {
/* num_loops does not take into account meshes with only loose geometry, which might be meshes
* used as custom bone shapes, so let's check the num_vertices also. */
if (num_vertices == 0 && num_loops == 0) {
return false;
}
DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
DRWSubdivCache *cache = ctx->cache;
/* Set topology information. */
cache->num_subdiv_edges = (uint)num_edges;
cache->num_subdiv_loops = (uint)num_loops;
cache->num_subdiv_verts = (uint)num_vertices;
cache->num_subdiv_quads = (uint)num_polygons;
cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset));
/* Set topology information only if we have loops. */
if (num_loops != 0) {
cache->num_subdiv_edges = (uint)num_edges;
cache->num_subdiv_loops = (uint)num_loops;
cache->num_subdiv_verts = (uint)num_vertices;
cache->num_subdiv_quads = (uint)num_polygons;
cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset));
}
cache->may_have_loose_geom = num_vertices != 0 || num_edges != 0;
/* Initialize cache buffers, prefer dynamic usage so we can reuse memory on the host even after
* it was sent to the device, since we may use the data while building other buffers on the CPU
@ -795,16 +812,20 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
ctx->e_origindex = static_cast<int *>(
CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX));
ctx->vert_origindex_map = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map"));
for (int i = 0; i < num_vertices; i++) {
ctx->vert_origindex_map[i] = -1;
if (cache->num_subdiv_verts) {
ctx->vert_origindex_map = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map"));
for (int i = 0; i < num_vertices; i++) {
ctx->vert_origindex_map[i] = -1;
}
}
ctx->edge_origindex_map = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map"));
for (int i = 0; i < num_edges; i++) {
ctx->edge_origindex_map[i] = -1;
if (cache->num_subdiv_edges) {
ctx->edge_origindex_map = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map"));
for (int i = 0; i < num_edges; i++) {
ctx->edge_origindex_map[i] = -1;
}
}
return true;
@ -848,6 +869,10 @@ static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context,
{
DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
if (!ctx->edge_origindex_map) {
return;
}
int coarse_index = coarse_edge_index;
if (coarse_index != -1) {
@ -998,7 +1023,8 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
cache_building_context.cache = cache;
do_subdiv_traversal(&cache_building_context, subdiv);
if (cache->num_subdiv_loops == 0) {
if (cache->num_subdiv_loops == 0 && cache->num_subdiv_verts == 0 &&
!cache->may_have_loose_geom) {
/* Either the traversal failed, or we have an empty mesh, either way we cannot go any further.
* The subdiv_polygon_offset cannot then be reliably stored in the cache, so free it directly.
*/
@ -1006,44 +1032,47 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
return false;
}
/* Build buffers for the PatchMap. */
draw_patch_map_build(&cache->gpu_patch_map, subdiv);
/* Only build polygon related data if we have polygons. */
if (cache->num_subdiv_loops != 0) {
/* Build buffers for the PatchMap. */
draw_patch_map_build(&cache->gpu_patch_map, subdiv);
cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
// Build patch coordinates for all the face dots
cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(),
mesh_eval->totpoly);
CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(
cache->fdots_patch_coords);
for (int i = 0; i < mesh_eval->totpoly; i++) {
const int ptex_face_index = cache->face_ptex_offset[i];
if (mesh_eval->mpoly[i].totloop == 4) {
/* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */
blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f);
}
else {
/* For N-gons, since they are split into quads from the center, and since the center is
* chosen to be the top right corner of each quad, the center coordinate of the coarse face
* is any one of those top right corners with `u = v = 1.0`. */
blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f);
/* Build patch coordinates for all the face dots. */
cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(),
mesh_eval->totpoly);
CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)
GPU_vertbuf_get_data(cache->fdots_patch_coords);
for (int i = 0; i < mesh_eval->totpoly; i++) {
const int ptex_face_index = cache->face_ptex_offset[i];
if (mesh_eval->mpoly[i].totloop == 4) {
/* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */
blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f);
}
else {
/* For N-gons, since they are split into quads from the center, and since the center is
* chosen to be the top right corner of each quad, the center coordinate of the coarse face
* is any one of those top right corners with `u = v = 1.0`. */
blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f);
}
}
cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer(
cache->subdiv_polygon_offset, mesh_eval->totpoly);
cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset,
mesh_eval->totpoly + 1);
build_vertex_face_adjacency_maps(cache);
}
cache->resolution = to_mesh_settings.resolution;
cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer(
cache->subdiv_polygon_offset, mesh_eval->totpoly);
cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset,
mesh_eval->totpoly + 1);
cache->num_coarse_poly = mesh_eval->totpoly;
build_vertex_face_adjacency_maps(cache);
/* Cleanup. */
MEM_freeN(cache_building_context.vert_origindex_map);
MEM_freeN(cache_building_context.edge_origindex_map);
MEM_SAFE_FREE(cache_building_context.vert_origindex_map);
MEM_SAFE_FREE(cache_building_context.edge_origindex_map);
return true;
}
@ -1199,6 +1228,11 @@ static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor)
{
if (!draw_subdiv_cache_need_polygon_data(cache)) {
/* Happens on meshes with only loose geometry. */
return;
}
Subdiv *subdiv = cache->subdiv;
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
@ -1256,6 +1290,11 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
const int face_varying_channel,
const int dst_offset)
{
if (!draw_subdiv_cache_need_polygon_data(cache)) {
/* Happens on meshes with only loose geometry. */
return;
}
Subdiv *subdiv = cache->subdiv;
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
@ -1477,6 +1516,11 @@ void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
GPUIndexBuf *subdiv_tris,
const int material_count)
{
if (!draw_subdiv_cache_need_polygon_data(cache)) {
/* Happens on meshes with only loose geometry. */
return;
}
const bool do_single_material = material_count <= 1;
const char *defines = "#define SUBDIV_POLYGON_OFFSET\n";
@ -1513,6 +1557,11 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
GPUVertBuf *fdots_nor,
GPUIndexBuf *fdots_indices)
{
if (!draw_subdiv_cache_need_polygon_data(cache)) {
/* Happens on meshes with only loose geometry. */
return;
}
Subdiv *subdiv = cache->subdiv;
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
@ -1631,6 +1680,11 @@ void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
GPUVertBuf *pos_nor,
GPUVertBuf *lnor)
{
if (!draw_subdiv_cache_need_polygon_data(cache)) {
/* Happens on meshes with only loose geometry. */
return;
}
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LNOR, "#define SUBDIV_POLYGON_OFFSET\n");
GPU_shader_bind(shader);
@ -1846,7 +1900,15 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
if (!BKE_subdiv_eval_begin_from_mesh(
subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) {
return false;
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
* topology.
* In either way, we can't safely continue. However, we still have to handle potential loose
* geometry, which is done separately. */
if (mesh_eval->totpoly) {
return false;
}
}
DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache);
@ -1883,6 +1945,104 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
return true;
}
void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cache)
{
const int coarse_loose_vert_len = cache->loose_geom.vert_len;
const int coarse_loose_edge_len = cache->loose_geom.edge_len;
if (coarse_loose_vert_len == 0 && coarse_loose_edge_len == 0) {
/* Nothing to do. */
return;
}
if (subdiv_cache->loose_geom.edges || subdiv_cache->loose_geom.verts) {
/* Already processed. */
return;
}
const Mesh *coarse_mesh = subdiv_cache->mesh;
const bool is_simple = subdiv_cache->subdiv->settings.is_simple;
const int resolution = subdiv_cache->resolution;
const int resolution_1 = resolution - 1;
const float inv_resolution_1 = 1.0f / (float)resolution_1;
const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
const int num_subdivided_edge = coarse_loose_edge_len *
(num_subdiv_vertices_per_coarse_edge + 1);
/* Each edge will store data for its 2 verts, that way we can keep the overall logic simple, here
* and in the buffer extractors. Although it duplicates memory (and work), the buffers also store
* duplicate values. */
const int num_subdivided_verts = num_subdivided_edge * 2;
DRWSubdivLooseEdge *loose_subd_edges = static_cast<DRWSubdivLooseEdge *>(
MEM_callocN(sizeof(DRWSubdivLooseEdge) * num_subdivided_edge, "DRWSubdivLooseEdge"));
DRWSubdivLooseVertex *loose_subd_verts = static_cast<DRWSubdivLooseVertex *>(
MEM_callocN(sizeof(DRWSubdivLooseVertex) * (num_subdivided_verts + coarse_loose_vert_len),
"DRWSubdivLooseEdge"));
int subd_edge_offset = 0;
int subd_vert_offset = 0;
/* Subdivide each loose coarse edge. */
for (int i = 0; i < coarse_loose_edge_len; i++) {
const int coarse_edge_index = cache->loose_geom.edges[i];
const MEdge *coarse_edge = &coarse_mesh->medge[cache->loose_geom.edges[i]];
/* Perform interpolation of each vertex. */
for (int i = 0; i < resolution - 1; i++, subd_edge_offset++) {
DRWSubdivLooseEdge &subd_edge = loose_subd_edges[subd_edge_offset];
subd_edge.coarse_edge_index = coarse_edge_index;
/* First vert. */
DRWSubdivLooseVertex &subd_v1 = loose_subd_verts[subd_vert_offset];
subd_v1.coarse_vertex_index = (i == 0) ? coarse_edge->v1 : -1u;
const float u1 = i * inv_resolution_1;
BKE_subdiv_mesh_interpolate_position_on_edge(
coarse_mesh, coarse_edge, is_simple, u1, subd_v1.co);
subd_edge.loose_subdiv_v1_index = subd_vert_offset++;
/* Second vert. */
DRWSubdivLooseVertex &subd_v2 = loose_subd_verts[subd_vert_offset];
subd_v2.coarse_vertex_index = ((i + 1) == resolution - 1) ? coarse_edge->v2 : -1u;
const float u2 = (i + 1) * inv_resolution_1;
BKE_subdiv_mesh_interpolate_position_on_edge(
coarse_mesh, coarse_edge, is_simple, u2, subd_v2.co);
subd_edge.loose_subdiv_v2_index = subd_vert_offset++;
}
}
/* Copy the remaining loose_verts. */
for (int i = 0; i < coarse_loose_vert_len; i++) {
const int coarse_vertex_index = cache->loose_geom.verts[i];
const MVert &coarse_vertex = coarse_mesh->mvert[coarse_vertex_index];
DRWSubdivLooseVertex &subd_v = loose_subd_verts[subd_vert_offset++];
subd_v.coarse_vertex_index = cache->loose_geom.verts[i];
copy_v3_v3(subd_v.co, coarse_vertex.co);
}
subdiv_cache->loose_geom.edges = loose_subd_edges;
subdiv_cache->loose_geom.verts = loose_subd_verts;
subdiv_cache->loose_geom.edge_len = num_subdivided_edge;
subdiv_cache->loose_geom.vert_len = coarse_loose_vert_len;
subdiv_cache->loose_geom.loop_len = num_subdivided_edge * 2 + coarse_loose_vert_len;
}
blender::Span<DRWSubdivLooseEdge> draw_subdiv_cache_get_loose_edges(const DRWSubdivCache *cache)
{
return {cache->loose_geom.edges, static_cast<int64_t>(cache->loose_geom.edge_len)};
}
blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWSubdivCache *cache)
{
return {cache->loose_geom.verts + cache->loose_geom.edge_len * 2,
static_cast<int64_t>(cache->loose_geom.vert_len)};
}
static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr;
void DRW_create_subdivision(const Scene *scene,

View File

@ -55,6 +55,56 @@ typedef struct DRWPatchMap {
/** \} */
/* -------------------------------------------------------------------- */
/** \name DRWSubdivLooseEdge
*
* This stores information about a subdivided loose edge.
* \{ */
typedef struct DRWSubdivLooseEdge {
/* The corresponding coarse edge, this is always valid. */
int coarse_edge_index;
/* Pointers into #DRWSubdivLooseGeom.verts. */
int loose_subdiv_v1_index;
int loose_subdiv_v2_index;
} DRWSubdivLooseEdge;
/** \} */
/* -------------------------------------------------------------------- */
/** \name DRWSubdivLooseVertex
*
* This stores information about a subdivided loose vertex, that may or may not come from a loose
* edge.
* \{ */
typedef struct DRWSubdivLooseVertex {
/* The corresponding coarse vertex, or -1 if this vertex is the result
* of subdivision. */
unsigned int coarse_vertex_index;
/* Position and normal of the vertex. */
float co[3];
float nor[3];
} DRWSubdivLooseVertex;
/** \} */
/* -------------------------------------------------------------------- */
/** \name DRWSubdivLooseGeom
*
* This stores the subdivided vertices and edges of loose geometry from #MeshExtractLooseGeom.
* \{ */
typedef struct DRWSubdivLooseGeom {
DRWSubdivLooseEdge *edges;
DRWSubdivLooseVertex *verts;
int edge_len;
int vert_len;
int loop_len;
} DRWSubdivLooseGeom;
/** \} */
/* -------------------------------------------------------------------- */
/** \name DRWSubdivCache
*
@ -84,6 +134,11 @@ typedef struct DRWSubdivCache {
uint num_subdiv_verts;
uint num_subdiv_quads;
/* We only do the subdivision traversal for full faces, however we may have geometries that only
* have loose edges (e.g. a custom bone shape). This flag is used to detect those cases, as the
* counters above will all be set to zero if we do not have subdivision loops. */
bool may_have_loose_geom;
/* Number of polygons in the coarse mesh, notably used to compute a coarse polygon index given a
* subdivision loop index. */
int num_coarse_poly;
@ -128,6 +183,8 @@ typedef struct DRWSubdivCache {
DRWPatchMap gpu_patch_map;
DRWSubdivLooseGeom loose_geom;
/* UBO to store settings for the various compute shaders. */
struct GPUUniformBuf *ubo;
} DRWSubdivCache;
@ -243,3 +300,15 @@ void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache,
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
# include "BLI_span.hh"
/* Helper to access the loose edges. */
blender::Span<DRWSubdivLooseEdge> draw_subdiv_cache_get_loose_edges(const DRWSubdivCache *cache);
/* Helper to access only the loose vertices, i.e. not the ones attached to loose edges. To access
* loose vertices of loose edges #draw_subdiv_cache_get_loose_edges should be used. */
blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWSubdivCache *cache);
#endif

View File

@ -206,7 +206,6 @@ typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
void *data);
typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
const MeshExtractLooseGeom *loose_geom,
void *buffer,
void *data);
typedef void(ExtractInitFn)(const MeshRenderData *mr,

View File

@ -158,30 +158,35 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
}
static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
void *buffer,
void *UNUSED(data))
{
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
GPU_indexbuf_init_build_on_device(ibo,
subdiv_cache->num_subdiv_loops * 2 + mr->edge_loose_len * 2);
subdiv_cache->num_subdiv_loops * 2 + loose_geom.edge_len * 2);
if (subdiv_cache->num_subdiv_loops == 0) {
return;
}
draw_subdiv_build_lines_buffer(subdiv_cache, ibo);
}
static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
const MeshExtractLooseGeom *loose_geom,
void *buffer,
void *UNUSED(data))
{
if (loose_geom->edge_len == 0) {
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
if (loose_geom.edge_len == 0) {
return;
}
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom->edge_len));
draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom.edge_len));
}
constexpr MeshExtract create_extractor_lines()
@ -231,6 +236,20 @@ static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr,
extract_lines_loose_subbuffer(mr, cache);
}
static void extract_lines_with_lines_loose_finish_subdiv(const struct DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *cache,
void *UNUSED(buf),
void *UNUSED(_data))
{
/* Multiply by 2 because these are edges indices. */
const int start = subdiv_cache->num_subdiv_loops * 2;
const int len = subdiv_cache->loose_geom.edge_len * 2;
GPU_indexbuf_create_subrange_in_place(
cache->final.buff.ibo.lines_loose, cache->final.buff.ibo.lines, start, len);
cache->no_loose_wire = (len == 0);
}
constexpr MeshExtract create_extractor_lines_with_lines_loose()
{
MeshExtract extractor = {nullptr};
@ -241,6 +260,9 @@ constexpr MeshExtract create_extractor_lines_with_lines_loose()
extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh;
extractor.task_reduce = extract_lines_task_reduce;
extractor.finish = extract_lines_with_lines_loose_finish;
extractor.init_subdiv = extract_lines_init_subdiv;
extractor.iter_loose_geom_subdiv = extract_lines_loose_geom_subdiv;
extractor.finish_subdiv = extract_lines_with_lines_loose_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = true;
@ -264,10 +286,22 @@ static void extract_lines_loose_only_init(const MeshRenderData *mr,
extract_lines_loose_subbuffer(mr, cache);
}
static void extract_lines_loose_only_init_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
BLI_assert(buffer == cache->final.buff.ibo.lines_loose);
UNUSED_VARS_NDEBUG(buffer);
extract_lines_loose_subbuffer(mr, cache);
}
constexpr MeshExtract create_extractor_lines_loose_only()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_lines_loose_only_init;
extractor.init_subdiv = extract_lines_loose_only_init_subdiv;
extractor.data_type = MR_DATA_LOOSE_GEOM;
extractor.data_size = 0;
extractor.use_threading = false;

View File

@ -163,8 +163,10 @@ static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
void *data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
GPU_indexbuf_init(
elb, GPU_PRIM_POINTS, mr->vert_len, subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
GPU_indexbuf_init(elb,
GPU_PRIM_POINTS,
mr->vert_len,
subdiv_cache->num_subdiv_loops + subdiv_cache->loose_geom.loop_len);
}
static void extract_points_iter_subdiv_common(GPUIndexBufBuilder *elb,
@ -212,46 +214,70 @@ static void extract_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
const MeshExtractLooseGeom *loose_geom,
void *UNUSED(buffer),
void *data)
{
const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
const int loop_loose_len = loose_geom.loop_len;
if (loop_loose_len == 0) {
return;
}
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
uint offset = subdiv_cache->num_subdiv_loops;
if (mr->extract_type == MR_EXTRACT_MESH) {
const Mesh *coarse_mesh = subdiv_cache->mesh;
const MEdge *coarse_edges = coarse_mesh->medge;
if (mr->extract_type != MR_EXTRACT_BMESH) {
blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(
subdiv_cache);
for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
const DRWSubdivLooseVertex &v1 = loose_geom.verts[loose_edge.loose_subdiv_v1_index];
const DRWSubdivLooseVertex &v2 = loose_geom.verts[loose_edge.loose_subdiv_v2_index];
if (v1.coarse_vertex_index != -1u) {
vert_set_mesh(elb, mr, v1.coarse_vertex_index, offset);
}
if (v2.coarse_vertex_index != -1u) {
vert_set_mesh(elb, mr, v2.coarse_vertex_index, offset + 1);
}
for (int i = 0; i < loose_geom->edge_len; i++) {
const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
vert_set_mesh(elb, mr, loose_edge->v1, offset);
vert_set_mesh(elb, mr, loose_edge->v2, offset + 1);
offset += 2;
}
blender::Span<DRWSubdivLooseVertex> loose_verts = draw_subdiv_cache_get_loose_verts(
subdiv_cache);
for (int i = 0; i < loose_geom->vert_len; i++) {
vert_set_mesh(elb, mr, loose_geom->verts[i], offset);
for (const DRWSubdivLooseVertex &loose_vert : loose_verts) {
vert_set_mesh(elb, mr, loose_vert.coarse_vertex_index, offset);
offset += 1;
}
}
else {
BMesh *bm = mr->bm;
for (int i = 0; i < loose_geom->edge_len; i++) {
const BMEdge *loose_edge = BM_edge_at_index(bm, loose_geom->edges[i]);
vert_set_bm(elb, loose_edge->v1, offset);
vert_set_bm(elb, loose_edge->v2, offset + 1);
blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(
subdiv_cache);
for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
const DRWSubdivLooseVertex &v1 = loose_geom.verts[loose_edge.loose_subdiv_v1_index];
const DRWSubdivLooseVertex &v2 = loose_geom.verts[loose_edge.loose_subdiv_v2_index];
if (v1.coarse_vertex_index != -1u) {
BMVert *eve = mr->v_origindex ? bm_original_vert_get(mr, v1.coarse_vertex_index) :
BM_vert_at_index(mr->bm, v1.coarse_vertex_index);
vert_set_bm(elb, eve, offset);
}
if (v2.coarse_vertex_index != -1u) {
BMVert *eve = mr->v_origindex ? bm_original_vert_get(mr, v2.coarse_vertex_index) :
BM_vert_at_index(mr->bm, v2.coarse_vertex_index);
vert_set_bm(elb, eve, offset + 1);
}
offset += 2;
}
blender::Span<DRWSubdivLooseVertex> loose_verts = draw_subdiv_cache_get_loose_verts(
subdiv_cache);
for (int i = 0; i < loose_geom->vert_len; i++) {
const BMVert *loose_vert = BM_vert_at_index(bm, loose_geom->verts[i]);
vert_set_bm(elb, loose_vert, offset);
for (const DRWSubdivLooseVertex &loose_vert : loose_verts) {
BMVert *eve = mr->v_origindex ? bm_original_vert_get(mr, loose_vert.coarse_vertex_index) :
BM_vert_at_index(mr->bm, loose_vert.coarse_vertex_index);
vert_set_bm(elb, eve, offset);
offset += 1;
}
}

View File

@ -233,16 +233,17 @@ static GPUVertFormat *get_subdiv_edge_fac_format()
}
static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
GPUVertBuf *edge_idx = cache->final.buff.vbo.edge_idx;
GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
GPU_vertbuf_init_build_on_device(
vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
/* Create a temporary buffer for the edge original indices if it was not requested. */
const bool has_edge_idx = edge_idx != nullptr;
@ -268,11 +269,11 @@ static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
const MeshExtractLooseGeom *loose_geom,
void *buffer,
void *UNUSED(data))
{
if (loose_geom->edge_len == 0) {
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
if (loose_geom.edge_len == 0) {
return;
}
@ -282,7 +283,7 @@ static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cach
GPU_vertbuf_use(vbo);
uint offset = subdiv_cache->num_subdiv_loops;
for (int i = 0; i < loose_geom->edge_len; i++) {
for (int i = 0; i < loose_geom.edge_len; i++) {
if (GPU_crappy_amd_driver()) {
float loose_edge_fac[2] = {1.0f, 1.0f};
GPU_vertbuf_update_sub(vbo, offset * sizeof(float), sizeof(loose_edge_fac), loose_edge_fac);

View File

@ -256,14 +256,15 @@ static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr,
}
static void extract_edit_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
const MeshRenderData *UNUSED(mr),
MeshBatchCache *UNUSED(cache),
void *buf,
void *data)
{
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
GPU_vertbuf_init_with_format(vbo, get_edit_data_format());
GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
*(EditLoopData **)data = vbo_data;
}
@ -322,27 +323,38 @@ static void extract_edit_data_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cach
static void extract_edit_data_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
const MeshExtractLooseGeom *loose_geom,
void *UNUSED(buffer),
void *_data)
{
if (loose_geom->edge_len == 0) {
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
if (loose_geom.edge_len == 0) {
return;
}
EditLoopData *vbo_data = *(EditLoopData **)_data;
blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(subdiv_cache);
for (int ledge_index = 0; ledge_index < loose_geom->edge_len; ledge_index++) {
const int offset = subdiv_cache->num_subdiv_loops + ledge_index * 2;
EditLoopData *vbo_data = *(EditLoopData **)_data;
int ledge_index = 0;
for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
const int offset = subdiv_cache->num_subdiv_loops + ledge_index++ * 2;
EditLoopData *data = &vbo_data[offset];
memset(data, 0, sizeof(EditLoopData));
const int edge_index = loose_geom->edges[ledge_index];
const int edge_index = loose_edge.coarse_edge_index;
BMEdge *eed = mr->e_origindex ? bm_original_edge_get(mr, edge_index) :
BM_edge_at_index(mr->bm, edge_index);
mesh_render_data_edge_flag(mr, eed, &data[0]);
data[1] = data[0];
mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
const DRWSubdivLooseVertex &v1 = loose_geom.verts[loose_edge.loose_subdiv_v1_index];
const DRWSubdivLooseVertex &v2 = loose_geom.verts[loose_edge.loose_subdiv_v2_index];
if (v1.coarse_vertex_index != -1u) {
mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
}
if (v2.coarse_vertex_index != -1u) {
mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
}
}
}

View File

@ -227,16 +227,21 @@ static GPUVertFormat *get_custom_normals_format()
}
static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
void *buffer,
void *UNUSED(data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
/* Initialize the vertex buffer, it was already allocated. */
GPU_vertbuf_init_build_on_device(
vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
if (subdiv_cache->num_subdiv_loops == 0) {
return;
}
draw_subdiv_extract_pos_nor(subdiv_cache, vbo);
@ -289,13 +294,12 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
}
static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
const MeshExtractLooseGeom *loose_geom,
const MeshRenderData *UNUSED(mr),
void *buffer,
void *UNUSED(data))
{
const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
if (loop_loose_len == 0) {
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
if (loose_geom.loop_len == 0) {
return;
}
@ -309,75 +313,38 @@ static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache
float flag;
};
if (mr->extract_type == MR_EXTRACT_MESH) {
const Mesh *coarse_mesh = subdiv_cache->mesh;
const MEdge *coarse_edges = coarse_mesh->medge;
const MVert *coarse_verts = coarse_mesh->mvert;
/* Make sure buffer is active for sending loose data. */
GPU_vertbuf_use(vbo);
SubdivPosNorLoop edge_data[2];
memset(&edge_data, 0, sizeof(SubdivPosNorLoop) * 2);
for (int i = 0; i < loose_geom->edge_len; i++) {
const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
const MVert *loose_vert1 = &coarse_verts[loose_edge->v1];
const MVert *loose_vert2 = &coarse_verts[loose_edge->v2];
blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(subdiv_cache);
copy_v3_v3(edge_data[0].pos, loose_vert1->co);
copy_v3_v3(edge_data[1].pos, loose_vert2->co);
SubdivPosNorLoop edge_data[2];
memset(edge_data, 0, sizeof(SubdivPosNorLoop) * 2);
for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
const DRWSubdivLooseVertex &v1 = loose_geom.verts[loose_edge.loose_subdiv_v1_index];
const DRWSubdivLooseVertex &v2 = loose_geom.verts[loose_edge.loose_subdiv_v2_index];
GPU_vertbuf_update_sub(
vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data);
copy_v3_v3(edge_data[0].pos, v1.co);
copy_v3_v3(edge_data[1].pos, v2.co);
offset += 2;
}
GPU_vertbuf_update_sub(
vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data);
SubdivPosNorLoop vert_data;
memset(&vert_data, 0, sizeof(SubdivPosNorLoop));
for (int i = 0; i < loose_geom->vert_len; i++) {
const MVert *loose_vertex = &coarse_verts[loose_geom->verts[i]];
copy_v3_v3(vert_data.pos, loose_vertex->co);
GPU_vertbuf_update_sub(
vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data);
offset += 1;
}
offset += 2;
}
else {
BMesh *bm = subdiv_cache->bm;
SubdivPosNorLoop edge_data[2];
memset(&edge_data, 0, sizeof(SubdivPosNorLoop) * 2);
for (int i = 0; i < loose_geom->edge_len; i++) {
const BMEdge *loose_edge = BM_edge_at_index(bm, loose_geom->edges[i]);
const BMVert *loose_vert1 = loose_edge->v1;
const BMVert *loose_vert2 = loose_edge->v2;
SubdivPosNorLoop vert_data;
memset(&vert_data, 0, sizeof(SubdivPosNorLoop));
blender::Span<DRWSubdivLooseVertex> loose_verts = draw_subdiv_cache_get_loose_verts(
subdiv_cache);
copy_v3_v3(edge_data[0].pos, loose_vert1->co);
copy_v3_v3(edge_data[0].nor, loose_vert1->no);
for (const DRWSubdivLooseVertex &loose_vert : loose_verts) {
copy_v3_v3(vert_data.pos, loose_vert.co);
copy_v3_v3(edge_data[1].pos, loose_vert2->co);
copy_v3_v3(edge_data[1].nor, loose_vert2->no);
GPU_vertbuf_update_sub(
vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data);
GPU_vertbuf_update_sub(
vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data);
offset += 2;
}
SubdivPosNorLoop vert_data;
memset(&vert_data, 0, sizeof(SubdivPosNorLoop));
for (int i = 0; i < loose_geom->vert_len; i++) {
const BMVert *loose_vertex = BM_vert_at_index(bm, loose_geom->verts[i]);
copy_v3_v3(vert_data.pos, loose_vertex->co);
copy_v3_v3(vert_data.nor, loose_vertex->no);
GPU_vertbuf_update_sub(
vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data);
offset += 1;
}
offset += 1;
}
}

View File

@ -204,12 +204,12 @@ static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
void *UNUSED(data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
/* Each element points to an element in the ibo.points. */
draw_subdiv_init_origindex_buffer(vbo,
(int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index),
subdiv_cache->num_subdiv_loops,
mr->loop_loose_len);
loose_geom.loop_len);
if (!mr->v_origindex) {
return;
}
@ -228,12 +228,11 @@ static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
const MeshExtractLooseGeom *loose_geom,
void *buffer,
void *UNUSED(data))
{
const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
if (loop_loose_len == 0) {
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
if (loose_geom.loop_len == 0) {
return;
}
@ -241,60 +240,57 @@ static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cach
uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo);
uint offset = subdiv_cache->num_subdiv_loops;
if (mr->extract_type == MR_EXTRACT_MESH) {
const Mesh *coarse_mesh = subdiv_cache->mesh;
const MEdge *coarse_edges = coarse_mesh->medge;
for (int i = 0; i < loose_geom->edge_len; i++) {
const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
vert_idx_data[offset] = loose_edge->v1;
vert_idx_data[offset + 1] = loose_edge->v2;
offset += 2;
blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(subdiv_cache);
for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
const DRWSubdivLooseVertex &v1 = loose_geom.verts[loose_edge.loose_subdiv_v1_index];
const DRWSubdivLooseVertex &v2 = loose_geom.verts[loose_edge.loose_subdiv_v2_index];
if (v1.coarse_vertex_index != -1u) {
vert_idx_data[offset] = mr->v_origindex ? mr->v_origindex[v1.coarse_vertex_index] :
v1.coarse_vertex_index;
}
for (int i = 0; i < loose_geom->vert_len; i++) {
vert_idx_data[offset] = loose_geom->verts[i];
offset += 1;
if (v2.coarse_vertex_index != -1u) {
vert_idx_data[offset + 1] = mr->v_origindex ? mr->v_origindex[v2.coarse_vertex_index] :
v2.coarse_vertex_index;
}
offset += 2;
}
else {
BMesh *bm = mr->bm;
for (int i = 0; i < loose_geom->edge_len; i++) {
const BMEdge *loose_edge = BM_edge_at_index(bm, loose_geom->edges[i]);
vert_idx_data[offset] = BM_elem_index_get(loose_edge->v1);
vert_idx_data[offset + 1] = BM_elem_index_get(loose_edge->v2);
offset += 2;
}
for (int i = 0; i < loose_geom->vert_len; i++) {
const BMVert *loose_vert = BM_vert_at_index(bm, loose_geom->verts[i]);
vert_idx_data[offset] = BM_elem_index_get(loose_vert);
offset += 1;
}
blender::Span<DRWSubdivLooseVertex> loose_verts = draw_subdiv_cache_get_loose_verts(
subdiv_cache);
for (const DRWSubdivLooseVertex &loose_vert : loose_verts) {
vert_idx_data[offset] = mr->v_origindex ? mr->v_origindex[loose_vert.coarse_vertex_index] :
loose_vert.coarse_vertex_index;
offset += 1;
}
}
static void extract_edge_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
const MeshRenderData *UNUSED(mr),
MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
draw_subdiv_init_origindex_buffer(
vbo,
static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)),
subdiv_cache->num_subdiv_loops,
mr->edge_loose_len * 2);
loose_geom.edge_len * 2);
}
static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
const MeshExtractLooseGeom *loose_geom,
const MeshRenderData *mr,
void *buffer,
void *UNUSED(data))
{
const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
if (loop_loose_len == 0) {
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
if (loose_geom.edge_len == 0) {
return;
}
@ -302,9 +298,12 @@ static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cach
uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo);
uint offset = subdiv_cache->num_subdiv_loops;
for (int i = 0; i < loose_geom->edge_len; i++) {
vert_idx_data[offset] = loose_geom->edges[i];
vert_idx_data[offset + 1] = loose_geom->edges[i];
blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(subdiv_cache);
for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
const int coarse_edge_index = mr->e_origindex ? mr->e_origindex[loose_edge.coarse_edge_index] :
loose_edge.coarse_edge_index;
vert_idx_data[offset] = coarse_edge_index;
vert_idx_data[offset + 1] = coarse_edge_index;
offset += 2;
}
}