Blender V4.3
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_string.h"
6
8
9#include "NOD_rna_define.hh"
10
11#include "UI_interface.hh"
12#include "UI_resources.hh"
13
14#include "BKE_collection.hh"
15#include "BKE_instances.hh"
16
18
19#include "node_geometry_util.hh"
20
21#include <algorithm>
22
24
26
28{
29 b.add_input<decl::Collection>("Collection").hide_label();
30 b.add_input<decl::Bool>("Separate Children")
31 .description(
32 "Output each child of the collection as a separate instance, sorted alphabetically");
33 b.add_input<decl::Bool>("Reset Children")
34 .description(
35 "Reset the transforms of every child instance in the output. Only used when Separate "
36 "Children is enabled");
37 b.add_output<decl::Geometry>("Instances");
38}
39
40static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
41{
42 uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
43}
44
45static void node_node_init(bNodeTree * /*tree*/, bNode *node)
46{
47 NodeGeometryCollectionInfo *data = MEM_cnew<NodeGeometryCollectionInfo>(__func__);
48 data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
49 node->storage = data;
50}
51
57
59{
60 Collection *collection = params.get_input<Collection *>("Collection");
61
62 if (collection == nullptr) {
63 params.set_default_remaining_outputs();
64 return;
65 }
66 const Object *self_object = params.self_object();
67 /* Compare by `orig_id` because objects may be copied into separate depsgraphs. */
69 collection, const_cast<Object *>(self_object));
70 if (is_recursive) {
71 params.error_message_add(NodeWarningType::Error, TIP_("Collection contains current object"));
72 params.set_default_remaining_outputs();
73 return;
74 }
75 if (!DEG_collection_geometry_is_evaluated(*collection)) {
76 params.error_message_add(NodeWarningType::Error,
77 TIP_("Can't access collections geometry because it's not evaluated "
78 "yet. This can happen when there is a dependency cycle"));
79 params.set_default_remaining_outputs();
80 return;
81 }
82
83 const NodeGeometryCollectionInfo &storage = node_storage(params.node());
84 const bool use_relative_transform = (storage.transform_space ==
86
87 std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
88
89 const bool separate_children = params.get_input<bool>("Separate Children");
90 if (separate_children) {
91 const bool reset_children = params.get_input<bool>("Reset Children");
92 Vector<Collection *> children_collections;
93 LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) {
94 children_collections.append(collection_child->collection);
95 }
96 Vector<Object *> children_objects;
97 LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
98 children_objects.append(collection_object->ob);
99 }
100
102 entries.reserve(children_collections.size() + children_objects.size());
103
104 for (Collection *child_collection : children_collections) {
105 float4x4 transform = float4x4::identity();
106 if (!reset_children) {
107 transform.location() += float3(child_collection->instance_offset);
108 if (use_relative_transform) {
109 transform = self_object->world_to_object() * transform;
110 }
111 else {
112 transform.location() -= float3(collection->instance_offset);
113 }
114 }
115 const int handle = instances->add_reference(*child_collection);
116 entries.append({handle, &(child_collection->id.name[2]), transform});
117 }
118 for (Object *child_object : children_objects) {
119 const int handle = instances->add_reference(*child_object);
120 float4x4 transform = float4x4::identity();
121 if (!reset_children) {
122 if (use_relative_transform) {
123 transform = self_object->world_to_object();
124 }
125 else {
126 transform.location() -= float3(collection->instance_offset);
127 }
128 transform *= child_object->object_to_world();
129 }
130 entries.append({handle, &(child_object->id.name[2]), transform});
131 }
132
133 std::sort(entries.begin(),
134 entries.end(),
135 [](const InstanceListEntry &a, const InstanceListEntry &b) {
136 return BLI_strcasecmp_natural(a.name, b.name) < 0;
137 });
138 for (const InstanceListEntry &entry : entries) {
139 instances->add_instance(entry.handle, entry.transform);
140 }
141 }
142 else {
143 float4x4 transform = float4x4::identity();
144 if (use_relative_transform) {
145 transform.location() = collection->instance_offset;
146 transform = self_object->world_to_object() * transform;
147 }
148
149 const int handle = instances->add_reference(*collection);
150 instances->add_instance(handle, transform);
151 }
152 GeometrySet geometry = GeometrySet::from_instances(instances.release());
153 geometry.name = collection->id.name + 2;
154
155 params.set_output("Instances", std::move(geometry));
156}
157
158static void node_rna(StructRNA *srna)
159{
160 static const EnumPropertyItem rna_node_geometry_collection_info_transform_space_items[] = {
162 "ORIGINAL",
163 0,
164 "Original",
165 "Output the geometry relative to the collection offset"},
167 "RELATIVE",
168 0,
169 "Relative",
170 "Bring the input collection geometry into the modified object, maintaining the relative "
171 "position between the objects in the scene"},
172 {0, nullptr, 0, nullptr, nullptr},
173 };
174
176 srna,
177 "transform_space",
178 "Transform Space",
179 "The transformation of the instances output. Does not affect the internal geometry",
180 rna_node_geometry_collection_info_transform_space_items,
181 NOD_storage_enum_accessors(transform_space),
184}
185
186static void node_register()
187{
188 static blender::bke::bNodeType ntype;
189
190 geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT);
191 ntype.declare = node_declare;
192 ntype.initfunc = node_node_init;
194 "NodeGeometryCollectionInfo",
200
201 node_rna(ntype.rna_ext.srna);
202}
204
205} // 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:1799
#define NODE_CLASS_INPUT
Definition BKE_node.hh:404
#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)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_EXPAND
int64_t size() const
void append(const T &value)
void reserve(const int64_t min_capacity)
local_group_size(16, 16) .push_constant(Type b
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
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)
void transform(Context &context, Result &input, Result &output, const float3x3 &transformation, RealizationOptions realization_options)
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:46
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:58
void RNA_def_property_update_runtime(PropertyRNA *prop, RNAPropertyUpdateFunc func)
StructRNA * srna
Definition RNA_types.hh:780
static GeometrySet from_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Defines a node type.
Definition BKE_node.hh:218
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:339
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:347
PointerRNA * ptr
Definition wm_files.cc:4126