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