Blender V5.0
node_geo_collection_info.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_listbase.h"
6#include "BLI_string.h"
7
9
10#include "NOD_rna_define.hh"
11
13#include "UI_resources.hh"
14
15#include "BKE_collection.hh"
16#include "BKE_instances.hh"
17
19
20#include "node_geometry_util.hh"
21
22#include <algorithm>
23
25
27
29{
30 b.add_input<decl::Collection>("Collection").optional_label();
31 b.add_input<decl::Bool>("Separate Children")
33 "Output each child of the collection as a separate instance, sorted alphabetically");
34 b.add_input<decl::Bool>("Reset Children")
36 "Reset the transforms of every child instance in the output. Only used when Separate "
37 "Children is enabled");
38 b.add_output<decl::Geometry>("Instances")
40 "Instance of the collection or instances of all the children in the collection");
41}
42
43static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
44{
45 layout->prop(ptr, "transform_space", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
46}
47
48static void node_node_init(bNodeTree * /*tree*/, bNode *node)
49{
51 data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
52 node->storage = data;
53}
54
60
62{
63 Collection *collection = params.extract_input<Collection *>("Collection");
64
65 if (collection == nullptr) {
66 params.set_default_remaining_outputs();
67 return;
68 }
69 const Object *self_object = params.self_object();
70 /* Compare by `orig_id` because objects may be copied into separate depsgraphs. */
72 collection, const_cast<Object *>(self_object));
73 if (is_recursive) {
74 params.error_message_add(NodeWarningType::Error, TIP_("Collection contains current object"));
75 params.set_default_remaining_outputs();
76 return;
77 }
78 if (!DEG_collection_geometry_is_evaluated(*collection)) {
79 params.error_message_add(NodeWarningType::Error,
80 TIP_("Cannot access collections geometry because it's not evaluated "
81 "yet. This can happen when there is a dependency cycle"));
82 params.set_default_remaining_outputs();
83 return;
84 }
85
86 const NodeGeometryCollectionInfo &storage = node_storage(params.node());
87 const bool use_relative_transform = (storage.transform_space ==
89
90 std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
91
92 const bool separate_children = params.extract_input<bool>("Separate Children");
93 if (separate_children) {
94 const bool reset_children = params.extract_input<bool>("Reset Children");
95 Vector<Collection *> children_collections;
96 LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) {
97 children_collections.append(collection_child->collection);
98 }
99 Vector<Object *> children_objects;
100 LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
101 children_objects.append(collection_object->ob);
102 }
103
105 entries.reserve(children_collections.size() + children_objects.size());
106
107 for (Collection *child_collection : children_collections) {
109 if (!reset_children) {
110 transform.location() += float3(child_collection->instance_offset);
111 if (use_relative_transform) {
112 transform = self_object->world_to_object() * transform;
113 }
114 else {
115 transform.location() -= float3(collection->instance_offset);
116 }
117 }
118 const int handle = instances->add_reference(*child_collection);
119 entries.append({handle, &(child_collection->id.name[2]), transform});
120 }
121 for (Object *child_object : children_objects) {
122 const int handle = instances->add_reference(*child_object);
124 if (!reset_children) {
125 if (use_relative_transform) {
126 transform = self_object->world_to_object();
127 }
128 else {
129 transform.location() -= float3(collection->instance_offset);
130 }
131 transform *= child_object->object_to_world();
132 }
133 entries.append({handle, &(child_object->id.name[2]), transform});
134 }
135
136 std::sort(entries.begin(),
137 entries.end(),
138 [](const InstanceListEntry &a, const InstanceListEntry &b) {
139 return BLI_strcasecmp_natural(a.name, b.name) < 0;
140 });
141 for (const InstanceListEntry &entry : entries) {
142 instances->add_instance(entry.handle, entry.transform);
143 }
144 }
145 else {
147 if (use_relative_transform) {
148 transform.location() = collection->instance_offset;
149 transform = self_object->world_to_object() * transform;
150 }
151
152 const int handle = instances->add_reference(*collection);
153 instances->add_instance(handle, transform);
154 }
155 GeometrySet geometry = GeometrySet::from_instances(instances.release());
156 geometry.name = collection->id.name + 2;
157
158 params.set_output("Instances", std::move(geometry));
159}
160
161static void node_rna(StructRNA *srna)
162{
163 static const EnumPropertyItem rna_node_geometry_collection_info_transform_space_items[] = {
165 "ORIGINAL",
166 0,
167 "Original",
168 "Output the geometry relative to the collection offset"},
170 "RELATIVE",
171 0,
172 "Relative",
173 "Bring the input collection geometry into the modified object, maintaining the relative "
174 "position between the objects in the scene"},
175 {0, nullptr, 0, nullptr, nullptr},
176 };
177
179 srna,
180 "transform_space",
181 "Transform Space",
182 "The transformation of the instances output. Does not affect the internal geometry",
183 rna_node_geometry_collection_info_transform_space_items,
184 NOD_storage_enum_accessors(transform_space),
187}
188
189static void node_register()
190{
191 static blender::bke::bNodeType ntype;
192
193 geo_node_type_base(&ntype, "GeometryNodeCollectionInfo", GEO_NODE_COLLECTION_INFO);
194 ntype.ui_name = "Collection Info";
195 ntype.ui_description = "Retrieve geometry instances from a collection";
196 ntype.enum_name_legacy = "COLLECTION_INFO";
197 ntype.nclass = NODE_CLASS_INPUT;
198 ntype.declare = node_declare;
199 ntype.initfunc = node_node_init;
201 ntype, "NodeGeometryCollectionInfo", node_free_standard_storage, node_copy_standard_storage);
205
206 node_rna(ntype.rna_ext.srna);
207}
209
210} // namespace blender::nodes::node_geo_collection_info_cc
bool BKE_collection_has_object_recursive_instanced_orig_id(Collection *collection_eval, Object *object_eval)
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define NODE_CLASS_INPUT
Definition BKE_node.hh:447
#define GEO_NODE_COLLECTION_INFO
#define LISTBASE_FOREACH(type, var, list)
#define TIP_(msgid)
bool DEG_collection_geometry_is_evaluated(const Collection &collection)
Object groups, one object can be in many groups at once.
@ GEO_NODE_TRANSFORM_SPACE_RELATIVE
@ GEO_NODE_TRANSFORM_SPACE_ORIGINAL
#define NOD_REGISTER_NODE(REGISTER_FUNC)
void rna_Node_update_relations(Main *bmain, Scene *scne, PointerRNA *ptr)
#define NOD_storage_enum_accessors(member)
@ UI_ITEM_R_EXPAND
BMesh const char void * data
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
int64_t size() const
void append(const T &value)
void reserve(const int64_t min_capacity)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5414
static void node_declare(NodeDeclarationBuilder &b)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_node_init(bNodeTree *, bNode *node)
static void node_geo_exec(GeoNodeExecParams params)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
void RNA_def_property_update_runtime(PropertyRNA *prop, RNAPropertyUpdateFunc func)
StructRNA * srna
char name[258]
Definition DNA_ID.h:432
void * storage
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeDeclareFunction declare
Definition BKE_node.hh:362
static GeometrySet from_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
PointerRNA * ptr
Definition wm_files.cc:4238