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:
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user