Mesh: Cache loose vertices #105567
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()) {
|
||||
|
|
Loading…
Reference in New Issue