Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/intern/draw_cache_impl_subdivision.cc')
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc254
1 files changed, 207 insertions, 47 deletions
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 5d99478476c..8682a15feba 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -518,6 +518,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);
@@ -550,6 +555,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);
@@ -557,6 +563,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
@@ -729,19 +740,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
@@ -780,16 +797,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;
@@ -833,6 +854,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) {
@@ -983,7 +1008,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.
*/
@@ -991,44 +1017,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);
+
+ /* 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->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+ cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer(
+ cache->subdiv_polygon_offset, mesh_eval->totpoly);
- /* 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->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;
}
@@ -1184,6 +1213,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;
@@ -1241,6 +1275,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;
@@ -1462,6 +1501,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";
@@ -1498,6 +1542,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;
@@ -1616,6 +1665,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);
@@ -1831,7 +1885,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);
@@ -1868,6 +1930,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,