Blender V4.5
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_lib_id.hh"
9#include "BKE_mesh_wrapper.hh"
10#include "BKE_modifier.hh"
11#include "BKE_object.hh"
12#include "BKE_object_types.hh"
13
15#include "DNA_layer_types.h"
16#include "DNA_object_types.h"
17
19
20namespace blender::bke {
21
23 GeometrySet &geometry_set,
24 const bool apply_subdiv)
25{
26 if (apply_subdiv) {
28 &const_cast<Object &>(object));
29
30 if (mesh != nullptr) {
33 }
34 return;
35 }
37 if (mesh != nullptr) {
39 }
40}
41
42GeometrySet object_get_evaluated_geometry_set(const Object &object, const bool apply_subdiv)
43{
45 return {};
46 }
47 if (object.type == OB_MESH && object.mode == OB_MODE_EDIT) {
48 GeometrySet geometry_set;
49 if (object.runtime->geometry_set_eval != nullptr) {
50 /* `geometry_set_eval` only contains non-mesh components, see `editbmesh_build_data`. */
51 geometry_set = *object.runtime->geometry_set_eval;
52 }
53 add_final_mesh_as_geometry_component(object, geometry_set, apply_subdiv);
54 return geometry_set;
55 }
56 if (object.runtime->geometry_set_eval != nullptr) {
57 GeometrySet geometry_set = *object.runtime->geometry_set_eval;
58 /* Ensure that subdivision is performed on the CPU. */
59 if (geometry_set.has_mesh()) {
60 add_final_mesh_as_geometry_component(object, geometry_set, apply_subdiv);
61 }
62 return geometry_set;
63 }
64
65 /* Otherwise, construct a new geometry set with the component based on the object type. */
66 if (object.type == OB_MESH) {
67 GeometrySet geometry_set;
68 add_final_mesh_as_geometry_component(object, geometry_set, apply_subdiv);
69 return geometry_set;
70 }
71 if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
72 Collection &collection = *object.instance_collection;
73 std::unique_ptr<Instances> instances = std::make_unique<Instances>();
74 const int handle = instances->add_reference(collection);
75 instances->add_instance(handle, float4x4::identity());
76 return GeometrySet::from_instances(instances.release());
77 }
78
79 /* Return by value since there is not always an existing geometry set owned elsewhere to use. */
80 return {};
81}
82
84 FunctionRef<void(const GeometrySet &geometry_set)> callback) const
85{
86 for (const InstanceReference &reference : references_) {
87 switch (reference.type()) {
89 const Object &object = reference.object();
90 const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
91 callback(object_geometry_set);
92 break;
93 }
95 Collection &collection = reference.collection();
96 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
97 const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(*object);
98 callback(object_geometry_set);
99 }
101 break;
102 }
104 const GeometrySet &instance_geometry_set = reference.geometry_set();
105 callback(instance_geometry_set);
106 break;
107 }
109 break;
110 }
111 }
112 }
113}
114
116{
117 Vector<InstanceReference> new_references;
118 new_references.reserve(references_.size());
119 for (const InstanceReference &reference : references_) {
120 switch (reference.type()) {
122 new_references.append(InstanceReference(GeometrySet{}));
123 break;
124 }
126 /* Those references can stay as their were. */
127 new_references.append(reference);
128 break;
129 }
131 /* Create a new reference that contains the geometry set of the object. We may want to
132 * treat e.g. lamps and similar object types separately here. */
133 Object &object = reference.object();
134 if (ELEM(object.type, OB_LAMP, OB_CAMERA, OB_SPEAKER, OB_ARMATURE)) {
135 new_references.append(InstanceReference(object));
136 break;
137 }
138 GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
139 object_geometry_set.name = BKE_id_name(object.id);
140 if (object_geometry_set.has_instances()) {
141 object_geometry_set.get_instances_for_write()->ensure_geometry_instances();
142 }
143 new_references.append(std::move(object_geometry_set));
144 break;
145 }
147 /* Create a new reference that contains a geometry set that contains all objects from the
148 * collection as instances. */
149 std::unique_ptr<Instances> instances = std::make_unique<Instances>();
150 Collection &collection = reference.collection();
151
152 Vector<Object *, 8> objects;
153 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
154 objects.append(object);
155 }
157
158 instances->resize(objects.size());
159 MutableSpan<int> handles = instances->reference_handles_for_write();
160 MutableSpan<float4x4> transforms = instances->transforms_for_write();
161 for (const int i : objects.index_range()) {
162 handles[i] = instances->add_reference(*objects[i]);
163 transforms[i] = objects[i]->object_to_world();
164 transforms[i].location() -= collection.instance_offset;
165 }
166 instances->ensure_geometry_instances();
167 GeometrySet geometry_set = GeometrySet::from_instances(instances.release());
168 geometry_set.name = BKE_id_name(collection.id);
169 new_references.append(std::move(geometry_set));
170 break;
171 }
172 }
173 }
174 references_ = std::move(new_references);
175}
176
177} // namespace blender::bke
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
const char * BKE_id_name(const ID &id)
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh_no_subsurf(const Object *object_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
int64_t size() const
void append(const T &value)
IndexRange index_range() const
void reserve(const int64_t min_capacity)
Span< float4x4 > transforms() const
Definition instances.cc:233
void foreach_referenced_geometry(FunctionRef< void(const GeometrySet &geometry_set)> callback) const
GeometrySet object_get_evaluated_geometry_set(const Object &object, bool apply_subdiv=true)
static void add_final_mesh_as_geometry_component(const Object &object, GeometrySet &geometry_set, const bool apply_subdiv)
static GeometrySet from_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Instances * get_instances_for_write()
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
i
Definition text_draw.cc:230
ParamHandle ** handles