Blender V4.3
blender/geometry.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "scene/curves.h"
6#include "scene/hair.h"
7#include "scene/mesh.h"
8#include "scene/object.h"
9#include "scene/pointcloud.h"
10#include "scene/volume.h"
11
12#include "blender/sync.h"
13#include "blender/util.h"
14
15#include "util/foreach.h"
16#include "util/task.h"
17
19
20static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair)
21{
22 if (b_ob_info.object_data.is_a(&RNA_Curves) || use_particle_hair) {
23 return Geometry::HAIR;
24 }
25
26 if (b_ob_info.object_data.is_a(&RNA_PointCloud)) {
28 }
29
30 if (b_ob_info.object_data.is_a(&RNA_Volume) ||
31 (b_ob_info.object_data == b_ob_info.real_object.data() &&
33 {
34 return Geometry::VOLUME;
35 }
36
37 return Geometry::MESH;
38}
39
40array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob)
41{
42 BL::Material material_override = view_layer.material_override;
43 Shader *default_shader = (b_ob.type() == BL::Object::type_VOLUME) ? scene->default_volume :
44 scene->default_surface;
45
46 array<Node *> used_shaders;
47
48 for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
49 if (material_override) {
50 find_shader(material_override, used_shaders, default_shader);
51 }
52 else {
53 BL::ID b_material(b_slot.material());
54 find_shader(b_material, used_shaders, default_shader);
55 }
56 }
57
58 if (used_shaders.size() == 0) {
59 if (material_override) {
60 find_shader(material_override, used_shaders, default_shader);
61 }
62 else {
63 used_shaders.push_back_slow(default_shader);
64 }
65 }
66
67 return used_shaders;
68}
69
70Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
71 BObjectInfo &b_ob_info,
72 bool object_updated,
73 bool use_particle_hair,
75{
76 /* Test if we can instance or if the object is modified. */
77 Geometry::Type geom_type = determine_geom_type(b_ob_info, use_particle_hair);
78 BL::ID b_key_id = (b_ob_info.is_real_object_data() &&
79 BKE_object_is_modified(b_ob_info.real_object)) ?
80 b_ob_info.real_object :
81 b_ob_info.object_data;
82 GeometryKey key(b_key_id.ptr.data, geom_type);
83
84 /* Find shader indices. */
85 array<Node *> used_shaders = find_used_shaders(b_ob_info.iter_object);
86
87 /* Ensure we only sync instanced geometry once. */
88 Geometry *geom = geometry_map.find(key);
89 if (geom) {
90 if (geometry_synced.find(geom) != geometry_synced.end()) {
91 return geom;
92 }
93 }
94
95 /* Test if we need to sync. */
96 bool sync = true;
97 if (geom == NULL) {
98 /* Add new geometry if it did not exist yet. */
99 if (geom_type == Geometry::HAIR) {
100 geom = scene->create_node<Hair>();
101 }
102 else if (geom_type == Geometry::VOLUME) {
103 geom = scene->create_node<Volume>();
104 }
105 else if (geom_type == Geometry::POINTCLOUD) {
106 geom = scene->create_node<PointCloud>();
107 }
108 else {
109 geom = scene->create_node<Mesh>();
110 }
111 geometry_map.add(key, geom);
112 }
113 else {
114 /* Test if we need to update existing geometry. */
115 sync = geometry_map.update(geom, b_key_id);
116 }
117
118 if (!sync) {
119 /* If transform was applied to geometry, need full update. */
120 if (object_updated && geom->transform_applied) {
121 ;
122 }
123 /* Test if shaders changed, these can be object level so geometry
124 * does not get tagged for recalc. */
125 else if (geom->get_used_shaders() != used_shaders) {
126 ;
127 }
128 else {
129 /* Even if not tagged for recalc, we may need to sync anyway
130 * because the shader needs different geometry attributes. */
131 bool attribute_recalc = false;
132
133 foreach (Node *node, geom->get_used_shaders()) {
134 Shader *shader = static_cast<Shader *>(node);
135 if (shader->need_update_geometry()) {
136 attribute_recalc = true;
137 }
138 }
139
140 if (!attribute_recalc) {
141 return geom;
142 }
143 }
144 }
145
146 geometry_synced.insert(geom);
147
148 geom->name = ustring(b_ob_info.object_data.name().c_str());
149
150 /* Store the shaders immediately for the object attribute code. */
151 geom->set_used_shaders(used_shaders);
152
153 auto sync_func = [=]() mutable {
154 if (progress.get_cancel()) {
155 return;
156 }
157
158 progress.set_sync_status("Synchronizing object", b_ob_info.real_object.name());
159
160 if (geom_type == Geometry::HAIR) {
161 Hair *hair = static_cast<Hair *>(geom);
162 sync_hair(b_depsgraph, b_ob_info, hair);
163 }
164 else if (geom_type == Geometry::VOLUME) {
165 Volume *volume = static_cast<Volume *>(geom);
166 sync_volume(b_ob_info, volume);
167 }
168 else if (geom_type == Geometry::POINTCLOUD) {
169 PointCloud *pointcloud = static_cast<PointCloud *>(geom);
170 sync_pointcloud(pointcloud, b_ob_info);
171 }
172 else {
173 Mesh *mesh = static_cast<Mesh *>(geom);
174 sync_mesh(b_depsgraph, b_ob_info, mesh);
175 }
176 };
177
178 /* Defer the actual geometry sync to the task_pool for multithreading */
179 if (task_pool) {
181 }
182 else {
183 sync_func();
184 }
185
186 return geom;
187}
188
189void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
190 BObjectInfo &b_ob_info,
191 Object *object,
192 float motion_time,
193 bool use_particle_hair,
195{
196 /* Ensure we only sync instanced geometry once. */
197 Geometry *geom = object->get_geometry();
198
199 if (geometry_motion_synced.find(geom) != geometry_motion_synced.end() ||
200 geometry_motion_attribute_synced.find(geom) != geometry_motion_attribute_synced.end())
201 {
202 return;
203 }
204
205 geometry_motion_synced.insert(geom);
206
207 /* Ensure we only motion sync geometry that also had geometry synced, to avoid
208 * unnecessary work and to ensure that its attributes were clear. */
209 if (geometry_synced.find(geom) == geometry_synced.end()) {
210 return;
211 }
212
213 /* Find time matching motion step required by geometry. */
214 int motion_step = geom->motion_step(motion_time);
215 if (motion_step < 0) {
216 return;
217 }
218
219 auto sync_func = [=]() mutable {
220 if (progress.get_cancel()) {
221 return;
222 }
223
224 if (b_ob_info.object_data.is_a(&RNA_Curves) || use_particle_hair) {
225 Hair *hair = static_cast<Hair *>(geom);
226 sync_hair_motion(b_depsgraph, b_ob_info, hair, motion_step);
227 }
228 else if (b_ob_info.object_data.is_a(&RNA_Volume) ||
230 {
231 /* No volume motion blur support yet. */
232 }
233 else if (b_ob_info.object_data.is_a(&RNA_PointCloud)) {
234 PointCloud *pointcloud = static_cast<PointCloud *>(geom);
235 sync_pointcloud_motion(pointcloud, b_ob_info, motion_step);
236 }
237 else {
238 Mesh *mesh = static_cast<Mesh *>(geom);
239 sync_mesh_motion(b_depsgraph, b_ob_info, mesh, motion_step);
240 }
241 };
242
243 /* Defer the actual geometry sync to the task_pool for multithreading */
244 if (task_pool) {
246 }
247 else {
248 sync_func();
249 }
250}
251
static CCL_NAMESPACE_BEGIN Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair)
bool transform_applied
int motion_step(float time) const
Definition hair.h:14
bool get_cancel() const
Definition progress.h:93
void set_sync_status(const string &status_, const string &substatus_="")
Definition progress.h:284
size_t size() const
void push_back_slow(const T &t)
void add(const K &key, T *data)
Definition id_map.h:80
bool update(T *data, const BL::ID &id)
Definition id_map.h:88
T * find(const BL::ID &id)
Definition id_map.h:39
static BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
OperationNode * node
#define CCL_NAMESPACE_END
#define NULL
TaskPool * task_pool
static PyObject * sync_func(PyObject *, PyObject *args)
Definition python.cpp:381
BL::Object real_object
BL::Object iter_object
bool is_real_object_data() const
ustring name
Definition graph/node.h:177
void push(TaskRunFunction &&task)
Definition task.cpp:22