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:
-rw-r--r--source/blender/blenkernel/BKE_subdiv_mesh.h8
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.cc79
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc33
3 files changed, 92 insertions, 28 deletions
diff --git a/source/blender/blenkernel/BKE_subdiv_mesh.h b/source/blender/blenkernel/BKE_subdiv_mesh.h
index b24db517143..49c45efafe0 100644
--- a/source/blender/blenkernel/BKE_subdiv_mesh.h
+++ b/source/blender/blenkernel/BKE_subdiv_mesh.h
@@ -14,7 +14,9 @@ extern "C" {
#endif
struct Mesh;
+struct MeshElemMap;
struct MEdge;
+struct MVert;
struct Subdiv;
typedef struct SubdivToMeshSettings {
@@ -37,8 +39,10 @@ struct Mesh *BKE_subdiv_to_mesh(struct Subdiv *subdiv,
/* 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,
+void BKE_subdiv_mesh_interpolate_position_on_edge(const struct MVert *coarse_verts,
+ const struct MEdge *coarse_edges,
+ const struct MeshElemMap *vert_to_edge_map,
+ int coarse_edge_index,
bool is_simple,
float u,
float pos_r[3]);
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc
index 5a2af36e83c..dc9fc3dee09 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.cc
+++ b/source/blender/blenkernel/intern/subdiv_mesh.cc
@@ -5,6 +5,8 @@
* \ingroup bke
*/
+#include <mutex>
+
#include "atomic_ops.h"
#include "DNA_key_types.h"
@@ -18,6 +20,7 @@
#include "BKE_customdata.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_eval.h"
#include "BKE_subdiv_foreach.h"
@@ -25,6 +28,8 @@
#include "MEM_guardedalloc.h"
+using blender::Span;
+
/* -------------------------------------------------------------------- */
/** \name Subdivision Context
* \{ */
@@ -58,6 +63,11 @@ struct SubdivMeshContext {
/* Per-subdivided vertex counter of averaged values. */
int *accumulated_counters;
bool have_displacement;
+
+ /* Lazily initialize a map from vertices to connected edges. */
+ std::mutex vert_to_edge_map_mutex;
+ int *vert_to_edge_buffer;
+ MeshElemMap *vert_to_edge_map;
};
static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
@@ -106,6 +116,8 @@ static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vert
static void subdiv_mesh_context_free(SubdivMeshContext *ctx)
{
MEM_SAFE_FREE(ctx->accumulated_counters);
+ MEM_SAFE_FREE(ctx->vert_to_edge_buffer);
+ MEM_SAFE_FREE(ctx->vert_to_edge_map);
}
/** \} */
@@ -961,25 +973,30 @@ 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 Mesh *coarse_mesh,
- const MEdge *edge,
+static void find_edge_neighbors(const MEdge *coarse_edges,
+ const MeshElemMap *vert_to_edge_map,
+ const int edge_index,
const MEdge *neighbors[2])
{
- const blender::Span<MEdge> coarse_edges = coarse_mesh->edges();
+ const MEdge *edge = &coarse_edges[edge_index];
neighbors[0] = nullptr;
neighbors[1] = nullptr;
int neighbor_counters[2] = {0, 0};
- for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) {
- const MEdge *current_edge = &coarse_edges[edge_index];
- if (current_edge == edge) {
+ for (const int i : Span(vert_to_edge_map[edge->v1].indices, vert_to_edge_map[edge->v1].count)) {
+ if (i == edge_index) {
continue;
}
- if (ELEM(edge->v1, current_edge->v1, current_edge->v2)) {
- neighbors[0] = current_edge;
+ if (ELEM(edge->v1, coarse_edges[i].v1, coarse_edges[i].v2)) {
+ neighbors[0] = &coarse_edges[i];
++neighbor_counters[0];
}
- if (ELEM(edge->v2, current_edge->v1, current_edge->v2)) {
- neighbors[1] = current_edge;
+ }
+ for (const int i : Span(vert_to_edge_map[edge->v2].indices, vert_to_edge_map[edge->v2].count)) {
+ if (i == edge_index) {
+ continue;
+ }
+ if (ELEM(edge->v2, coarse_edges[i].v1, coarse_edges[i].v2)) {
+ neighbors[1] = &coarse_edges[i];
++neighbor_counters[1];
}
}
@@ -994,12 +1011,11 @@ static void find_edge_neighbors(const Mesh *coarse_mesh,
}
}
-static void points_for_loose_edges_interpolation_get(const Mesh *coarse_mesh,
+static void points_for_loose_edges_interpolation_get(const MVert *coarse_mvert,
const MEdge *coarse_edge,
const MEdge *neighbors[2],
float points_r[4][3])
{
- const MVert *coarse_mvert = BKE_mesh_verts(coarse_mesh);
/* Middle points corresponds to the edge. */
copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co);
copy_v3_v3(points_r[2], coarse_mvert[coarse_edge->v2].co);
@@ -1031,24 +1047,26 @@ static void points_for_loose_edges_interpolation_get(const Mesh *coarse_mesh,
}
}
-void BKE_subdiv_mesh_interpolate_position_on_edge(const Mesh *coarse_mesh,
- const MEdge *coarse_edge,
+void BKE_subdiv_mesh_interpolate_position_on_edge(const MVert *coarse_verts,
+ const MEdge *coarse_edges,
+ const MeshElemMap *vert_to_edge_map,
+ const int coarse_edge_index,
const bool is_simple,
const float u,
float pos_r[3])
{
+ const MEdge *coarse_edge = &coarse_edges[coarse_edge_index];
if (is_simple) {
- const MVert *coarse_mvert = BKE_mesh_verts(coarse_mesh);
- const MVert *vert_1 = &coarse_mvert[coarse_edge->v1];
- const MVert *vert_2 = &coarse_mvert[coarse_edge->v2];
+ const MVert *vert_1 = &coarse_verts[coarse_edge->v1];
+ const MVert *vert_2 = &coarse_verts[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);
+ find_edge_neighbors(coarse_edges, vert_to_edge_map, coarse_edge_index, neighbors);
float points[4][3];
- points_for_loose_edges_interpolation_get(coarse_mesh, coarse_edge, neighbors, points);
+ points_for_loose_edges_interpolation_get(coarse_verts, 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);
@@ -1090,6 +1108,20 @@ static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach
const Mesh *coarse_mesh = ctx->coarse_mesh;
const MEdge *coarse_edge = &ctx->coarse_edges[coarse_edge_index];
const bool is_simple = ctx->subdiv->settings.is_simple;
+
+ /* Lazily initialize a vertex to edge map to avoid quadratic runtime when subdividing loose
+ * edges. Do this here to avoid the cost in common cases when there are no loose edges at all. */
+ if (ctx->vert_to_edge_map == NULL) {
+ std::lock_guard lock{ctx->vert_to_edge_map_mutex};
+ if (ctx->vert_to_edge_map == NULL) {
+ BKE_mesh_vert_edge_map_create(&ctx->vert_to_edge_map,
+ &ctx->vert_to_edge_buffer,
+ ctx->coarse_edges,
+ coarse_mesh->totvert,
+ ctx->coarse_mesh->totedge);
+ }
+ }
+
/* 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)) {
@@ -1097,8 +1129,13 @@ static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach
}
/* Interpolate coordinate. */
MVert *subdiv_vertex = &ctx->subdiv_verts[subdiv_vertex_index];
- BKE_subdiv_mesh_interpolate_position_on_edge(
- coarse_mesh, coarse_edge, is_simple, u, subdiv_vertex->co);
+ BKE_subdiv_mesh_interpolate_position_on_edge(ctx->coarse_verts,
+ ctx->coarse_edges,
+ ctx->vert_to_edge_map,
+ coarse_edge_index,
+ 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
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 51fbc5a3027..ab935809f96 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -10,6 +10,7 @@
#include "BKE_attribute.hh"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -2155,7 +2156,17 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac
int subd_vert_offset = 0;
/* Subdivide each loose coarse edge. */
+ const Span<MVert> coarse_verts = coarse_mesh->verts();
const Span<MEdge> coarse_edges = coarse_mesh->edges();
+
+ int *vert_to_edge_buffer;
+ MeshElemMap *vert_to_edge_map;
+ BKE_mesh_vert_edge_map_create(&vert_to_edge_map,
+ &vert_to_edge_buffer,
+ coarse_edges.data(),
+ coarse_mesh->totvert,
+ coarse_edges.size());
+
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_edges[cache->loose_geom.edges[i]];
@@ -2169,8 +2180,13 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac
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);
+ BKE_subdiv_mesh_interpolate_position_on_edge(coarse_verts.data(),
+ coarse_edges.data(),
+ vert_to_edge_map,
+ coarse_edge_index,
+ is_simple,
+ u1,
+ subd_v1.co);
subd_edge.loose_subdiv_v1_index = subd_vert_offset++;
@@ -2178,15 +2194,22 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac
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);
+ BKE_subdiv_mesh_interpolate_position_on_edge(coarse_verts.data(),
+ coarse_edges.data(),
+ vert_to_edge_map,
+ coarse_edge_index,
+ is_simple,
+ u2,
+ subd_v2.co);
subd_edge.loose_subdiv_v2_index = subd_vert_offset++;
}
}
+ MEM_freeN(vert_to_edge_buffer);
+ MEM_freeN(vert_to_edge_map);
+
/* Copy the remaining loose_verts. */
- const Span<MVert> coarse_verts = coarse_mesh->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_verts[coarse_vertex_index];