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
16 changed files with 47 additions and 47 deletions
Showing only changes of commit 7106c1b93e - Show all commits

View File

@ -176,8 +176,8 @@ struct MeshRuntime {
* unchanged topology. Accessed with #Mesh::loose_edges()/loose_verts().
*/
SharedCache<LooseEdgeCache> loose_edges_cache;
SharedCache<LooseVertCache> loose_verts_edge_cache;
SharedCache<LooseVertCache> loose_verts_face_cache;
SharedCache<LooseVertCache> loose_verts_no_edge_cache;
SharedCache<LooseVertCache> loose_verts_no_face_cache;
/**
* A bit vector the size of the number of vertices, set to true for the center vertices of

View File

@ -1213,7 +1213,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
switch (bvh_cache_type) {
case BVHTREE_FROM_LOOSEVERTS: {
const blender::bke::LooseVertCache &loose_verts = mesh->loose_verts_edge();
const blender::bke::LooseVertCache &loose_verts = mesh->loose_verts_no_edge();
data->tree = bvhtree_from_mesh_verts_create_tree(0.0f,
tree_type,
6,

View File

@ -767,7 +767,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
if (!offsets.any_single_point_curve) {
/* If there are no single point curves, every curve combination will always have faces. */
mesh->loose_verts_tag_none();
mesh->tag_loose_verts_none();
mesh->loose_edges_tag_none();
}

View File

