Blender  V2.93
geometry_set_instances.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 
18 #include "BKE_mesh.h"
19 #include "BKE_mesh_wrapper.h"
20 #include "BKE_modifier.h"
21 #include "BKE_pointcloud.h"
22 
23 #include "DNA_collection_types.h"
24 #include "DNA_mesh_types.h"
25 #include "DNA_meshdata_types.h"
26 #include "DNA_object_types.h"
27 #include "DNA_pointcloud_types.h"
28 
29 namespace blender::bke {
30 
31 static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
32  const float4x4 &transform,
33  Vector<GeometryInstanceGroup> &r_sets);
34 
35 static void geometry_set_collect_recursive_collection(const Collection &collection,
36  const float4x4 &transform,
37  Vector<GeometryInstanceGroup> &r_sets);
38 
39 static void add_final_mesh_as_geometry_component(const Object &object, GeometrySet &geometry_set)
40 {
42  false);
43 
44  if (mesh != nullptr) {
46 
47  MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
49  mesh_component.copy_vertex_group_names_from_object(object);
50  }
51 }
52 
57 {
58  if (object.type == OB_MESH && object.mode == OB_MODE_EDIT) {
59  GeometrySet geometry_set;
60  if (object.runtime.geometry_set_eval != nullptr) {
61  /* `geometry_set_eval` only contains non-mesh components, see `editbmesh_build_data`. */
62  geometry_set = *object.runtime.geometry_set_eval;
63  }
64  add_final_mesh_as_geometry_component(object, geometry_set);
65  return geometry_set;
66  }
67  if (object.runtime.geometry_set_eval != nullptr) {
68  return *object.runtime.geometry_set_eval;
69  }
70 
71  /* Otherwise, construct a new geometry set with the component based on the object type. */
72  GeometrySet geometry_set;
73  if (object.type == OB_MESH) {
74  add_final_mesh_as_geometry_component(object, geometry_set);
75  }
76 
77  /* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the
78  * #geometry_set_eval case above. */
79 
80  /* TODO: Add volume support. */
81 
82  /* Return by value since there is not always an existing geometry set owned elsewhere to use. */
83  return geometry_set;
84 }
85 
87  const Collection &collection, const float4x4 &transform, Vector<GeometryInstanceGroup> &r_sets)
88 {
89  float4x4 offset_matrix;
90  unit_m4(offset_matrix.values);
91  sub_v3_v3(offset_matrix.values[3], collection.instance_offset);
92  const float4x4 instance_transform = transform * offset_matrix;
93  geometry_set_collect_recursive_collection(collection, instance_transform, r_sets);
94 }
95 
97  const float4x4 &transform,
99 {
100  GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
101  geometry_set_collect_recursive(instance_geometry_set, transform, r_sets);
102 
103  if (object.type == OB_EMPTY) {
104  const Collection *collection_instance = object.instance_collection;
105  if (collection_instance != nullptr) {
106  geometry_set_collect_recursive_collection_instance(*collection_instance, transform, r_sets);
107  }
108  }
109 }
110 
112  const float4x4 &transform,
114 {
115  LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) {
116  BLI_assert(collection_object->ob != nullptr);
117  const Object &object = *collection_object->ob;
118  const float4x4 object_transform = transform * object.obmat;
119  geometry_set_collect_recursive_object(object, object_transform, r_sets);
120  }
121  LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) {
122  BLI_assert(collection_child->collection != nullptr);
123  const Collection &collection = *collection_child->collection;
125  }
126 }
127 
128 static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
129  const float4x4 &transform,
131 {
132  r_sets.append({geometry_set, {transform}});
133 
134  if (geometry_set.has_instances()) {
135  const InstancesComponent &instances_component =
137 
138  Span<float4x4> transforms = instances_component.transforms();
139  Span<InstancedData> instances = instances_component.instanced_data();
140  for (const int i : instances.index_range()) {
141  const InstancedData &data = instances[i];
142  const float4x4 instance_transform = transform * transforms[i];
143 
144  if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
145  BLI_assert(data.data.object != nullptr);
146  const Object &object = *data.data.object;
147  geometry_set_collect_recursive_object(object, instance_transform, r_sets);
148  }
149  else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
150  BLI_assert(data.data.collection != nullptr);
151  const Collection &collection = *data.data.collection;
152  geometry_set_collect_recursive_collection_instance(collection, instance_transform, r_sets);
153  }
154  }
155  }
156 }
157 
169  Vector<GeometryInstanceGroup> &r_instance_groups)
170 {
171  float4x4 unit_transform;
172  unit_m4(unit_transform.values);
173 
174  geometry_set_collect_recursive(geometry_set, unit_transform, r_instance_groups);
175 }
176 
177 static bool collection_instance_attribute_foreach(const Collection &collection,
179  const int limit,
180  int &count);
181 
182 static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_set,
184  const int limit,
185  int &count);
186 
187 static bool object_instance_attribute_foreach(const Object &object,
189  const int limit,
190  int &count)
191 {
192  GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
193  if (!instances_attribute_foreach_recursive(instance_geometry_set, callback, limit, count)) {
194  return false;
195  }
196 
197  if (object.type == OB_EMPTY) {
198  const Collection *collection_instance = object.instance_collection;
199  if (collection_instance != nullptr) {
200  if (!collection_instance_attribute_foreach(*collection_instance, callback, limit, count)) {
201  return false;
202  }
203  }
204  }
205  return true;
206 }
207 
208 static bool collection_instance_attribute_foreach(const Collection &collection,
210  const int limit,
211  int &count)
212 {
213  LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) {
214  BLI_assert(collection_object->ob != nullptr);
215  const Object &object = *collection_object->ob;
216  if (!object_instance_attribute_foreach(object, callback, limit, count)) {
217  return false;
218  }
219  }
220  LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) {
221  BLI_assert(collection_child->collection != nullptr);
222  const Collection &collection = *collection_child->collection;
223  if (!collection_instance_attribute_foreach(collection, callback, limit, count)) {
224  return false;
225  }
226  }
227  return true;
228 }
229 
234 static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_set,
236  const int limit,
237  int &count)
238 {
239  for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
240  if (!component->attribute_foreach(callback)) {
241  return false;
242  }
243  }
244 
245  /* Now that this this geometry set is visited, increase the count and check with the limit. */
246  if (limit > 0 && count++ > limit) {
247  return false;
248  }
249 
250  const InstancesComponent *instances_component =
252  if (instances_component == nullptr) {
253  return true;
254  }
255 
256  for (const InstancedData &data : instances_component->instanced_data()) {
257  if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
258  BLI_assert(data.data.object != nullptr);
259  const Object &object = *data.data.object;
260  if (!object_instance_attribute_foreach(object, callback, limit, count)) {
261  return false;
262  }
263  }
264  else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
265  BLI_assert(data.data.collection != nullptr);
266  const Collection &collection = *data.data.collection;
267  if (!collection_instance_attribute_foreach(collection, callback, limit, count)) {
268  return false;
269  }
270  }
271  }
272 
273  return true;
274 }
275 
287  const int limit)
288 {
289  int count = 0;
291 }
292 
294  Span<GeometryComponentType> component_types,
295  const Set<std::string> &ignored_attributes,
296  Map<std::string, AttributeKind> &r_attributes)
297 {
298  for (const GeometryInstanceGroup &set_group : set_groups) {
299  const GeometrySet &set = set_group.geometry_set;
300  for (const GeometryComponentType component_type : component_types) {
301  if (!set.has(component_type)) {
302  continue;
303  }
304  const GeometryComponent &component = *set.get_component_for_read(component_type);
305 
306  component.attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
307  if (ignored_attributes.contains(name)) {
308  return true;
309  }
310  auto add_info = [&](AttributeKind *attribute_kind) {
311  attribute_kind->domain = meta_data.domain;
312  attribute_kind->data_type = meta_data.data_type;
313  };
314  auto modify_info = [&](AttributeKind *attribute_kind) {
315  attribute_kind->domain = meta_data.domain; /* TODO: Use highest priority domain. */
316  attribute_kind->data_type = bke::attribute_data_type_highest_complexity(
317  {attribute_kind->data_type, meta_data.data_type});
318  };
319 
320  r_attributes.add_or_modify(name, add_info, modify_info);
321  return true;
322  });
323  }
324  }
325 }
326 
328  const bool convert_points_to_vertices)
329 {
330  int totverts = 0;
331  int totloops = 0;
332  int totedges = 0;
333  int totpolys = 0;
334  int64_t cd_dirty_vert = 0;
335  int64_t cd_dirty_poly = 0;
336  int64_t cd_dirty_edge = 0;
337  int64_t cd_dirty_loop = 0;
338  for (const GeometryInstanceGroup &set_group : set_groups) {
339  const GeometrySet &set = set_group.geometry_set;
340  const int tot_transforms = set_group.transforms.size();
341  if (set.has_mesh()) {
342  const Mesh &mesh = *set.get_mesh_for_read();
343  totverts += mesh.totvert * tot_transforms;
344  totloops += mesh.totloop * tot_transforms;
345  totedges += mesh.totedge * tot_transforms;
346  totpolys += mesh.totpoly * tot_transforms;
347  cd_dirty_vert |= mesh.runtime.cd_dirty_vert;
348  cd_dirty_poly |= mesh.runtime.cd_dirty_poly;
349  cd_dirty_edge |= mesh.runtime.cd_dirty_edge;
350  cd_dirty_loop |= mesh.runtime.cd_dirty_loop;
351  }
352  if (convert_points_to_vertices && set.has_pointcloud()) {
353  const PointCloud &pointcloud = *set.get_pointcloud_for_read();
354  totverts += pointcloud.totpoint * tot_transforms;
355  }
356  }
357 
358  /* Don't create an empty mesh. */
359  if ((totverts + totloops + totedges + totpolys) == 0) {
360  return nullptr;
361  }
362 
363  Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
364  /* Copy settings from the first input geometry set with a mesh. */
365  for (const GeometryInstanceGroup &set_group : set_groups) {
366  const GeometrySet &set = set_group.geometry_set;
367  if (set.has_mesh()) {
368  const Mesh &mesh = *set.get_mesh_for_read();
369  BKE_mesh_copy_settings(new_mesh, &mesh);
370  break;
371  }
372  }
373  new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
374  new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
375  new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
376  new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
377 
378  int vert_offset = 0;
379  int loop_offset = 0;
380  int edge_offset = 0;
381  int poly_offset = 0;
382  for (const GeometryInstanceGroup &set_group : set_groups) {
383  const GeometrySet &set = set_group.geometry_set;
384  if (set.has_mesh()) {
385  const Mesh &mesh = *set.get_mesh_for_read();
386  for (const float4x4 &transform : set_group.transforms) {
387  for (const int i : IndexRange(mesh.totvert)) {
388  const MVert &old_vert = mesh.mvert[i];
389  MVert &new_vert = new_mesh->mvert[vert_offset + i];
390 
391  new_vert = old_vert;
392 
393  const float3 new_position = transform * float3(old_vert.co);
394  copy_v3_v3(new_vert.co, new_position);
395  }
396  for (const int i : IndexRange(mesh.totedge)) {
397  const MEdge &old_edge = mesh.medge[i];
398  MEdge &new_edge = new_mesh->medge[edge_offset + i];
399  new_edge = old_edge;
400  new_edge.v1 += vert_offset;
401  new_edge.v2 += vert_offset;
402  }
403  for (const int i : IndexRange(mesh.totloop)) {
404  const MLoop &old_loop = mesh.mloop[i];
405  MLoop &new_loop = new_mesh->mloop[loop_offset + i];
406  new_loop = old_loop;
407  new_loop.v += vert_offset;
408  new_loop.e += edge_offset;
409  }
410  for (const int i : IndexRange(mesh.totpoly)) {
411  const MPoly &old_poly = mesh.mpoly[i];
412  MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
413  new_poly = old_poly;
414  new_poly.loopstart += loop_offset;
415  }
416 
417  vert_offset += mesh.totvert;
418  loop_offset += mesh.totloop;
419  edge_offset += mesh.totedge;
420  poly_offset += mesh.totpoly;
421  }
422  }
423  if (convert_points_to_vertices && set.has_pointcloud()) {
424  const PointCloud &pointcloud = *set.get_pointcloud_for_read();
425  for (const float4x4 &transform : set_group.transforms) {
426  for (const int i : IndexRange(pointcloud.totpoint)) {
427  MVert &new_vert = new_mesh->mvert[vert_offset + i];
428  const float3 old_position = pointcloud.co[i];
429  const float3 new_position = transform * old_position;
430  copy_v3_v3(new_vert.co, new_position);
431  }
432  vert_offset += pointcloud.totpoint;
433  }
434  }
435  }
436 
437  return new_mesh;
438 }
439 
441  Span<GeometryComponentType> component_types,
442  const Map<std::string, AttributeKind> &attribute_info,
444 {
445  for (Map<std::string, AttributeKind>::Item entry : attribute_info.items()) {
446  StringRef name = entry.key;
447  const AttributeDomain domain_output = entry.value.domain;
448  const CustomDataType data_type_output = entry.value.data_type;
449  const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type_output);
450  BLI_assert(cpp_type != nullptr);
451 
452  result.attribute_try_create(entry.key, domain_output, data_type_output);
453  WriteAttributePtr write_attribute = result.attribute_try_get_for_write(name);
454  if (!write_attribute || &write_attribute->cpp_type() != cpp_type ||
455  write_attribute->domain() != domain_output) {
456  continue;
457  }
458  fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only();
459 
460  int offset = 0;
461  for (const GeometryInstanceGroup &set_group : set_groups) {
462  const GeometrySet &set = set_group.geometry_set;
463  for (const GeometryComponentType component_type : component_types) {
464  if (set.has(component_type)) {
465  const GeometryComponent &component = *set.get_component_for_read(component_type);
466  const int domain_size = component.attribute_domain_size(domain_output);
467  if (domain_size == 0) {
468  continue; /* Domain size is 0, so no need to increment the offset. */
469  }
470  ReadAttributePtr source_attribute = component.attribute_try_get_for_read(
471  name, domain_output, data_type_output);
472 
473  if (source_attribute) {
474  fn::GSpan src_span = source_attribute->get_span();
475  const void *src_buffer = src_span.data();
476  for (const int UNUSED(i) : set_group.transforms.index_range()) {
477  void *dst_buffer = dst_span[offset];
478  cpp_type->copy_to_initialized_n(src_buffer, dst_buffer, domain_size);
479  offset += domain_size;
480  }
481  }
482  else {
483  offset += domain_size * set_group.transforms.size();
484  }
485  }
486  }
487  }
488 
489  write_attribute->apply_span();
490  }
491 }
492 
494  bool convert_points_to_vertices,
496 {
497  Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(set_groups,
498  convert_points_to_vertices);
499  if (new_mesh == nullptr) {
500  return;
501  }
502 
503  MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
504  dst_component.replace(new_mesh);
505 
506  Vector<GeometryComponentType> component_types;
507  component_types.append(GEO_COMPONENT_TYPE_MESH);
508  if (convert_points_to_vertices) {
509  component_types.append(GEO_COMPONENT_TYPE_POINT_CLOUD);
510  }
511 
512  /* Don't copy attributes that are stored directly in the mesh data structs. */
515  set_groups,
516  component_types,
517  {"position", "material_index", "normal", "shade_smooth", "crease"},
518  attributes);
520  set_groups, component_types, attributes, static_cast<GeometryComponent &>(dst_component));
521 }
522 
525 {
526  int totpoint = 0;
527  for (const GeometryInstanceGroup &set_group : set_groups) {
528  const GeometrySet &set = set_group.geometry_set;
529  if (set.has<PointCloudComponent>()) {
531  totpoint += component.attribute_domain_size(ATTR_DOMAIN_POINT);
532  }
533  }
534  if (totpoint == 0) {
535  return;
536  }
537 
538  PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
539  PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoint);
540  dst_component.replace(pointcloud);
543  set_groups, {GEO_COMPONENT_TYPE_POINT_CLOUD}, {}, attributes);
544  join_attributes(set_groups,
546  attributes,
547  static_cast<GeometryComponent &>(dst_component));
548 }
549 
552 {
553  /* Not yet supported. Joining volume grids with the same name requires resampling of at least
554  * one of the grids. The cell size of the resulting volume has to be determined somehow. */
555  VolumeComponent &dst_component = result.get_component_for_write<VolumeComponent>();
556  UNUSED_VARS(set_groups, dst_component);
557 }
558 
560 {
561  if (!geometry_set.has_instances() && !geometry_set.has_pointcloud()) {
562  return geometry_set;
563  }
564 
565  GeometrySet new_geometry_set = geometry_set;
567  geometry_set_gather_instances(geometry_set, set_groups);
568  join_instance_groups_mesh(set_groups, true, new_geometry_set);
569  /* Remove all instances, even though some might contain other non-mesh data. We can't really
570  * keep only non-mesh instances in general. */
571  new_geometry_set.remove<InstancesComponent>();
572  /* If there was a point cloud, it is now part of the mesh. */
573  new_geometry_set.remove<PointCloudComponent>();
574  return new_geometry_set;
575 }
576 
578 {
579  if (!geometry_set.has_instances()) {
580  return geometry_set;
581  }
582 
583  GeometrySet new_geometry_set;
584 
586  geometry_set_gather_instances(geometry_set, set_groups);
587  join_instance_groups_mesh(set_groups, false, new_geometry_set);
588  join_instance_groups_pointcloud(set_groups, new_geometry_set);
589  join_instance_groups_volume(set_groups, new_geometry_set);
590 
591  return new_geometry_set;
592 }
593 
594 } // namespace blender::bke
AttributeDomain
Definition: BKE_attribute.h:41
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:43
GeometryComponentType
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
@ INSTANCE_DATA_TYPE_OBJECT
@ INSTANCE_DATA_TYPE_COLLECTION
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 BKE_mesh_wrapper_ensure_mdata(struct Mesh *me)
Definition: mesh_wrapper.c:98
struct Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval, const bool get_cage_mesh)
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 LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void unit_m4(float m[4][4])
Definition: rct.c:1140
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNUSED_VARS(...)
#define UNUSED(x)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:126
Object groups, one object can be in many groups at once.
CustomDataType
@ OB_MODE_EDIT
Object is a sort of wrapper for general info.
@ OB_EMPTY
@ OB_MESH
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
blender::Span< blender::float4x4 > transforms() const
blender::Span< InstancedData > instanced_data() const
void replace(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void copy_vertex_group_names_from_object(const struct Object &object)
void replace(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
ItemIterator items() const
Definition: BLI_map.hh:825
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition: BLI_map.hh:450
bool contains(const Key &key) const
Definition: BLI_set.hh:310
constexpr IndexRange index_range() const
Definition: BLI_span.hh:414
void append(const T &value)
Definition: BLI_vector.hh:438
void copy_to_initialized_n(const void *src, void *dst, int64_t n) const
Definition: FN_cpp_type.hh:399
const void * data() const
DEGForeachIDComponentCallback callback
int count
static void join_instance_groups_mesh(Span< GeometryInstanceGroup > set_groups, bool convert_points_to_vertices, GeometrySet &result)
static bool object_instance_attribute_foreach(const Object &object, const AttributeForeachCallback callback, const int limit, int &count)
static void join_instance_groups_pointcloud(Span< GeometryInstanceGroup > set_groups, GeometrySet &result)
static void add_final_mesh_as_geometry_component(const Object &object, GeometrySet &geometry_set)
void geometry_set_gather_instances(const GeometrySet &geometry_set, Vector< GeometryInstanceGroup > &r_instance_groups)
static void geometry_set_collect_recursive_object(const Object &object, const float4x4 &transform, Vector< GeometryInstanceGroup > &r_sets)
static Mesh * join_mesh_topology_and_builtin_attributes(Span< GeometryInstanceGroup > set_groups, const bool convert_points_to_vertices)
GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set)
static void geometry_set_collect_recursive(const GeometrySet &geometry_set, const float4x4 &transform, Vector< GeometryInstanceGroup > &r_sets)
std::unique_ptr< WriteAttribute > WriteAttributePtr
GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
void geometry_set_gather_instances_attribute_info(Span< GeometryInstanceGroup > set_groups, Span< GeometryComponentType > component_types, const Set< std::string > &ignored_attributes, Map< std::string, AttributeKind > &r_attributes)
static bool collection_instance_attribute_foreach(const Collection &collection, const AttributeForeachCallback callback, const int limit, int &count)
static void join_instance_groups_volume(Span< GeometryInstanceGroup > set_groups, GeometrySet &result)
static void geometry_set_collect_recursive_collection_instance(const Collection &collection, const float4x4 &transform, Vector< GeometryInstanceGroup > &r_sets)
static GeometrySet object_get_geometry_set_for_read(const Object &object)
const CPPType * custom_data_type_to_cpp_type(const CustomDataType type)
void geometry_set_instances_attribute_foreach(const GeometrySet &geometry_set, const AttributeForeachCallback callback, const int limit)
static void geometry_set_collect_recursive_collection(const Collection &collection, const float4x4 &transform, Vector< GeometryInstanceGroup > &r_sets)
std::unique_ptr< ReadAttribute > ReadAttributePtr
static void join_attributes(Span< GeometryInstanceGroup > set_groups, Span< GeometryComponentType > component_types, const Map< std::string, AttributeKind > &attribute_info, GeometryComponent &result)
static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_set, const AttributeForeachCallback callback, const int limit, int &count)
__int64 int64_t
Definition: stdint.h:92
float instance_offset[3]
void remove(const GeometryComponentType component_type)
const PointCloud * get_pointcloud_for_read() const
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
blender::Vector< const GeometryComponent * > get_components_for_read() const
bool has(const GeometryComponentType component_type) const
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) const
const Mesh * get_mesh_for_read() const
bool has_instances() const
bool has_mesh() const
bool has_pointcloud() const
unsigned int v1
unsigned int v2
unsigned int e
unsigned int v
float co[3]
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
float(* co)[3]
float values[4][4]
Definition: BLI_float4x4.hh:25