Mesh: Cache loose vertices #105567

Merged
Hans Goudey merged 29 commits from HooglyBoogly/blender:mesh-loose-vert-cache into main 2023-04-22 13:46:23 +02:00
7 changed files with 67 additions and 62 deletions
Showing only changes of commit 473205df07 - Show all commits

View File

@ -171,12 +171,11 @@ struct MeshRuntime {
mutable Vector<float3> vert_normals;
mutable Vector<float3> poly_normals;
/**
* Caches of data about the loose edges/verts. Can be shared with other data-blocks with
* unchanged topology. Accessed with #Mesh::loose_edges()/loose_verts().
*/
/** Cache of data about edges not used by faces. See #Mesh::loose_edges(). */
SharedCache<LooseEdgeCache> loose_edges_cache;
/** Cache of data about vertices not used by edges. See #Mesh::loose_verts(). */
SharedCache<LooseVertCache> loose_verts_cache;
/** Cache of data about vertices not used by faces. See #Mesh::loose_verts(). */
SharedCache<LooseVertCache> verts_no_face_cache;
/**

View File

@ -202,10 +202,10 @@ void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
/* Deselect loose vertices without corners that are still selected from the 'true' default. */
const bke::LooseVertCache &loose_verts = mesh.verts_no_face();
if (loose_verts.count > 0) {
const BitSpan loose = loose_verts.is_loose_bits;
threading::parallel_for(loose.index_range(), 2048, [loose, r_values](const IndexRange range) {
const BitSpan bits = loose_verts.is_loose_bits;
threading::parallel_for(bits.index_range(), 2048, [&](const IndexRange range) {
for (const int vert_index : range) {
if (loose[vert_index]) {
if (bits[vert_index]) {
r_values[vert_index] = false;
}
}

View File

@ -106,7 +106,7 @@ MeshRuntime::~MeshRuntime()
}
}
static int reset_bits_and_count(const Span<int> indices_to_reset, MutableBitSpan bits)
static int reset_bits_and_count(MutableBitSpan bits, const Span<int> indices_to_reset)
{
int count = bits.size();
for (const int vert : indices_to_reset) {
@ -118,21 +118,45 @@ static int reset_bits_and_count(const Span<int> indices_to_reset, MutableBitSpan
return count;
}
static void bit_vector_with_reset_bits_or_empty(const Span<int> indices_to_reset,
const int indexed_elems_num,
BitVector<> &r_bits,
int &r_count)
{
r_bits.resize(0);
r_bits.resize(indexed_elems_num, true);
r_count = reset_bits_and_count(r_bits, indices_to_reset);
if (r_count == 0) {
r_bits.clear_and_shrink();
}
}
/**
* If there are no loose edges and no loose vertices, all vertices are used by faces.
*/
static void try_tag_verts_no_face_none(const Mesh &mesh)
{
if (mesh.runtime->loose_edges_cache.is_cached() || mesh.loose_edges().count > 0) {
return;
}
if (mesh.runtime->loose_verts_cache.is_cached() || mesh.loose_verts().count > 0) {
return;
}
mesh.runtime->verts_no_face_cache.ensure([&](LooseVertCache &r_data) {
r_data.is_loose_bits.clear_and_shrink();
r_data.count = 0;
});
}
} // namespace blender::bke
const blender::bke::LooseVertCache &Mesh::loose_verts() const
{
using namespace blender::bke;
this->runtime->loose_verts_cache.ensure([&](LooseVertCache &r_data) {
blender::BitVector<> &loose_verts = r_data.is_loose_bits;
loose_verts.resize(0);
loose_verts.resize(this->totvert, true);
r_data.count = reset_bits_and_count(this->edges().cast<int>(), loose_verts);
if (r_data.count == 0) {
loose_verts.clear_and_shrink();
}
const Span<int> verts = this->edges().cast<int>();
bit_vector_with_reset_bits_or_empty(verts, this->totvert, r_data.is_loose_bits, r_data.count);
});
return this->runtime->loose_verts_cache.data();
}
@ -140,15 +164,9 @@ const blender::bke::LooseVertCache &Mesh::verts_no_face() const
{
using namespace blender::bke;
this->runtime->verts_no_face_cache.ensure([&](LooseVertCache &r_data) {
blender::BitVector<> &loose_verts = r_data.is_loose_bits;
loose_verts.resize(0);
loose_verts.resize(this->totvert, true);
r_data.count = reset_bits_and_count(this->corner_verts(), loose_verts);
if (r_data.count == 0) {
loose_verts.clear_and_shrink();
}
const Span<int> verts = this->corner_verts();
bit_vector_with_reset_bits_or_empty(verts, this->totvert, r_data.is_loose_bits, r_data.count);
});
return this->runtime->verts_no_face_cache.data();
}
@ -156,15 +174,9 @@ const blender::bke::LooseEdgeCache &Mesh::loose_edges() const
{
using namespace blender::bke;
this->runtime->loose_edges_cache.ensure([&](LooseEdgeCache &r_data) {
blender::BitVector<> &loose_edges = r_data.is_loose_bits;
loose_edges.resize(0);
loose_edges.resize(this->totedge, true);
r_data.count = reset_bits_and_count(this->corner_edges(), loose_edges);
if (r_data.count == 0) {
loose_edges.clear_and_shrink();
}
const Span<int> edges = this->corner_edges();
bit_vector_with_reset_bits_or_empty(edges, this->totedge, r_data.is_loose_bits, r_data.count);
});
return this->runtime->loose_edges_cache.data();
}
@ -175,15 +187,7 @@ void Mesh::tag_loose_verts_none() const
r_data.is_loose_bits.clear_and_shrink();
r_data.count = 0;
});
}
void Mesh::tag_verts_no_face_none() const
{
using namespace blender::bke;
this->runtime->verts_no_face_cache.ensure([&](LooseEdgeCache &r_data) {
r_data.is_loose_bits.clear_and_shrink();
r_data.count = 0;
});
try_tag_verts_no_face_none(*this);
}
void Mesh::loose_edges_tag_none() const
@ -193,6 +197,7 @@ void Mesh::loose_edges_tag_none() const
r_data.is_loose_bits.clear_and_shrink();
r_data.count = 0;
});
try_tag_verts_no_face_none(*this);
}
blender::Span<MLoopTri> Mesh::looptris() const

