Geometry Nodes: speedup joining many geometries

Joining many geometries was O(n^2) because of deduplication of the same
components was not done using a map. My test file that generates 1000
stars in a repeat zone got 10x faster, but it's possible to create a file for any
speedup.
This commit is contained in:
Jacques Lucke
2024-09-12 17:49:16 +02:00
parent 5ff4e5fcb9
commit bde6f888e2
4 changed files with 25 additions and 4 deletions

View File

@@ -446,6 +446,12 @@ struct GeometrySet {
return Span(a.components_) == Span(b.components_) && a.name == b.name;
}
uint64_t hash() const
{
/* This should have the same data that's also taken into account in #operator==. */
return get_default_hash(Span(components_), this->name);
}
void count_memory(MemoryCounter &memory) const;
private:

View File

@@ -105,6 +105,8 @@ class InstanceReference {
void count_memory(MemoryCounter &memory) const;
friend bool operator==(const InstanceReference &a, const InstanceReference &b);
uint64_t hash() const;
};
class Instances {

View File

@@ -131,6 +131,11 @@ bool operator==(const InstanceReference &a, const InstanceReference &b)
return a.type_ == b.type_ && a.data_ == b.data_;
}
uint64_t InstanceReference::hash() const
{
return get_default_hash(geometry_set_, type_, data_);
}
Instances::Instances()
{
CustomData_reset(&attributes_);

View File

@@ -110,6 +110,8 @@ static void join_instances(const Span<const GeometryComponent *> src_components,
MutableSpan<int> all_handles = dst_instances->reference_handles_for_write();
Map<std::reference_wrapper<const bke::InstanceReference>, int> new_handle_by_src_reference;
for (const int i : src_components.index_range()) {
const auto &src_component = static_cast<const bke::InstancesComponent &>(*src_components[i]);
const bke::Instances &src_instances = *src_component.get();
@@ -117,7 +119,9 @@ static void join_instances(const Span<const GeometryComponent *> src_components,
const Span<bke::InstanceReference> src_references = src_instances.references();
Array<int> handle_map(src_references.size());
for (const int src_handle : src_references.index_range()) {
handle_map[src_handle] = dst_instances->add_reference(src_references[src_handle]);
const bke::InstanceReference &src_reference = src_references[src_handle];
handle_map[src_handle] = new_handle_by_src_reference.lookup_or_add_cb(
src_reference, [&]() { return dst_instances->add_new_reference(src_reference); });
}
const IndexRange dst_range = offsets[i];
@@ -174,10 +178,14 @@ static void join_component_type(const bke::GeometryComponent::Type component_typ
instances->resize(components.size());
instances->transforms_for_write().fill(float4x4::identity());
MutableSpan<int> handles = instances->reference_handles_for_write();
Map<const GeometryComponent *, int> handle_by_component;
for (const int i : components.index_range()) {
GeometrySet tmp_geo;
tmp_geo.add(*components[i]);
handles[i] = instances->add_reference(bke::InstanceReference{tmp_geo});
const GeometryComponent *component = components[i];
handles[i] = handle_by_component.lookup_or_add_cb(component, [&]() {
GeometrySet tmp_geo;
tmp_geo.add(*components[i]);
return instances->add_new_reference(bke::InstanceReference{tmp_geo});
});
}
RealizeInstancesOptions options;