@ -200,7 +200,7 @@ 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.loose_verts_face();
const bke::LooseVertCache &loose_verts = mesh.loose_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) {
@ -753,12 +753,12 @@ static bool can_simple_adapt_for_single(const Mesh &mesh,
return true;
case ATTR_DOMAIN_EDGE:
if (to_domain == ATTR_DOMAIN_POINT) {
return mesh.loose_verts_edge().count == 0;
return mesh.loose_verts_no_edge().count == 0;
}
return true;
case ATTR_DOMAIN_FACE:
if (to_domain == ATTR_DOMAIN_POINT) {
return mesh.loose_verts_face().count == 0;
return mesh.loose_verts_no_face().count == 0;
}
if (to_domain == ATTR_DOMAIN_EDGE) {
return mesh.loose_edges().count == 0;
@ -766,7 +766,7 @@ static bool can_simple_adapt_for_single(const Mesh &mesh,
return true;
case ATTR_DOMAIN_CORNER:
if (to_domain == ATTR_DOMAIN_POINT) {
return mesh.loose_verts_face().count == 0;
return mesh.loose_verts_no_face().count == 0;
}
if (to_domain == ATTR_DOMAIN_EDGE) {
return mesh.loose_edges().count == 0;

View File

@ -130,8 +130,8 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
* when the source is persistent and edits to the destination mesh don't affect the caches.
* Caches will be "un-shared" as necessary later on. */
mesh_dst->runtime->bounds_cache = mesh_src->runtime->bounds_cache;
mesh_dst->runtime->loose_verts_edge_cache = mesh_src->runtime->loose_verts_edge_cache;
mesh_dst->runtime->loose_verts_face_cache = mesh_src->runtime->loose_verts_face_cache;
mesh_dst->runtime->loose_verts_no_edge_cache = mesh_src->runtime->loose_verts_no_edge_cache;
mesh_dst->runtime->loose_verts_no_face_cache = mesh_src->runtime->loose_verts_no_face_cache;
mesh_dst->runtime->loose_edges_cache = mesh_src->runtime->loose_edges_cache;
mesh_dst->runtime->looptris_cache = mesh_src->runtime->looptris_cache;

View File

@ -108,10 +108,10 @@ MeshRuntime::~MeshRuntime()
} // namespace blender::bke
const blender::bke::LooseVertCache &Mesh::loose_verts_edge() const
const blender::bke::LooseVertCache &Mesh::loose_verts_no_edge() const
{
using namespace blender::bke;
this->runtime->loose_verts_edge_cache.ensure([&](LooseVertCache &r_data) {
this->runtime->loose_verts_no_edge_cache.ensure([&](LooseVertCache &r_data) {
blender::BitVector<> &loose_verts = r_data.is_loose_bits;
loose_verts.resize(0);
loose_verts.resize(this->totvert, true);
@ -129,13 +129,13 @@ const blender::bke::LooseVertCache &Mesh::loose_verts_edge() const
r_data.count = count;
});
return this->runtime->loose_verts_edge_cache.data();
return this->runtime->loose_verts_no_edge_cache.data();
}
const blender::bke::LooseVertCache &Mesh::loose_verts_face() const
const blender::bke::LooseVertCache &Mesh::loose_verts_no_face() const
{
using namespace blender::bke;
this->runtime->loose_verts_face_cache.ensure([&](LooseVertCache &r_data) {
this->runtime->loose_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);
@ -153,7 +153,7 @@ const blender::bke::LooseVertCache &Mesh::loose_verts_face() const
r_data.count = count;
});
return this->runtime->loose_verts_face_cache.data();
return this->runtime->loose_verts_no_face_cache.data();
}
const blender::bke::LooseEdgeCache &Mesh::loose_edges() const
@ -180,26 +180,26 @@ const blender::bke::LooseEdgeCache &Mesh::loose_edges() const
return this->runtime->loose_edges_cache.data();
}
void Mesh::loose_verts_edge_tag_none() const
void Mesh::tag_loose_verts_no_edge_none() const
{
using namespace blender::bke;
this->runtime->loose_verts_edge_cache.ensure([&](LooseVertCache &r_data) {
this->runtime->loose_verts_no_edge_cache.ensure([&](LooseVertCache &r_data) {
r_data.is_loose_bits.clear_and_shrink();
r_data.count = 0;
});
}
void Mesh::loose_verts_face_tag_none() const
void Mesh::tag_loose_verts_no_face_none() const
{
using namespace blender::bke;
this->runtime->loose_verts_face_cache.ensure([&](LooseVertCache &r_data) {
this->runtime->loose_verts_no_face_cache.ensure([&](LooseVertCache &r_data) {
r_data.is_loose_bits.clear_and_shrink();
r_data.count = 0;
});
}
void Mesh::loose_verts_tag_none() const
void Mesh::tag_loose_verts_none() const
{
this->loose_verts_edge_tag_none();
this->loose_verts_face_tag_none();
this->tag_loose_verts_no_edge_none();
this->tag_loose_verts_no_face_none();
}
void Mesh::loose_edges_tag_none() const
@ -289,8 +289,8 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
free_subdiv_ccg(*mesh->runtime);
mesh->runtime->bounds_cache.tag_dirty();
mesh->runtime->loose_edges_cache.tag_dirty();
mesh->runtime->loose_verts_edge_cache.tag_dirty();
mesh->runtime->loose_verts_face_cache.tag_dirty();
mesh->runtime->loose_verts_no_edge_cache.tag_dirty();
mesh->runtime->loose_verts_no_face_cache.tag_dirty();
mesh->runtime->looptris_cache.tag_dirty();
mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink();
@ -309,8 +309,8 @@ void BKE_mesh_tag_edges_split(struct Mesh *mesh)
reset_normals(*mesh->runtime);
free_subdiv_ccg(*mesh->runtime);
mesh->runtime->loose_edges_cache.tag_dirty();
mesh->runtime->loose_verts_edge_cache.tag_dirty();
mesh->runtime->loose_verts_face_cache.tag_dirty();
mesh->runtime->loose_verts_no_edge_cache.tag_dirty();
mesh->runtime->loose_verts_no_face_cache.tag_dirty();
mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink();
if (mesh->runtime->shrinkwrap_data) {

View File

@ -354,7 +354,7 @@ static void initialize_manifold_indices(ConverterStorage *storage)
{
using namespace blender;
const Mesh *mesh = storage->mesh;
const bke::LooseVertCache &loose_verts = mesh->loose_verts_face();
const bke::LooseVertCache &loose_verts = mesh->loose_verts_no_face();
const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
initialize_manifold_index_array(loose_verts.is_loose_bits,
mesh->totvert,

View File

@ -46,7 +46,7 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe
}
}
const bke::LooseVertCache &loose_verts = mr->me->loose_verts_edge();
const bke::LooseVertCache &loose_verts = mr->me->loose_verts_no_edge();
if (loose_verts.count > 0) {
cache->loose_geom.verts.reinitialize(loose_verts.count);

View File

@ -417,7 +417,7 @@ Mesh *create_cuboid_mesh(const float3 &size,
const float3 bounds = size * 0.5f;
mesh->bounds_set_eager({-bounds, bounds});
mesh->loose_verts_tag_none();
mesh->tag_loose_verts_none();
return mesh;
}

View File

@ -951,13 +951,13 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
});
info.no_loose_verts_edge_hint = std::all_of(
info.order.begin(), info.order.end(), [](const Mesh *mesh) {
return mesh->runtime->loose_verts_edge_cache.is_cached() &&
mesh->loose_verts_edge().count == 0;
return mesh->runtime->loose_verts_no_edge_cache.is_cached() &&
mesh->loose_verts_no_edge().count == 0;
});
info.no_loose_verts_face_hint = std::all_of(
info.order.begin(), info.order.end(), [](const Mesh *mesh) {
return mesh->runtime->loose_verts_face_cache.is_cached() &&
mesh->loose_verts_face().count == 0;
return mesh->runtime->loose_verts_no_face_cache.is_cached() &&
mesh->loose_verts_no_face().count == 0;
});
return info;
@ -1168,10 +1168,10 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
dst_mesh->loose_edges_tag_none();
}
if (all_meshes_info.no_loose_verts_edge_hint) {
dst_mesh->loose_verts_edge_tag_none();
dst_mesh->tag_loose_verts_no_edge_none();
}
if (all_meshes_info.no_loose_verts_face_hint) {
dst_mesh->loose_verts_face_tag_none();
dst_mesh->tag_loose_verts_no_face_none();
}
}

View File

@ -306,11 +306,11 @@ typedef struct Mesh {
/**
* Cached information about vertices that aren't used by any edges.
*/
const blender::bke::LooseVertCache &loose_verts_edge() const;
const blender::bke::LooseVertCache &loose_verts_no_edge() const;
/**
* Cached information about vertices that aren't used by faces (but may be used by loose edges).
*/
const blender::bke::LooseVertCache &loose_verts_face() const;
const blender::bke::LooseVertCache &loose_verts_no_face() const;
/**
* Explicitly set the cached number of loose edges to zero. This can improve performance
@ -320,9 +320,9 @@ typedef struct Mesh {
* cache dirty. If the mesh was changed first, the relevant dirty tags should be called first.

Why are these const? Aren't these function you should call after changing the topology when having non-const access to the mesh? BKE_mesh_tag_positions_changed is non-const as well.

Why are these `const`? Aren't these function you should call after changing the topology when having non-const access to the mesh? `BKE_mesh_tag_positions_changed` is non-const as well.

They're const because setting them doesn't change the logical state of the mesh. Let's say you're doing a mostly unrelated calculation and discover that there are no loose vertices, these could be called to pass that information elsewhere without changing the mesh.

BKE_mesh_tag_positions_changed is different, it means "I've changed the positions, the mesh is now different than it was".

They're const because setting them doesn't change the logical state of the mesh. Let's say you're doing a mostly unrelated calculation and discover that there are no loose vertices, these could be called to pass that information elsewhere without changing the mesh. `BKE_mesh_tag_positions_changed` is different, it means "I've changed the positions, the mesh is now different than it was".
*/

It feels a bit like these tag functions are redundant. Shouldn't tag_no_loose_edges and tag_no_loose_verts methods be enough?

It feels a bit like these `tag` functions are redundant. Shouldn't `tag_no_loose_edges` and `tag_no_loose_verts` methods be enough?

Generally they're used in similar situations, but not always. For example, the realize instances node:

  if (all_meshes_info.no_loose_verts_edge_hint) {
    dst_mesh->loose_verts_edge_tag_none();
  }
  if (all_meshes_info.no_loose_verts_face_hint) {
    dst_mesh->loose_verts_face_tag_none();
  }
Generally they're used in similar situations, but not always. For example, the realize instances node: ``` if (all_meshes_info.no_loose_verts_edge_hint) { dst_mesh->loose_verts_edge_tag_none(); } if (all_meshes_info.no_loose_verts_face_hint) { dst_mesh->loose_verts_face_tag_none(); } ```
void loose_edges_tag_none() const;
void loose_verts_edge_tag_none() const;
void loose_verts_face_tag_none() const;
void loose_verts_tag_none() const;
void tag_loose_verts_no_edge_none() const;
void tag_loose_verts_no_face_none() const;
void tag_loose_verts_none() const;
/**
* Normal direction of polygons, defined by positions and the winding direction of face corners.

View File

@ -551,7 +551,7 @@ static void duplicate_faces(GeometrySet &geometry_set,
}
}
new_mesh->loose_verts_tag_none();
new_mesh->tag_loose_verts_none();
new_mesh->loose_edges_tag_none();
copy_face_attributes_without_id(edge_mapping,

View File

@ -154,7 +154,7 @@ 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_verts_tag_none();
mesh->tag_loose_verts_none();
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : poly_offsets.index_range()) {
@ -171,7 +171,7 @@ static Mesh *create_circle_mesh(const float radius,
corner_edges[3 * i + 2] = verts_num + i;
}
mesh->loose_verts_edge_tag_none();
mesh->tag_loose_verts_no_edge_none();
}
mesh->bounds_set_eager(calculate_bounds_circle(radius, verts_num));

View File

@ -723,7 +723,7 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
}
calculate_selection_outputs(config, attribute_outputs, mesh->attributes_for_write());
mesh->loose_verts_tag_none();
mesh->tag_loose_verts_none();
mesh->loose_edges_tag_none();
mesh->bounds_set_eager(calculate_bounds_cylinder(config));

View File

@ -149,7 +149,7 @@ Mesh *create_grid_mesh(const int verts_x,
calculate_uvs(mesh, positions, corner_verts, size_x, size_y, uv_map_id);
}
mesh->loose_verts_tag_none();
mesh->tag_loose_verts_none();
mesh->loose_edges_tag_none();
const float3 bounds = float3(size_x * 0.5f, size_y * 0.5f, 0.0f);

View File

@ -333,7 +333,7 @@ static Mesh *create_uv_sphere_mesh(const float radius,
}
});
mesh->loose_verts_tag_none();
mesh->tag_loose_verts_none();
mesh->loose_edges_tag_none();
mesh->bounds_set_eager(calculate_bounds_uv_sphere(radius, segments, rings));