Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2021-05-08 22:53:32 +0300
committerHans Goudey <h.goudey@me.com>2021-05-08 22:53:32 +0300
commit9569a522f28a30d1b95cbee7b05cb3b2a397a268 (patch)
tree633754ba177e2a2dc0c2e06656e2dac5ad061947 /source
parent34439f05ab68e0f6287c96d7391f38dca8e64205 (diff)
Geometry Nodes: Refactor point instance node
This patch refactors the instance component to make use of the earlier refactoring in rB4599cea15dcf. Now we don't have to build an array of instance references the size of the point domain, and we can gather the possible instances only once and use the same vector for all component types. Generally the node should be a bit faster and use less memory. The logic is moved around a bit, especially the hashing of the ID attribute to pick from the instance list, but the result is unchanged. Differential Revision: https://developer.blender.org/D11203
Diffstat (limited to 'source')
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_instance.cc145
1 files changed, 85 insertions, 60 deletions
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
index d42b61df5a8..98f36deb050 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
@@ -63,94 +63,93 @@ static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node)
seed_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && !use_whole_collection);
}
-static void get_instance_references__object(const GeoNodeExecParams &params,
- MutableSpan<InstanceReference> r_references)
+static Vector<InstanceReference> get_instance_references__object(GeoNodeExecParams &params)
{
- Object *object = params.get_input<Object *>("Object");
+ Object *object = params.extract_input<Object *>("Object");
if (object == params.self_object()) {
- object = nullptr;
+ return {};
}
if (object != nullptr) {
- r_references.fill(*object);
+ return {*object};
}
+ return {};
}
-static void get_instance_references__collection(const GeoNodeExecParams &params,
- const GeometryComponent &component,
- MutableSpan<InstanceReference> r_references)
+static Vector<InstanceReference> get_instance_references__collection(GeoNodeExecParams &params)
{
const bNode &node = params.node();
NodeGeometryPointInstance *node_storage = (NodeGeometryPointInstance *)node.storage;
Collection *collection = params.get_input<Collection *>("Collection");
if (collection == nullptr) {
- return;
+ return {};
}
if (BLI_listbase_is_empty(&collection->children) &&
BLI_listbase_is_empty(&collection->gobject)) {
params.error_message_add(NodeWarningType::Info, TIP_("Collection is empty"));
- return;
+ return {};
}
- const bool use_whole_collection = (node_storage->flag &
- GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION) != 0;
- if (use_whole_collection) {
- r_references.fill(*collection);
+ if (node_storage->flag & GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION) {
+ return {*collection};
}
- else {
- Vector<InstanceReference> possible_references;
- /* Direct child objects are instanced as objects. */
- LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
- possible_references.append(*cob->ob);
- }
- /* Direct child collections are instanced as collections. */
- LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- possible_references.append(*child->collection);
- }
- if (!possible_references.is_empty()) {
- const int seed = params.get_input<int>("Seed");
- Array<uint32_t> ids = get_geometry_element_ids_as_uints(component, ATTR_DOMAIN_POINT);
- for (const int i : r_references.index_range()) {
- const int index = BLI_hash_int_2d(ids[i], seed) % possible_references.size();
- r_references[i] = possible_references[index];
- }
- }
+ Vector<InstanceReference> references;
+ /* Direct child objects are instanced as objects. */
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+ references.append(*cob->ob);
+ }
+ /* Direct child collections are instanced as collections. */
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
+ references.append(*child->collection);
}
+
+ return references;
}
-static Array<InstanceReference> get_instance_references(const GeoNodeExecParams &params,
- const GeometryComponent &component,
- const int amount)
+static Vector<InstanceReference> get_instance_references(GeoNodeExecParams &params)
{
const bNode &node = params.node();
NodeGeometryPointInstance *node_storage = (NodeGeometryPointInstance *)node.storage;
const GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)
node_storage->instance_type;
- Array<InstanceReference> references(amount);
switch (type) {
case GEO_NODE_POINT_INSTANCE_TYPE_OBJECT: {
- get_instance_references__object(params, references);
- break;
+ return get_instance_references__object(params);
}
case GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION: {
- get_instance_references__collection(params, component, references);
- break;
+ return get_instance_references__collection(params);
}
}
- return references;
+ return {};
}
-static void add_instances_from_geometry_component(InstancesComponent &instances,
- const GeometryComponent &src_geometry,
- const GeoNodeExecParams &params)
+/**
+ * Add the instance references to the component as a separate step from actually creating the
+ * instances in order to avoid a map lookup for every transform. While this might add some
+ * unecessary references if they are not chosen while adding transforms, in the common cases
+ * there are many more transforms than there are references, so that isn't likely.
+ */
+static Array<int> add_instance_references(InstancesComponent &instance_component,
+ Span<InstanceReference> possible_references)
+{
+ Array<int> possible_handles(possible_references.size());
+ for (const int i : possible_references.index_range()) {
+ possible_handles[i] = instance_component.add_reference(possible_references[i]);
+ }
+ return possible_handles;
+}
+
+static void add_instances_from_component(InstancesComponent &instances,
+ const GeometryComponent &src_geometry,
+ Span<int> possible_handles,
+ const GeoNodeExecParams &params)
{
const AttributeDomain domain = ATTR_DOMAIN_POINT;
const int domain_size = src_geometry.attribute_domain_size(domain);
- Array<InstanceReference> references = get_instance_references(params, src_geometry, domain_size);
GVArray_Typed<float3> positions = src_geometry.attribute_get_for_read<float3>(
"position", domain, {0, 0, 0});
@@ -158,14 +157,27 @@ static void add_instances_from_geometry_component(InstancesComponent &instances,
"rotation", domain, {0, 0, 0});
GVArray_Typed<float3> scales = src_geometry.attribute_get_for_read<float3>(
"scale", domain, {1, 1, 1});
- GVArray_Typed<int> ids = src_geometry.attribute_get_for_read<int>("id", domain, -1);
-
- for (const int i : IndexRange(domain_size)) {
- const InstanceReference &reference = references[i];
- if (reference.type() != InstanceReference::Type::None) {
- const float4x4 matrix = float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]);
- const int handle = instances.add_reference(reference);
- instances.add_instance(handle, matrix, ids[i]);
+ GVArray_Typed<int> id_attribute = src_geometry.attribute_get_for_read<int>("id", domain, -1);
+
+ /* Skip all of the randomness handling if there is only a single possible instance
+ * (anything except for collection mode with "Whole Collection" turned off). */
+ if (possible_handles.size() == 1) {
+ const int handle = possible_handles.first();
+ for (const int i : IndexRange(domain_size)) {
+ instances.add_instance(handle,
+ float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]),
+ id_attribute[i]);
+ }
+ }
+ else {
+ const int seed = params.get_input<int>("Seed");
+ Array<uint32_t> ids = get_geometry_element_ids_as_uints(src_geometry, ATTR_DOMAIN_POINT);
+ for (const int i : IndexRange(domain_size)) {
+ const int index = BLI_hash_int_2d(ids[i], seed) % possible_handles.size();
+ const int handle = possible_handles[index];
+ instances.add_instance(handle,
+ float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]),
+ id_attribute[i]);
}
}
}
@@ -179,19 +191,32 @@ static void geo_node_point_instance_exec(GeoNodeExecParams params)
* rather than making the entire input geometry set real. */
geometry_set = geometry_set_realize_instances(geometry_set);
+ const Vector<InstanceReference> possible_references = get_instance_references(params);
+ if (possible_references.is_empty()) {
+ params.set_output("Geometry", std::move(geometry_set_out));
+ return;
+ }
+
InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
+ Array<int> possible_handles = add_instance_references(instances, possible_references);
+
if (geometry_set.has<MeshComponent>()) {
- add_instances_from_geometry_component(
- instances, *geometry_set.get_component_for_read<MeshComponent>(), params);
+ add_instances_from_component(instances,
+ *geometry_set.get_component_for_read<MeshComponent>(),
+ possible_handles,
+ params);
}
if (geometry_set.has<PointCloudComponent>()) {
- add_instances_from_geometry_component(
- instances, *geometry_set.get_component_for_read<PointCloudComponent>(), params);
+ add_instances_from_component(instances,
+ *geometry_set.get_component_for_read<PointCloudComponent>(),
+ possible_handles,
+ params);
}
-
if (geometry_set.has<CurveComponent>()) {
- add_instances_from_geometry_component(
- instances, *geometry_set.get_component_for_read<CurveComponent>(), params);
+ add_instances_from_component(instances,
+ *geometry_set.get_component_for_read<CurveComponent>(),
+ possible_handles,
+ params);
}
params.set_output("Geometry", std::move(geometry_set_out));