View File

@ -30,33 +30,31 @@
/** \name Update Loose Geometry
* \{ */
static void extract_set_bits(const blender::BitSpan bits, blender::MutableSpan<int> indices)
{
int count = 0;
for (const int64_t i : bits.index_range()) {
if (bits[i]) {
indices[count] = int(i);
count++;
}
}
BLI_assert(count == indices.size());
}
static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBufferCache *cache)
{
using namespace blender;
const bke::LooseEdgeCache &loose_edges = mr->me->loose_edges();
if (loose_edges.count > 0) {
cache->loose_geom.edges.reinitialize(loose_edges.count);
int count = 0;
for (const int64_t i : loose_edges.is_loose_bits.index_range()) {
if (loose_edges.is_loose_bits[i]) {
cache->loose_geom.edges[count] = int(i);
count++;
}
}
extract_set_bits(loose_edges.is_loose_bits, cache->loose_geom.edges);
}
const bke::LooseVertCache &loose_verts = mr->me->loose_verts();
if (loose_verts.count > 0) {
cache->loose_geom.verts.reinitialize(loose_verts.count);
int count = 0;
for (const int64_t i : loose_edges.is_loose_bits.index_range()) {
if (loose_verts.is_loose_bits[i]) {
cache->loose_geom.verts[count] = int(i);
count++;
}
}
extract_set_bits(loose_verts.is_loose_bits, cache->loose_geom.verts);
}
}

View File

@ -203,7 +203,7 @@ struct AllMeshesInfo {
/** True if we know that there are no loose edges in any of the input meshes. */
bool no_loose_edges_hint = false;
bool no_loose_verts_edge_hint = false;
bool no_loose_verts_hint = false;
};
struct AllCurvesInfo {
@ -948,7 +948,7 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
info.order.begin(), info.order.end(), [](const Mesh *mesh) {
return mesh->runtime->loose_edges_cache.is_cached() && mesh->loose_edges().count == 0;
});
info.no_loose_verts_edge_hint = std::all_of(
info.no_loose_verts_hint = std::all_of(
info.order.begin(), info.order.end(), [](const Mesh *mesh) {
return mesh->runtime->loose_verts_cache.is_cached() && mesh->loose_verts().count == 0;
});
@ -1160,7 +1160,7 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
if (all_meshes_info.no_loose_edges_hint) {
dst_mesh->loose_edges_tag_none();
}
if (all_meshes_info.no_loose_verts_edge_hint) {
if (all_meshes_info.no_loose_verts_hint) {
dst_mesh->tag_loose_verts_none();
}
}

View File

@ -309,7 +309,6 @@ typedef struct Mesh {
const blender::bke::LooseVertCache &loose_verts() const;
/**
* Cached information about vertices that aren't used by faces (but may be used by loose edges).
* This also contains vertices with no edges from #loose_verts().
*/
const blender::bke::LooseVertCache &verts_no_face() const;
@ -324,9 +323,11 @@ typedef struct Mesh {
/**
* Set the number of verices not connected to edges to zero. Similar to #loose_edges_tag_none().
* There may still be vertices only used by loose edges though.
*
* \note If both #loose_edges_tag_none() and #tag_loose_verts_none() are called,
* all vertices are used by faces, so #verts_no_faces() will be tagged empty as well.
*/
void tag_loose_verts_none() const;
void tag_verts_no_face_none() const;
/**
* Normal direction of polygons, defined by positions and the winding direction of face corners.

View File

@ -153,6 +153,8 @@ static Mesh *create_circle_mesh(const float radius,
std::iota(corner_verts.begin(), corner_verts.end(), 0);
std::iota(corner_edges.begin(), corner_edges.end(), 0);
mesh->loose_edges_tag_none();
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : poly_offsets.index_range()) {