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
20 changed files with 83 additions and 91 deletions
Showing only changes of commit 320463a272 - Show all commits

View File

@ -29,7 +29,7 @@ namespace blender::bke {
*
* Once created, #AnonymousAttributeID is immutable. Also it is intrinsically reference counted so
* that it can have shared ownership. `std::shared_ptr` can't be used for that purpose here,
* because that is not available in C code. If possible, the #AutoAnonymousAttributeID wrapper
* because that is not available in C code. If possible, the #AnonymousAttributeIDPtr wrapper
* should be used to avoid manual reference counting in C++ code.
*/
class AnonymousAttributeID : public ImplicitSharingMixin {
@ -54,7 +54,7 @@ class AnonymousAttributeID : public ImplicitSharingMixin {
};
/** Wrapper for #AnonymousAttributeID that avoids manual reference counting. */
using AutoAnonymousAttributeID = ImplicitSharingPtr<const AnonymousAttributeID>;
using AnonymousAttributeIDPtr = ImplicitSharingPtr<const AnonymousAttributeID>;
/**
* A set of anonymous attribute names that is passed around in geometry nodes.

View File

@ -259,11 +259,11 @@ class NormalFieldInput : public GeometryFieldInput {
class AnonymousAttributeFieldInput : public GeometryFieldInput {
private:
AutoAnonymousAttributeID anonymous_id_;
AnonymousAttributeIDPtr anonymous_id_;
std::string producer_name_;
public:
AnonymousAttributeFieldInput(AutoAnonymousAttributeID anonymous_id,
AnonymousAttributeFieldInput(AnonymousAttributeIDPtr anonymous_id,
const CPPType &type,
std::string producer_name)
: GeometryFieldInput(type, anonymous_id->user_name()),
@ -274,7 +274,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
}
template<typename T>
static fn::Field<T> Create(AutoAnonymousAttributeID anonymous_id, std::string producer_name)
static fn::Field<T> Create(AnonymousAttributeIDPtr anonymous_id, std::string producer_name)
{
const CPPType &type = CPPType::get<T>();
auto field_input = std::make_shared<AnonymousAttributeFieldInput>(
@ -282,7 +282,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
return fn::Field<T>{field_input};
}
const AutoAnonymousAttributeID &anonymous_id() const
const AnonymousAttributeIDPtr &anonymous_id() const
{
return anonymous_id_;
}

View File

@ -833,8 +833,7 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
}
static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
const blender::int2 *edge,
const int edge_num,
blender::Span<blender::int2> edges,
const BitSpan edges_mask,
int edges_num_active,
float epsilon,
@ -842,10 +841,10 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
int axis)
{
if (!edges_mask.is_empty()) {
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges.size()));
}
else {
edges_num_active = edge_num;
edges_num_active = edges.size();
}
if (edges_num_active == 0) {
return nullptr;
@ -857,13 +856,13 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
return nullptr;
}
for (int i = 0; i < edge_num; i++) {
for (const int i : edges.index_range()) {
if (!edges_mask.is_empty() && !edges_mask[i]) {
continue;
}
float co[2][3];
copy_v3_v3(co[0], positions[edge[i][0]]);
copy_v3_v3(co[1], positions[edge[i][1]]);
copy_v3_v3(co[0], positions[edges[i][0]]);
copy_v3_v3(co[1], positions[edges[i][1]]);
BLI_bvhtree_insert(tree, i, co[0], 2);
}
@ -908,7 +907,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
int axis)
{
BVHTree *tree = bvhtree_from_mesh_edges_create_tree(
vert_positions, edge, edges_num, edges_mask, edges_num_active, epsilon, tree_type, axis);
vert_positions, {edge, edges_num}, edges_mask, edges_num_active, epsilon, tree_type, axis);
bvhtree_balance(tree, false);
@ -1142,22 +1141,6 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
return tree;
}
static BitVector<> loose_verts_map_get(const Mesh &mesh, int *r_loose_vert_num)
{
using namespace blender::bke;
const LooseVertCache &loose_verts = mesh.loose_verts_edge();
*r_loose_vert_num = loose_verts.count;
return loose_verts.is_loose_bits;
}
static BitVector<> loose_edges_map_get(const Mesh &mesh, int *r_loose_edge_len)
{
using namespace blender::bke;
const LooseEdgeCache &loose_edges = mesh.loose_edges();
*r_loose_edge_len = loose_edges.count;
return loose_edges.is_loose_bits;
}
static BitVector<> looptri_no_hidden_map_get(const blender::OffsetIndices<int> polys,
const VArray<bool> &hide_poly,
HooglyBoogly marked this conversation as resolved Outdated

Does this intentionally return by value instead of const-references? Same below.

Does this intentionally return by value instead of const-references? Same below.
const int looptri_len,
@ -1227,27 +1210,36 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
}
/* Create BVHTree. */
BitVector<> mask;
int mask_bits_act_len = -1;
switch (bvh_cache_type) {
case BVHTREE_FROM_LOOSEVERTS:
mask = loose_verts_map_get(*mesh, &mask_bits_act_len);
ATTR_FALLTHROUGH;
case BVHTREE_FROM_VERTS:
case BVHTREE_FROM_LOOSEVERTS: {
const blender::bke::LooseVertCache &loose_verts = mesh->loose_verts_edge();
data->tree = bvhtree_from_mesh_verts_create_tree(0.0f,
tree_type,
6,
positions,
mesh->totvert,
loose_verts.is_loose_bits,
loose_verts.count);
break;
}
case BVHTREE_FROM_VERTS: {
data->tree = bvhtree_from_mesh_verts_create_tree(
0.0f, tree_type, 6, positions, mesh->totvert, mask, mask_bits_act_len);
0.0f, tree_type, 6, positions, mesh->totvert, {}, -1);
break;
case BVHTREE_FROM_LOOSEEDGES:
mask = loose_edges_map_get(*mesh, &mask_bits_act_len);
ATTR_FALLTHROUGH;
case BVHTREE_FROM_EDGES:
}
case BVHTREE_FROM_LOOSEEDGES: {
const blender::bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
data->tree = bvhtree_from_mesh_edges_create_tree(
positions, edges.data(), mesh->totedge, mask, mask_bits_act_len, 0.0f, tree_type, 6);
positions, edges, loose_edges.is_loose_bits, loose_edges.count, 0.0f, tree_type, 6);
break;
case BVHTREE_FROM_FACES:
}
case BVHTREE_FROM_EDGES: {
data->tree = bvhtree_from_mesh_edges_create_tree(
positions, edges, {}, -1, 0.0f, tree_type, 6);
break;
}
case BVHTREE_FROM_FACES: {
BLI_assert(!(mesh->totface == 0 && mesh->totpoly != 0));
data->tree = bvhtree_from_mesh_faces_create_tree(
0.0f,
@ -1259,25 +1251,29 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
{},
-1);
break;
}
case BVHTREE_FROM_LOOPTRI_NO_HIDDEN: {
blender::bke::AttributeAccessor attributes = mesh->attributes();
mask = looptri_no_hidden_map_get(
int mask_bits_act_len = -1;
const BitVector<> mask = looptri_no_hidden_map_get(
mesh->polys(),
*attributes.lookup_or_default(".hide_poly", ATTR_DOMAIN_FACE, false),
looptris.size(),
&mask_bits_act_len);
ATTR_FALLTHROUGH;
}
case BVHTREE_FROM_LOOPTRI:
data->tree = bvhtree_from_mesh_looptri_create_tree(
0.0f, tree_type, 6, positions, corner_verts.data(), looptris, mask, mask_bits_act_len);
break;
}
case BVHTREE_FROM_LOOPTRI: {
data->tree = bvhtree_from_mesh_looptri_create_tree(
0.0f, tree_type, 6, positions, corner_verts.data(), looptris, {}, -1);
break;
}
case BVHTREE_FROM_EM_VERTS:
case BVHTREE_FROM_EM_EDGES:
case BVHTREE_FROM_EM_LOOPTRI:
case BVHTREE_MAX_ITEM:
BLI_assert(false);
BLI_assert_unreachable();
break;
}

