Blender V4.3
geometry_set_instances.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 "BKE_collection.hh"
7#include "BKE_instances.hh"
8#include "BKE_mesh_wrapper.hh"
9#include "BKE_modifier.hh"
10#include "BKE_object_types.hh"
11
13#include "DNA_layer_types.h"
14#include "DNA_object_types.h"
15
17
18namespace blender::bke {
19
20static void add_final_mesh_as_geometry_component(const Object &object, GeometrySet &geometry_set)
21{
23 &const_cast<Object &>(object));
24
25 if (mesh != nullptr) {
28 }
29}
30
32{
34 return {};
35 }
36 if (object.type == OB_MESH && object.mode == OB_MODE_EDIT) {
37 GeometrySet geometry_set;
38 if (object.runtime->geometry_set_eval != nullptr) {
39 /* `geometry_set_eval` only contains non-mesh components, see `editbmesh_build_data`. */
40 geometry_set = *object.runtime->geometry_set_eval;
41 }
42 add_final_mesh_as_geometry_component(object, geometry_set);
43 return geometry_set;
44 }
45 if (object.runtime->geometry_set_eval != nullptr) {
46 GeometrySet geometry_set = *object.runtime->geometry_set_eval;
47 /* Ensure that subdivision is performed on the CPU. */
48 if (geometry_set.has_mesh()) {
49 add_final_mesh_as_geometry_component(object, geometry_set);
50 }
51 return geometry_set;
52 }
53
54 /* Otherwise, construct a new geometry set with the component based on the object type. */
55 if (object.type == OB_MESH) {
56 GeometrySet geometry_set;
57 add_final_mesh_as_geometry_component(object, geometry_set);
58 return geometry_set;
59 }
60 if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
61 Collection &collection = *object.instance_collection;
62 std::unique_ptr<Instances> instances = std::make_unique<Instances>();
63 const int handle = instances->add_reference(collection);
64 instances->add_instance(handle, float4x4::identity());
65 return GeometrySet::from_instances(instances.release());
66 }
67
68 /* Return by value since there is not always an existing geometry set owned elsewhere to use. */
69 return {};
70}
71
73 FunctionRef<void(const GeometrySet &geometry_set)> callback) const
74{
75 for (const InstanceReference &reference : references_) {
76 switch (reference.type()) {
78 const Object &object = reference.object();
79 const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
80 callback(object_geometry_set);
81 break;
82 }
84 Collection &collection = reference.collection();
85 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
86 const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(*object);
87 callback(object_geometry_set);
88 }
90 break;
91 }
93 const GeometrySet &instance_geometry_set = reference.geometry_set();
94 callback(instance_geometry_set);
95 break;
96 }
98 break;
99 }
100 }
101 }
102}
103
105{
106 Vector<InstanceReference> new_references;
107 new_references.reserve(references_.size());
108 for (const InstanceReference &reference : references_) {
109 switch (reference.type()) {
111 new_references.append(InstanceReference(GeometrySet{}));
112 break;
113 }
115 /* Those references can stay as their were. */
116 new_references.append(reference);
117 break;
118 }
120 /* Create a new reference that contains the geometry set of the object. We may want to
121 * treat e.g. lamps and similar object types separately here. */
122 Object &object = reference.object();
124 new_references.append(InstanceReference(object));
125 break;
126 }
127 GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
128 if (object_geometry_set.has_instances()) {
129 object_geometry_set.get_instances_for_write()->ensure_geometry_instances();
130 }
131 new_references.append(std::move(object_geometry_set));
132 break;
133 }
135 /* Create a new reference that contains a geometry set that contains all objects from the
136 * collection as instances. */
137 std::unique_ptr<Instances> instances = std::make_unique<Instances>();
138 Collection &collection = reference.collection();
139
140 Vector<Object *, 8> objects;
141 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
142 objects.append(object);
143 }
145
146 instances->resize(objects.size());
147 MutableSpan<int> handles = instances->reference_handles_for_write();
148 MutableSpan<float4x4> transforms = instances->transforms_for_write();
149 for (const int i : objects.index_range()) {
150 handles[i] = instances->add_reference(*objects[i]);
151 transforms[i] = objects[i]->object_to_world();
152 transforms[i].location() -= collection.instance_offset;
153 }
154 instances->ensure_geometry_instances();
155 new_references.append(GeometrySet::from_instances(instances.release()));
156 break;
157 }
158 }
159 }
160 references_ = std::move(new_references);
161}
162
163} // namespace blender::bke
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval)
#define ELEM(...)
bool DEG_object_geometry_is_evaluated(const Object &object)
Object groups, one object can be in many groups at once.
@ OB_MODE_EDIT
Object is a sort of wrapper for general info.
@ OB_SPEAKER
@ OB_EMPTY
@ OB_CAMERA
@ OB_ARMATURE
@ OB_LAMP
@ OB_MESH
@ OB_GPENCIL_LEGACY
void append(const T &value)
void reserve(const int64_t min_capacity)
Span< float4x4 > transforms() const
Definition instances.cc:225
void foreach_referenced_geometry(FunctionRef< void(const GeometrySet &geometry_set)> callback) const
DEGForeachIDComponentCallback callback
static void add_final_mesh_as_geometry_component(const Object &object, GeometrySet &geometry_set)
GeometrySet object_get_evaluated_geometry_set(const Object &object)
static GeometrySet from_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Instances * get_instances_for_write()
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)