Blender  V2.93
node_geo_join_geometry.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include "BKE_mesh.h"
18 #include "BKE_mesh_runtime.h"
19 #include "BKE_pointcloud.h"
20 
21 #include "DNA_mesh_types.h"
22 #include "DNA_meshdata_types.h"
23 
24 #include "node_geometry_util.hh"
25 
28  N_("Geometry"),
29  0.0f,
30  0.0f,
31  0.0f,
32  1.0f,
33  -1.0f,
34  1.0f,
35  PROP_NONE,
37  {-1, ""},
38 };
39 
41  {SOCK_GEOMETRY, N_("Geometry")},
42  {-1, ""},
43 };
44 
45 namespace blender::nodes {
46 
48 {
49  int totverts = 0;
50  int totloops = 0;
51  int totedges = 0;
52  int totpolys = 0;
53 
54  int64_t cd_dirty_vert = 0;
55  int64_t cd_dirty_poly = 0;
56  int64_t cd_dirty_edge = 0;
57  int64_t cd_dirty_loop = 0;
58 
59  for (const MeshComponent *mesh_component : src_components) {
60  const Mesh *mesh = mesh_component->get_for_read();
61  totverts += mesh->totvert;
62  totloops += mesh->totloop;
63  totedges += mesh->totedge;
64  totpolys += mesh->totpoly;
65  cd_dirty_vert |= mesh->runtime.cd_dirty_vert;
66  cd_dirty_poly |= mesh->runtime.cd_dirty_poly;
67  cd_dirty_edge |= mesh->runtime.cd_dirty_edge;
68  cd_dirty_loop |= mesh->runtime.cd_dirty_loop;
69  }
70 
71  const Mesh *first_input_mesh = src_components[0]->get_for_read();
72  Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
73  BKE_mesh_copy_settings(new_mesh, first_input_mesh);
74 
75  new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
76  new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
77  new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
78  new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
79 
80  int vert_offset = 0;
81  int loop_offset = 0;
82  int edge_offset = 0;
83  int poly_offset = 0;
84  for (const MeshComponent *mesh_component : src_components) {
85  const Mesh *mesh = mesh_component->get_for_read();
86  if (mesh == nullptr) {
87  continue;
88  }
89 
90  for (const int i : IndexRange(mesh->totvert)) {
91  const MVert &old_vert = mesh->mvert[i];
92  MVert &new_vert = new_mesh->mvert[vert_offset + i];
93  new_vert = old_vert;
94  }
95 
96  for (const int i : IndexRange(mesh->totedge)) {
97  const MEdge &old_edge = mesh->medge[i];
98  MEdge &new_edge = new_mesh->medge[edge_offset + i];
99  new_edge = old_edge;
100  new_edge.v1 += vert_offset;
101  new_edge.v2 += vert_offset;
102  }
103  for (const int i : IndexRange(mesh->totloop)) {
104  const MLoop &old_loop = mesh->mloop[i];
105  MLoop &new_loop = new_mesh->mloop[loop_offset + i];
106  new_loop = old_loop;
107  new_loop.v += vert_offset;
108  new_loop.e += edge_offset;
109  }
110  for (const int i : IndexRange(mesh->totpoly)) {
111  const MPoly &old_poly = mesh->mpoly[i];
112  MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
113  new_poly = old_poly;
114  new_poly.loopstart += loop_offset;
115  }
116 
117  vert_offset += mesh->totvert;
118  loop_offset += mesh->totloop;
119  edge_offset += mesh->totedge;
120  poly_offset += mesh->totpoly;
121  }
122 
123  return new_mesh;
124 }
125 
126 template<typename Component>
128 {
129  return components;
130 }
131 
133 {
134  Set<std::string> attribute_names;
135  for (const GeometryComponent *component : components) {
136  Set<std::string> names = component->attribute_names();
137  for (const std::string &name : names) {
138  attribute_names.add(name);
139  }
140  }
141  return attribute_names;
142 }
143 
145  StringRef attribute_name,
146  CustomDataType *r_type,
147  AttributeDomain *r_domain)
148 {
149  Vector<CustomDataType> data_types;
150  Vector<AttributeDomain> domains;
151  for (const GeometryComponent *component : components) {
152  ReadAttributePtr attribute = component->attribute_try_get_for_read(attribute_name);
153  if (attribute) {
154  data_types.append(attribute->custom_data_type());
155  domains.append(attribute->domain());
156  }
157  }
158 
159  *r_type = bke::attribute_data_type_highest_complexity(data_types);
160  *r_domain = bke::attribute_domain_highest_priority(domains);
161 }
162 
164  StringRef attribute_name,
165  const CustomDataType data_type,
166  const AttributeDomain domain,
167  fn::GMutableSpan dst_span)
168 {
169  const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type);
170  BLI_assert(cpp_type != nullptr);
171 
172  int offset = 0;
173  for (const GeometryComponent *component : src_components) {
174  const int domain_size = component->attribute_domain_size(domain);
175  if (domain_size == 0) {
176  continue;
177  }
178  ReadAttributePtr read_attribute = component->attribute_get_for_read(
179  attribute_name, domain, data_type, nullptr);
180 
181  fn::GSpan src_span = read_attribute->get_span();
182  const void *src_buffer = src_span.data();
183  void *dst_buffer = dst_span[offset];
184  cpp_type->copy_to_initialized_n(src_buffer, dst_buffer, domain_size);
185 
186  offset += domain_size;
187  }
188 }
189 
192  Span<StringRef> ignored_attributes = {})
193 {
194  Set<std::string> attribute_names = find_all_attribute_names(src_components);
195  for (StringRef name : ignored_attributes) {
196  attribute_names.remove(name);
197  }
198 
199  for (const std::string &attribute_name : attribute_names) {
200  CustomDataType data_type;
201  AttributeDomain domain;
202  determine_final_data_type_and_domain(src_components, attribute_name, &data_type, &domain);
203 
204  OutputAttributePtr write_attribute = result.attribute_try_get_for_output(
205  attribute_name, domain, data_type);
206  if (!write_attribute ||
207  &write_attribute->cpp_type() != bke::custom_data_type_to_cpp_type(data_type) ||
208  write_attribute->domain() != domain) {
209  continue;
210  }
211  fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only();
212  fill_new_attribute(src_components, attribute_name, data_type, domain, dst_span);
213  write_attribute.apply_span_and_save();
214  }
215 }
216 
218 {
219  Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(src_components);
220 
221  MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
222  dst_component.replace(new_mesh);
223 
224  /* Don't copy attributes that are stored directly in the mesh data structs. */
225  join_attributes(to_base_components(src_components),
226  dst_component,
227  {"position", "material_index", "normal", "shade_smooth", "crease"});
228 }
229 
231 {
232  int totpoints = 0;
233  for (const PointCloudComponent *pointcloud_component : src_components) {
234  totpoints += pointcloud_component->attribute_domain_size(ATTR_DOMAIN_POINT);
235  }
236 
237  PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
238  PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoints);
239  dst_component.replace(pointcloud);
240 
241  join_attributes(to_base_components(src_components), dst_component);
242 }
243 
245 {
246  InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>();
247  for (const InstancesComponent *component : src_components) {
248  const int size = component->instances_amount();
249  Span<InstancedData> instanced_data = component->instanced_data();
250  Span<float4x4> transforms = component->transforms();
251  Span<int> ids = component->ids();
252  for (const int i : IndexRange(size)) {
253  dst_component.add_instance(instanced_data[i], transforms[i], ids[i]);
254  }
255  }
256 }
257 
259 {
260  /* Not yet supported. Joining volume grids with the same name requires resampling of at least one
261  * of the grids. The cell size of the resulting volume has to be determined somehow. */
262  VolumeComponent &dst_component = result.get_component_for_write<VolumeComponent>();
263  UNUSED_VARS(src_components, dst_component);
264 }
265 
266 template<typename Component>
267 static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet &result)
268 {
269  Vector<const Component *> components;
270  for (const GeometrySet &geometry_set : src_geometry_sets) {
271  const Component *component = geometry_set.get_component_for_read<Component>();
272  if (component != nullptr && !component->is_empty()) {
273  components.append(component);
274  }
275  }
276 
277  if (components.size() == 0) {
278  return;
279  }
280  if (components.size() == 1) {
281  result.add(*components[0]);
282  return;
283  }
284  join_components(components, result);
285 }
286 
288 {
289  Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Geometry");
290 
291  GeometrySet geometry_set_result;
292  join_component_type<MeshComponent>(geometry_sets, geometry_set_result);
293  join_component_type<PointCloudComponent>(geometry_sets, geometry_set_result);
294  join_component_type<InstancesComponent>(geometry_sets, geometry_set_result);
295  join_component_type<VolumeComponent>(geometry_sets, geometry_set_result);
296 
297  params.set_output("Geometry", std::move(geometry_set_result));
298 }
299 } // namespace blender::nodes
300 
302 {
303  static bNodeType ntype;
304 
305  geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY, 0);
308  nodeRegisterType(&ntype);
309 }
AttributeDomain
Definition: BKE_attribute.h:41
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:43
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.c:877
void BKE_mesh_copy_settings(struct Mesh *me_dst, const struct Mesh *me_src)
void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs)
Definition: node.cc:4527
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1298
#define GEO_NODE_JOIN_GEOMETRY
Definition: BKE_node.h:1386
General operations for point-clouds.
struct PointCloud * BKE_pointcloud_new_nomain(const int totpoint)
Definition: pointcloud.cc:240
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define UNUSED_VARS(...)
#define N_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:126
CustomDataType
@ SOCK_MULTI_INPUT
@ SOCK_GEOMETRY
@ PROP_NONE
Definition: RNA_types.h:113
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
void add_instance(Object *object, blender::float4x4 transform, const int id=-1)
void replace(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void replace(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
bool add(const Key &key)
Definition: BLI_set.hh:267
bool remove(const Key &key)
Definition: BLI_set.hh:385
int64_t size() const
Definition: BLI_vector.hh:662
void append(const T &value)
Definition: BLI_vector.hh:438
AttributeDomain domain() const
fn::GMutableSpan get_span_for_write_only()
const CPPType & cpp_type() const
void copy_to_initialized_n(const void *src, void *dst, int64_t n) const
Definition: FN_cpp_type.hh:399
const void * data() const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static char ** names
Definition: makesdna.c:162
AttributeDomain attribute_domain_highest_priority(Span< AttributeDomain > domains)
const CPPType * custom_data_type_to_cpp_type(const CustomDataType type)
std::unique_ptr< ReadAttribute > ReadAttributePtr
CustomDataType attribute_data_type_highest_complexity(Span< CustomDataType > data_types)
static void join_component_type(Span< GeometrySet > src_geometry_sets, GeometrySet &result)
static Set< std::string > find_all_attribute_names(Span< const GeometryComponent * > components)
static void geo_node_join_geometry_exec(GeoNodeExecParams params)
static void fill_new_attribute(Span< const GeometryComponent * > src_components, StringRef attribute_name, const CustomDataType data_type, const AttributeDomain domain, fn::GMutableSpan dst_span)
static void determine_final_data_type_and_domain(Span< const GeometryComponent * > components, StringRef attribute_name, CustomDataType *r_type, AttributeDomain *r_domain)
static Mesh * join_mesh_topology_and_builtin_attributes(Span< const MeshComponent * > src_components)
static Array< const GeometryComponent * > to_base_components(Span< const Component * > components)
static void join_attributes(Span< const GeometryComponent * > src_components, GeometryComponent &result, Span< StringRef > ignored_attributes={})
static void join_components(Span< const MeshComponent * > src_components, GeometrySet &result)
static bNodeSocketTemplate geo_node_join_geometry_out[]
void register_node_type_geo_join_geometry()
static bNodeSocketTemplate geo_node_join_geometry_in[]
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
__int64 int64_t
Definition: stdint.h:92
unsigned int v1
unsigned int v2
unsigned int e
unsigned int v
int64_t cd_dirty_poly
int64_t cd_dirty_edge
int64_t cd_dirty_loop
int64_t cd_dirty_vert
struct MEdge * medge
struct MVert * mvert
int totedge
int totvert
struct MLoop * mloop
Mesh_Runtime runtime
int totpoly
int totloop
struct MPoly * mpoly
Compact definition of a node socket.
Definition: BKE_node.h:95
Defines a node type.
Definition: BKE_node.h:221
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:327