View File

@ -198,7 +198,7 @@ static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
* anyway... */
const int cb_flag = ((parent->collection != NULL &&
(parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
IDWALK_CB_EMBEDDED :
IDWALK_CB_EMBEDDED_NOT_OWNING :
IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);

View File

@ -73,7 +73,7 @@ static void add_new_edges(Mesh &mesh,
/* Store a copy of the IDs locally since we will remove the existing attributes which
* can also free the names, since the API does not provide pointer stability. */
Vector<std::string> named_ids;
Vector<bke::AutoAnonymousAttributeID> anonymous_ids;
Vector<bke::AnonymousAttributeIDPtr> anonymous_ids;
for (const bke::AttributeIDRef &id : attributes.all_ids()) {
if (attributes.lookup_meta_data(id)->domain != ATTR_DOMAIN_EDGE) {
continue;
@ -95,7 +95,7 @@ static void add_new_edges(Mesh &mesh,
for (const StringRef name : named_ids) {
local_edge_ids.append(name);
}
for (const bke::AutoAnonymousAttributeID &id : anonymous_ids) {
for (const bke::AnonymousAttributeIDPtr &id : anonymous_ids) {
local_edge_ids.append(*id);
}

View File

@ -18,6 +18,7 @@ namespace blender::nodes {
using bke::AnonymousAttributeFieldInput;
using bke::AnonymousAttributeID;
using bke::AnonymousAttributeIDPtr;
using bke::AnonymousAttributePropagationInfo;
using bke::AttributeAccessor;
using bke::AttributeFieldInput;
@ -26,7 +27,6 @@ using bke::AttributeKind;
using bke::AttributeMetaData;
using bke::AttributeReader;
using bke::AttributeWriter;
using bke::AutoAnonymousAttributeID;
using bke::GAttributeReader;
using bke::GAttributeWriter;
using bke::GSpanAttributeWriter;
@ -259,7 +259,7 @@ class GeoNodeExecParams {
* Return a new anonymous attribute id for the given output. None is returned if the anonymous
* attribute is not needed.
*/
AutoAnonymousAttributeID get_output_anonymous_attribute_id_if_needed(
AnonymousAttributeIDPtr get_output_anonymous_attribute_id_if_needed(
const StringRef output_identifier, const bool force_create = false)
{
if (!this->anonymous_attribute_output_is_required(output_identifier) && !force_create) {

View File

@ -56,10 +56,10 @@ Mesh *create_grid_mesh(
int verts_x, int verts_y, float size_x, float size_y, const AttributeIDRef &uv_map_id);
struct ConeAttributeOutputs {
AutoAnonymousAttributeID top_id;
AutoAnonymousAttributeID bottom_id;
AutoAnonymousAttributeID side_id;
AutoAnonymousAttributeID uv_map_id;
AnonymousAttributeIDPtr top_id;
AnonymousAttributeIDPtr bottom_id;
AnonymousAttributeIDPtr side_id;
AnonymousAttributeIDPtr uv_map_id;
};
Mesh *create_cylinder_or_cone_mesh(float radius_top,

View File

@ -142,7 +142,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const eAttrDomain domain = eAttrDomain(storage.domain);
const std::string output_identifier = "Attribute" + identifier_suffix(data_type);
AutoAnonymousAttributeID attribute_id = params.get_output_anonymous_attribute_id_if_needed(
AnonymousAttributeIDPtr attribute_id = params.get_output_anonymous_attribute_id_if_needed(
output_identifier);
if (!attribute_id) {

View File

@ -30,7 +30,7 @@ static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
}
struct AttributeOutputs {
AutoAnonymousAttributeID intersecting_edges_id;
AnonymousAttributeIDPtr intersecting_edges_id;
};
static void node_update(bNodeTree *ntree, bNode *node)

View File

@ -59,7 +59,7 @@ static Curves *create_star_curve(const float inner_radius,
}
static void create_selection_output(CurveComponent &component,
AutoAnonymousAttributeID &r_attribute)
AnonymousAttributeIDPtr &r_attribute)
{
SpanAttributeWriter<bool> selection =
component.attributes_for_write()->lookup_or_add_for_write_only_span<bool>(*r_attribute,
@ -78,8 +78,8 @@ static void node_geo_exec(GeoNodeExecParams params)
std::max(params.extract_input<int>("Points"), 3));
GeometrySet output = GeometrySet::create_with_curves(curves);
if (AutoAnonymousAttributeID outer_points_id =
params.get_output_anonymous_attribute_id_if_needed("Outer Points")) {
if (AnonymousAttributeIDPtr outer_points_id = params.get_output_anonymous_attribute_id_if_needed(
"Outer Points")) {
create_selection_output(output.get_component_for_write<CurveComponent>(), outer_points_id);
params.set_output("Outer Points",
AnonymousAttributeFieldInput::Create<bool>(

View File

@ -135,13 +135,13 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(geometry_set);
AutoAnonymousAttributeID rotation_anonymous_id =
AnonymousAttributeIDPtr rotation_anonymous_id =
params.get_output_anonymous_attribute_id_if_needed("Rotation");
const bool need_tangent_and_normal = bool(rotation_anonymous_id);
AutoAnonymousAttributeID tangent_anonymous_id =
AnonymousAttributeIDPtr tangent_anonymous_id =
params.get_output_anonymous_attribute_id_if_needed("Tangent", need_tangent_and_normal);
AutoAnonymousAttributeID normal_anonymous_id =
params.get_output_anonymous_attribute_id_if_needed("Normal", need_tangent_and_normal);
AnonymousAttributeIDPtr normal_anonymous_id = params.get_output_anonymous_attribute_id_if_needed(
"Normal", need_tangent_and_normal);
geometry::ResampleCurvesOutputAttributeIDs resample_attributes;
resample_attributes.tangent_id = tangent_anonymous_id.get();

View File

@ -322,8 +322,8 @@ BLI_NOINLINE static void propagate_existing_attributes(
namespace {
struct AttributeOutputs {
AutoAnonymousAttributeID normal_id;
AutoAnonymousAttributeID rotation_id;
AnonymousAttributeIDPtr normal_id;
AnonymousAttributeIDPtr rotation_id;
};
} // namespace

View File

@ -57,7 +57,7 @@ static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
}
struct IndexAttributes {
AutoAnonymousAttributeID duplicate_index;
AnonymousAttributeIDPtr duplicate_index;
};
/* -------------------------------------------------------------------- */

View File

@ -62,8 +62,8 @@ static void node_update(bNodeTree *ntree, bNode *node)
}
struct AttributeOutputs {
AutoAnonymousAttributeID top_id;
AutoAnonymousAttributeID side_id;
AnonymousAttributeIDPtr top_id;
AnonymousAttributeIDPtr side_id;
};
static void save_selection_as_attribute(Mesh &mesh,

View File

@ -593,8 +593,8 @@ static void interpolate_curve_attributes(bke::CurvesGeometry &child_curves,
}
static void store_output_attributes(bke::CurvesGeometry &child_curves,
const AutoAnonymousAttributeID weight_attribute_id,
const AutoAnonymousAttributeID index_attribute_id,
const AnonymousAttributeIDPtr weight_attribute_id,
const AnonymousAttributeIDPtr index_attribute_id,
const int max_neighbors,
const Span<int> all_neighbor_counts,
const Span<int> all_neighbor_indices,
@ -658,8 +658,8 @@ static GeometrySet generate_interpolated_curves(
const VArray<int> &point_group_ids,
const int max_neighbors,
const AnonymousAttributePropagationInfo &propagation_info,
const AutoAnonymousAttributeID &index_attribute_id,
const AutoAnonymousAttributeID &weight_attribute_id)
const AnonymousAttributeIDPtr &index_attribute_id,
const AnonymousAttributeIDPtr &weight_attribute_id)
{
const bke::CurvesGeometry &guide_curves = guide_curves_id.geometry.wrap();
@ -813,10 +813,10 @@ static void node_geo_exec(GeoNodeExecParams params)
const AnonymousAttributePropagationInfo propagation_info = params.get_output_propagation_info(
"Curves");
AutoAnonymousAttributeID index_attribute_id = params.get_output_anonymous_attribute_id_if_needed(
AnonymousAttributeIDPtr index_attribute_id = params.get_output_anonymous_attribute_id_if_needed(
"Closest Index");
AutoAnonymousAttributeID weight_attribute_id =
params.get_output_anonymous_attribute_id_if_needed("Closest Weight");
AnonymousAttributeIDPtr weight_attribute_id = params.get_output_anonymous_attribute_id_if_needed(
"Closest Weight");
GeometrySet new_curves = generate_interpolated_curves(guide_curves_id,
*points_component->attributes(),

View File

@ -107,8 +107,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
AutoAnonymousAttributeID uv_map_id = params.get_output_anonymous_attribute_id_if_needed(
"UV Map");
AnonymousAttributeIDPtr uv_map_id = params.get_output_anonymous_attribute_id_if_needed("UV Map");
Mesh *mesh = create_cube_mesh(size, verts_x, verts_y, verts_z, uv_map_id.get());

View File

@ -199,8 +199,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
AutoAnonymousAttributeID uv_map_id = params.get_output_anonymous_attribute_id_if_needed(
"UV Map");
AnonymousAttributeIDPtr uv_map_id = params.get_output_anonymous_attribute_id_if_needed("UV Map");
Mesh *mesh = create_grid_mesh(verts_x, verts_y, size_x, size_y, uv_map_id.get());
BKE_id_material_eval_ensure_default_slot(&mesh->id);

View File

@ -111,8 +111,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10);
const float radius = params.extract_input<float>("Radius");
AutoAnonymousAttributeID uv_map_id = params.get_output_anonymous_attribute_id_if_needed(
"UV Map");
AnonymousAttributeIDPtr uv_map_id = params.get_output_anonymous_attribute_id_if_needed("UV Map");
Mesh *mesh = create_ico_sphere_mesh(subdivisions, radius, uv_map_id.get());
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));

View File

@ -359,8 +359,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const float radius = params.extract_input<float>("Radius");
AutoAnonymousAttributeID uv_map_id = params.get_output_anonymous_attribute_id_if_needed(
"UV Map");
AnonymousAttributeIDPtr uv_map_id = params.get_output_anonymous_attribute_id_if_needed("UV Map");
Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num, uv_map_id.get());
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));

View File

@ -342,7 +342,7 @@ static void create_attributes(GeoNodeExecParams &params,
{
MutableAttributeAccessor attributes = instances.attributes_for_write();
if (AutoAnonymousAttributeID line_id = params.get_output_anonymous_attribute_id_if_needed(
if (AnonymousAttributeIDPtr line_id = params.get_output_anonymous_attribute_id_if_needed(
"Line")) {
SpanAttributeWriter<int> line_attribute = attributes.lookup_or_add_for_write_only_span<int>(
*line_id, ATTR_DOMAIN_INSTANCE);
@ -353,7 +353,7 @@ static void create_attributes(GeoNodeExecParams &params,
params.attribute_producer_name()));
}
if (AutoAnonymousAttributeID pivot_id = params.get_output_anonymous_attribute_id_if_needed(
if (AnonymousAttributeIDPtr pivot_id = params.get_output_anonymous_attribute_id_if_needed(
"Pivot Point")) {
SpanAttributeWriter<float3> pivot_attribute =
attributes.lookup_or_add_for_write_only_span<float3>(*pivot_id, ATTR_DOMAIN_INSTANCE);