Blender  V3.3
blender/object.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include "blender/object_cull.h"
5 #include "blender/sync.h"
6 #include "blender/util.h"
7 
8 #include "scene/alembic.h"
9 #include "scene/camera.h"
10 #include "scene/integrator.h"
11 #include "scene/light.h"
12 #include "scene/mesh.h"
13 #include "scene/object.h"
14 #include "scene/particles.h"
15 #include "scene/scene.h"
16 #include "scene/shader.h"
17 #include "scene/shader_graph.h"
18 #include "scene/shader_nodes.h"
19 #include "scene/volume.h"
20 
21 #include "util/foreach.h"
22 #include "util/hash.h"
23 #include "util/log.h"
24 #include "util/task.h"
25 
27 
28 /* Utilities */
29 
30 bool BlenderSync::BKE_object_is_modified(BL::Object &b_ob)
31 {
32  /* test if we can instance or if the object is modified */
33  if (b_ob.type() == BL::Object::type_META) {
34  /* multi-user and dupli metaballs are fused, can't instance */
35  return true;
36  }
37  else if (ccl::BKE_object_is_modified(b_ob, b_scene, preview)) {
38  /* modifiers */
39  return true;
40  }
41  else {
42  /* object level material links */
43  for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
44  if (b_slot.link() == BL::MaterialSlot::link_OBJECT) {
45  return true;
46  }
47  }
48  }
49 
50  return false;
51 }
52 
53 bool BlenderSync::object_is_geometry(BObjectInfo &b_ob_info)
54 {
55  BL::ID b_ob_data = b_ob_info.object_data;
56 
57  if (!b_ob_data) {
58  return false;
59  }
60 
61  BL::Object::type_enum type = b_ob_info.iter_object.type();
62 
63  if (type == BL::Object::type_VOLUME || type == BL::Object::type_CURVES ||
64  type == BL::Object::type_POINTCLOUD) {
65  /* Will be exported attached to mesh. */
66  return true;
67  }
68 
69  /* Other object types that are not meshes but evaluate to meshes are presented to render engines
70  * as separate instance objects. Metaballs have not been affected by that change yet. */
71  if (type == BL::Object::type_META) {
72  return true;
73  }
74 
75  return b_ob_data.is_a(&RNA_Mesh);
76 }
77 
78 bool BlenderSync::object_can_have_geometry(BL::Object &b_ob)
79 {
80  BL::Object::type_enum type = b_ob.type();
81  switch (type) {
82  case BL::Object::type_MESH:
83  case BL::Object::type_CURVE:
84  case BL::Object::type_SURFACE:
85  case BL::Object::type_META:
86  case BL::Object::type_FONT:
87  case BL::Object::type_CURVES:
88  case BL::Object::type_POINTCLOUD:
89  case BL::Object::type_VOLUME:
90  return true;
91  default:
92  return false;
93  }
94 }
95 
96 bool BlenderSync::object_is_light(BL::Object &b_ob)
97 {
98  BL::ID b_ob_data = b_ob.data();
99 
100  return (b_ob_data && b_ob_data.is_a(&RNA_Light));
101 }
102 
103 void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object)
104 {
105  /* Initialize motion blur for object, detecting if it's enabled and creating motion
106  * steps array if so. */
107  array<Transform> motion;
108  object->set_motion(motion);
109 
110  Geometry *geom = object->get_geometry();
111  if (!geom) {
112  return;
113  }
114 
115  int motion_steps = 0;
116  bool use_motion_blur = false;
117 
118  Scene::MotionType need_motion = scene->need_motion();
119  if (need_motion == Scene::MOTION_BLUR) {
120  motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
121  if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
122  use_motion_blur = true;
123  }
124  }
125  else if (need_motion != Scene::MOTION_NONE) {
126  motion_steps = 3;
127  }
128 
129  geom->set_use_motion_blur(use_motion_blur);
130  geom->set_motion_steps(motion_steps);
131 
132  motion.resize(motion_steps, transform_empty());
133 
134  if (motion_steps) {
135  motion[motion_steps / 2] = object->get_tfm();
136 
137  /* update motion socket before trying to access object->motion_time */
138  object->set_motion(motion);
139 
140  for (size_t step = 0; step < motion_steps; step++) {
141  motion_times.insert(object->motion_time(step));
142  }
143  }
144 }
145 
146 Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
147  BL::ViewLayer &b_view_layer,
148  BL::DepsgraphObjectInstance &b_instance,
149  float motion_time,
150  bool use_particle_hair,
151  bool show_lights,
152  BlenderObjectCulling &culling,
153  bool *use_portal,
154  TaskPool *geom_task_pool)
155 {
156  const bool is_instance = b_instance.is_instance();
157  BL::Object b_ob = b_instance.object();
158  BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object();
159  BObjectInfo b_ob_info{b_ob, is_instance ? b_instance.instance_object() : b_ob, b_ob.data()};
160  const bool motion = motion_time != 0.0f;
161  /*const*/ Transform tfm = get_transform(b_ob.matrix_world());
162  int *persistent_id = NULL;
163  BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id_array;
164  if (is_instance) {
165  persistent_id_array = b_instance.persistent_id();
166  persistent_id = persistent_id_array.data;
167  if (!b_ob_info.is_real_object_data()) {
168  /* Remember which object data the geometry is coming from, so that we can sync it when the
169  * object has changed. */
170  instance_geometries_by_object[b_ob_info.real_object.ptr.data].insert(b_ob_info.object_data);
171  }
172  }
173 
174  /* light is handled separately */
175  if (!motion && object_is_light(b_ob)) {
176  if (!show_lights) {
177  return NULL;
178  }
179 
180  /* TODO: don't use lights for excluded layers used as mask layer,
181  * when dynamic overrides are back. */
182 #if 0
183  if (!((layer_flag & view_layer.holdout_layer) && (layer_flag & view_layer.exclude_layer)))
184 #endif
185  {
186  sync_light(b_parent,
187  persistent_id,
188  b_ob_info,
189  is_instance ? b_instance.random_id() : 0,
190  tfm,
191  use_portal);
192  }
193 
194  return NULL;
195  }
196 
197  /* only interested in object that we can create geometry from */
198  if (!object_is_geometry(b_ob_info)) {
199  return NULL;
200  }
201 
202  /* Perform object culling. */
203  if (culling.test(scene, b_ob, tfm)) {
204  return NULL;
205  }
206 
207  /* Visibility flags for both parent and child. */
208  PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
209  bool use_holdout = b_parent.holdout_get(PointerRNA_NULL, b_view_layer);
211 
212  if (b_parent.ptr.data != b_ob.ptr.data) {
213  visibility &= object_ray_visibility(b_parent);
214  }
215 
216  /* TODO: make holdout objects on excluded layer invisible for non-camera rays. */
217 #if 0
218  if (use_holdout && (layer_flag & view_layer.exclude_layer)) {
219  visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA);
220  }
221 #endif
222 
223  /* Clear camera visibility for indirect only objects. */
224  bool use_indirect_only = !use_holdout &&
225  b_parent.indirect_only_get(PointerRNA_NULL, b_view_layer);
226  if (use_indirect_only) {
227  visibility &= ~PATH_RAY_CAMERA;
228  }
229 
230  /* Don't export completely invisible objects. */
231  if (visibility == 0) {
232  return NULL;
233  }
234 
235  /* Use task pool only for non-instances, since sync_dupli_particle accesses
236  * geometry. This restriction should be removed for better performance. */
237  TaskPool *object_geom_task_pool = (is_instance) ? NULL : geom_task_pool;
238 
239  /* key to lookup object */
240  ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, use_particle_hair);
241  Object *object;
242 
243  /* motion vector case */
244  if (motion) {
245  object = object_map.find(key);
246 
247  if (object && object->use_motion()) {
248  /* Set transform at matching motion time step. */
249  int time_index = object->motion_step(motion_time);
250  if (time_index >= 0) {
251  array<Transform> motion = object->get_motion();
252  motion[time_index] = tfm;
253  object->set_motion(motion);
254  }
255 
256  /* mesh deformation */
257  if (object->get_geometry())
258  sync_geometry_motion(
259  b_depsgraph, b_ob_info, object, motion_time, use_particle_hair, object_geom_task_pool);
260  }
261 
262  return object;
263  }
264 
265  /* test if we need to sync */
266  bool object_updated = object_map.add_or_update(&object, b_ob, b_parent, key) ||
267  (tfm != object->get_tfm());
268 
269  /* mesh sync */
270  Geometry *geometry = sync_geometry(
271  b_depsgraph, b_ob_info, object_updated, use_particle_hair, object_geom_task_pool);
272  object->set_geometry(geometry);
273 
274  /* special case not tracked by object update flags */
275 
276  if (sync_object_attributes(b_instance, object)) {
277  object_updated = true;
278  }
279 
280  /* holdout */
281  object->set_use_holdout(use_holdout);
282 
283  object->set_visibility(visibility);
284 
285  object->set_is_shadow_catcher(b_ob.is_shadow_catcher() || b_parent.is_shadow_catcher());
286 
287  float shadow_terminator_shading_offset = get_float(cobject, "shadow_terminator_offset");
288  object->set_shadow_terminator_shading_offset(shadow_terminator_shading_offset);
289 
290  float shadow_terminator_geometry_offset = get_float(cobject,
291  "shadow_terminator_geometry_offset");
292  object->set_shadow_terminator_geometry_offset(shadow_terminator_geometry_offset);
293 
294  float ao_distance = get_float(cobject, "ao_distance");
295  if (ao_distance == 0.0f && b_parent.ptr.data != b_ob.ptr.data) {
296  PointerRNA cparent = RNA_pointer_get(&b_parent.ptr, "cycles");
297  ao_distance = get_float(cparent, "ao_distance");
298  }
299  object->set_ao_distance(ao_distance);
300 
301  bool is_caustics_caster = get_boolean(cobject, "is_caustics_caster");
302  object->set_is_caustics_caster(is_caustics_caster);
303 
304  bool is_caustics_receiver = get_boolean(cobject, "is_caustics_receiver");
305  object->set_is_caustics_receiver(is_caustics_receiver);
306 
307  /* sync the asset name for Cryptomatte */
308  BL::Object parent = b_ob.parent();
309  ustring parent_name;
310  if (parent) {
311  while (parent.parent()) {
312  parent = parent.parent();
313  }
314  parent_name = parent.name();
315  }
316  else {
317  parent_name = b_ob.name();
318  }
319  object->set_asset_name(parent_name);
320 
321  /* object sync
322  * transform comparison should not be needed, but duplis don't work perfect
323  * in the depsgraph and may not signal changes, so this is a workaround */
324  if (object->is_modified() || object_updated ||
325  (object->get_geometry() && object->get_geometry()->is_modified())) {
326  object->name = b_ob.name().c_str();
327  object->set_pass_id(b_ob.pass_index());
328  const BL::Array<float, 4> object_color = b_ob.color();
329  object->set_color(get_float3(object_color));
330  object->set_alpha(object_color[3]);
331  object->set_tfm(tfm);
332 
333  /* dupli texture coordinates and random_id */
334  if (is_instance) {
335  object->set_dupli_generated(0.5f * get_float3(b_instance.orco()) -
336  make_float3(0.5f, 0.5f, 0.5f));
337  object->set_dupli_uv(get_float2(b_instance.uv()));
338  object->set_random_id(b_instance.random_id());
339  }
340  else {
341  object->set_dupli_generated(zero_float3());
342  object->set_dupli_uv(zero_float2());
343  object->set_random_id(hash_uint2(hash_string(object->name.c_str()), 0));
344  }
345 
346  /* lightgroup */
347  object->set_lightgroup(ustring(b_ob.lightgroup()));
348 
349  object->tag_update(scene);
350  }
351 
352  sync_object_motion_init(b_parent, b_ob, object);
353 
354  if (is_instance) {
355  /* Sync possible particle data. */
356  sync_dupli_particle(b_parent, b_instance, object);
357  }
358 
359  return object;
360 }
361 
362 /* This function mirrors drw_uniform_property_lookup in draw_instance_data.cpp */
363 static bool lookup_property(BL::ID b_id, const string &name, float4 *r_value)
364 {
365  PointerRNA ptr;
366  PropertyRNA *prop;
367 
368  if (!RNA_path_resolve(&b_id.ptr, name.c_str(), &ptr, &prop)) {
369  return false;
370  }
371 
372  if (prop == NULL) {
373  return false;
374  }
375 
377  int arraylen = RNA_property_array_length(&ptr, prop);
378 
379  if (arraylen == 0) {
380  float value;
381 
382  if (type == PROP_FLOAT)
383  value = RNA_property_float_get(&ptr, prop);
384  else if (type == PROP_INT)
385  value = static_cast<float>(RNA_property_int_get(&ptr, prop));
386  else
387  return false;
388 
389  *r_value = make_float4(value, value, value, 1.0f);
390  return true;
391  }
392  else if (type == PROP_FLOAT && arraylen <= 4) {
393  *r_value = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
394  RNA_property_float_get_array(&ptr, prop, &r_value->x);
395  return true;
396  }
397 
398  return false;
399 }
400 
401 /* This function mirrors drw_uniform_attribute_lookup in draw_instance_data.cpp */
402 static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance,
403  const string &name,
404  bool use_instancer)
405 {
406  string idprop_name = string_printf("[\"%s\"]", name.c_str());
407  float4 value;
408 
409  /* If requesting instance data, check the parent particle system and object. */
410  if (use_instancer && b_instance.is_instance()) {
411  BL::ParticleSystem b_psys = b_instance.particle_system();
412 
413  if (b_psys) {
414  if (lookup_property(b_psys.settings(), idprop_name, &value) ||
415  lookup_property(b_psys.settings(), name, &value)) {
416  return value;
417  }
418  }
419  if (lookup_property(b_instance.parent(), idprop_name, &value) ||
420  lookup_property(b_instance.parent(), name, &value)) {
421  return value;
422  }
423  }
424 
425  /* Check the object and mesh. */
426  BL::Object b_ob = b_instance.object();
427  BL::ID b_data = b_ob.data();
428 
429  if (lookup_property(b_ob, idprop_name, &value) || lookup_property(b_ob, name, &value) ||
430  lookup_property(b_data, idprop_name, &value) || lookup_property(b_data, name, &value)) {
431  return value;
432  }
433 
434  return zero_float4();
435 }
436 
437 bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object)
438 {
439  /* Find which attributes are needed. */
440  AttributeRequestSet requests = object->get_geometry()->needed_attributes();
441 
442  /* Delete attributes that became unnecessary. */
443  vector<ParamValue> &attributes = object->attributes;
444  bool changed = false;
445 
446  for (int i = attributes.size() - 1; i >= 0; i--) {
447  if (!requests.find(attributes[i].name())) {
448  attributes.erase(attributes.begin() + i);
449  changed = true;
450  }
451  }
452 
453  /* Update attribute values. */
454  foreach (AttributeRequest &req, requests.requests) {
455  ustring name = req.name;
456 
457  std::string real_name;
459 
460  if (type != BL::ShaderNodeAttribute::attribute_type_GEOMETRY) {
461  bool use_instancer = (type == BL::ShaderNodeAttribute::attribute_type_INSTANCER);
462  float4 value = lookup_instance_property(b_instance, real_name, use_instancer);
463 
464  /* Try finding the existing attribute value. */
465  ParamValue *param = NULL;
466 
467  for (size_t i = 0; i < attributes.size(); i++) {
468  if (attributes[i].name() == name) {
469  param = &attributes[i];
470  break;
471  }
472  }
473 
474  /* Replace or add the value. */
475  ParamValue new_param(name, TypeDesc::TypeFloat4, 1, &value);
476  assert(new_param.datasize() == sizeof(value));
477 
478  if (!param) {
479  changed = true;
480  attributes.push_back(new_param);
481  }
482  else if (memcmp(param->data(), &value, sizeof(value)) != 0) {
483  changed = true;
484  *param = new_param;
485  }
486  }
487  }
488 
489  return changed;
490 }
491 
492 /* Object Loop */
493 
494 void BlenderSync::sync_procedural(BL::Object &b_ob,
495  BL::MeshSequenceCacheModifier &b_mesh_cache,
496  bool has_subdivision_modifier)
497 {
498 #ifdef WITH_ALEMBIC
499  BL::CacheFile cache_file = b_mesh_cache.cache_file();
500  void *cache_file_key = cache_file.ptr.data;
501 
502  AlembicProcedural *procedural = static_cast<AlembicProcedural *>(
503  procedural_map.find(cache_file_key));
504 
505  if (procedural == nullptr) {
506  procedural = scene->create_node<AlembicProcedural>();
507  procedural_map.add(cache_file_key, procedural);
508  }
509  else {
510  procedural_map.used(procedural);
511  }
512 
513  float current_frame = static_cast<float>(b_scene.frame_current());
514  if (cache_file.override_frame()) {
515  current_frame = cache_file.frame();
516  }
517 
518  if (!cache_file.override_frame()) {
519  procedural->set_start_frame(static_cast<float>(b_scene.frame_start()));
520  procedural->set_end_frame(static_cast<float>(b_scene.frame_end()));
521  }
522 
523  procedural->set_frame(current_frame);
524  procedural->set_frame_rate(b_scene.render().fps() / b_scene.render().fps_base());
525  procedural->set_frame_offset(cache_file.frame_offset());
526 
527  string absolute_path = blender_absolute_path(b_data, b_ob, b_mesh_cache.cache_file().filepath());
528  procedural->set_filepath(ustring(absolute_path));
529 
530  array<ustring> layers;
531  for (BL::CacheFileLayer &layer : cache_file.layers) {
532  if (layer.hide_layer()) {
533  continue;
534  }
535 
536  absolute_path = blender_absolute_path(b_data, b_ob, layer.filepath());
537  layers.push_back_slow(ustring(absolute_path));
538  }
539  procedural->set_layers(layers);
540 
541  procedural->set_scale(cache_file.scale());
542 
543  procedural->set_use_prefetch(cache_file.use_prefetch());
544  procedural->set_prefetch_cache_size(cache_file.prefetch_cache_size());
545 
546  /* create or update existing AlembicObjects */
547  ustring object_path = ustring(b_mesh_cache.object_path());
548 
549  AlembicObject *abc_object = procedural->get_or_create_object(object_path);
550 
551  array<Node *> used_shaders = find_used_shaders(b_ob);
552  abc_object->set_used_shaders(used_shaders);
553 
554  PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
555  const float subd_dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
556  abc_object->set_subd_dicing_rate(subd_dicing_rate);
557  abc_object->set_subd_max_level(max_subdivisions);
558 
559  abc_object->set_ignore_subdivision(!has_subdivision_modifier);
560 
561  if (abc_object->is_modified() || procedural->is_modified()) {
562  procedural->tag_update(scene);
563  }
564 #else
565  (void)b_ob;
566  (void)b_mesh_cache;
567  (void)has_subdivision_modifier;
568 #endif
569 }
570 
571 void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
572  BL::SpaceView3D &b_v3d,
573  float motion_time)
574 {
575  /* Task pool for multithreaded geometry sync. */
576  TaskPool geom_task_pool;
577 
578  /* layer data */
579  bool motion = motion_time != 0.0f;
580 
581  if (!motion) {
582  /* prepare for sync */
583  light_map.pre_sync();
584  geometry_map.pre_sync();
585  object_map.pre_sync();
586  procedural_map.pre_sync();
587  particle_system_map.pre_sync();
588  motion_times.clear();
589  }
590  else {
591  geometry_motion_synced.clear();
592  }
593  instance_geometries_by_object.clear();
594 
595  /* initialize culling */
596  BlenderObjectCulling culling(scene, b_scene);
597 
598  /* object loop */
599  bool cancel = false;
600  bool use_portal = false;
601  const bool show_lights = BlenderViewportParameters(b_v3d, use_developer_ui).use_scene_lights;
602 
603  BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
604  BL::Depsgraph::object_instances_iterator b_instance_iter;
605 
606  for (b_depsgraph.object_instances.begin(b_instance_iter);
607  b_instance_iter != b_depsgraph.object_instances.end() && !cancel;
608  ++b_instance_iter) {
609  BL::DepsgraphObjectInstance b_instance = *b_instance_iter;
610  BL::Object b_ob = b_instance.object();
611 
612  /* Viewport visibility. */
613  const bool show_in_viewport = !b_v3d || b_ob.visible_in_viewport_get(b_v3d);
614  if (show_in_viewport == false) {
615  continue;
616  }
617 
618  /* Load per-object culling data. */
619  culling.init_object(scene, b_ob);
620 
621  /* Ensure the object geom supporting the hair is processed before adding
622  * the hair processing task to the task pool, calling .to_mesh() on the
623  * same object in parallel does not work. */
624  const bool sync_hair = b_instance.show_particles() && object_has_particle_hair(b_ob);
625 
626  /* Object itself. */
627  if (b_instance.show_self()) {
628 #ifdef WITH_ALEMBIC
629  bool use_procedural = false;
630  bool has_subdivision_modifier = false;
631  BL::MeshSequenceCacheModifier b_mesh_cache(PointerRNA_NULL);
632 
633  /* Experimental as Blender does not have good support for procedurals at the moment. */
634  if (experimental) {
635  b_mesh_cache = object_mesh_cache_find(b_ob, &has_subdivision_modifier);
636  use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural();
637  }
638 
639  if (use_procedural) {
640  /* Skip in the motion case, as generating motion blur data will be handled in the
641  * procedural. */
642  if (!motion) {
643  sync_procedural(b_ob, b_mesh_cache, has_subdivision_modifier);
644  }
645  }
646  else
647 #endif
648  {
649  sync_object(b_depsgraph,
650  b_view_layer,
651  b_instance,
652  motion_time,
653  false,
654  show_lights,
655  culling,
656  &use_portal,
657  sync_hair ? NULL : &geom_task_pool);
658  }
659  }
660 
661  /* Particle hair as separate object. */
662  if (sync_hair) {
663  sync_object(b_depsgraph,
664  b_view_layer,
665  b_instance,
666  motion_time,
667  true,
668  show_lights,
669  culling,
670  &use_portal,
671  &geom_task_pool);
672  }
673 
674  cancel = progress.get_cancel();
675  }
676 
677  geom_task_pool.wait_work();
678 
679  progress.set_sync_status("");
680 
681  if (!cancel && !motion) {
682  sync_background_light(b_v3d, use_portal);
683 
684  /* Handle removed data and modified pointers, as this may free memory, delete Nodes in the
685  * right order to ensure that dependent data is freed after their users. Objects should be
686  * freed before particle systems and geometries. */
687  light_map.post_sync();
688  object_map.post_sync();
689  geometry_map.post_sync();
690  particle_system_map.post_sync();
691  procedural_map.post_sync();
692  }
693 
694  if (motion)
695  geometry_motion_synced.clear();
696 }
697 
698 void BlenderSync::sync_motion(BL::RenderSettings &b_render,
699  BL::Depsgraph &b_depsgraph,
700  BL::SpaceView3D &b_v3d,
701  BL::Object &b_override,
702  int width,
703  int height,
704  void **python_thread_state)
705 {
706  if (scene->need_motion() == Scene::MOTION_NONE)
707  return;
708 
709  /* get camera object here to deal with camera switch */
710  BL::Object b_cam = b_scene.camera();
711  if (b_override)
712  b_cam = b_override;
713 
714  int frame_center = b_scene.frame_current();
715  float subframe_center = b_scene.frame_subframe();
716  float frame_center_delta = 0.0f;
717 
718  if (scene->need_motion() != Scene::MOTION_PASS &&
719  scene->camera->get_motion_position() != MOTION_POSITION_CENTER) {
720  float shuttertime = scene->camera->get_shuttertime();
721  if (scene->camera->get_motion_position() == MOTION_POSITION_END) {
722  frame_center_delta = -shuttertime * 0.5f;
723  }
724  else {
725  assert(scene->camera->get_motion_position() == MOTION_POSITION_START);
726  frame_center_delta = shuttertime * 0.5f;
727  }
728 
729  float time = frame_center + subframe_center + frame_center_delta;
730  int frame = (int)floorf(time);
731  float subframe = time - frame;
732  python_thread_state_restore(python_thread_state);
733  b_engine.frame_set(frame, subframe);
734  python_thread_state_save(python_thread_state);
735  if (b_cam) {
736  sync_camera_motion(b_render, b_cam, width, height, 0.0f);
737  }
738  sync_objects(b_depsgraph, b_v3d);
739  }
740 
741  /* Insert motion times from camera. Motion times from other objects
742  * have already been added in a sync_objects call. */
743  if (b_cam) {
744  uint camera_motion_steps = object_motion_steps(b_cam, b_cam);
745  for (size_t step = 0; step < camera_motion_steps; step++) {
746  motion_times.insert(scene->camera->motion_time(step));
747  }
748  }
749 
750  /* Check which geometry already has motion blur so it can be skipped. */
751  geometry_motion_attribute_synced.clear();
752  for (Geometry *geom : scene->geometry) {
754  geometry_motion_attribute_synced.insert(geom);
755  }
756  }
757 
758  /* note iteration over motion_times set happens in sorted order */
759  foreach (float relative_time, motion_times) {
760  /* center time is already handled. */
761  if (relative_time == 0.0f) {
762  continue;
763  }
764 
765  VLOG_WORK << "Synchronizing motion for the relative time " << relative_time << ".";
766 
767  /* fixed shutter time to get previous and next frame for motion pass */
768  float shuttertime = scene->motion_shutter_time();
769 
770  /* compute frame and subframe time */
771  float time = frame_center + subframe_center + frame_center_delta +
772  relative_time * shuttertime * 0.5f;
773  int frame = (int)floorf(time);
774  float subframe = time - frame;
775 
776  /* change frame */
777  python_thread_state_restore(python_thread_state);
778  b_engine.frame_set(frame, subframe);
779  python_thread_state_save(python_thread_state);
780 
781  /* Syncs camera motion if relative_time is one of the camera's motion times. */
782  sync_camera_motion(b_render, b_cam, width, height, relative_time);
783 
784  /* sync object */
785  sync_objects(b_depsgraph, b_v3d, relative_time);
786  }
787 
788  geometry_motion_attribute_synced.clear();
789 
790  /* we need to set the python thread state again because this
791  * function assumes it is being executed from python and will
792  * try to save the thread state */
793  python_thread_state_restore(python_thread_state);
794  b_engine.frame_set(frame_center, subframe_center);
795  python_thread_state_save(python_thread_state);
796 }
797 
int BKE_object_is_modified(struct Scene *scene, struct Object *ob)
Definition: object.cc:4854
unsigned int uint
Definition: BLI_sys_types.h:67
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
struct ID ID
struct CacheFile CacheFile
struct CacheFileLayer CacheFileLayer
struct ViewLayer ViewLayer
struct Object Object
struct ParticleSystem ParticleSystem
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_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
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
float float4[4]
PropertyType
Definition: RNA_types.h:58
@ PROP_FLOAT
Definition: RNA_types.h:61
@ PROP_INT
Definition: RNA_types.h:60
static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance, const string &name, bool use_instancer)
static bool lookup_property(BL::ID b_id, const string &name, float4 *r_value)
BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name)
vector< AttributeRequest > requests
bool find(ustring name)
Attribute * find(ustring name) const
void init_object(Scene *scene, BL::Object &b_ob)
Definition: object_cull.cpp:40
bool test(Scene *scene, BL::Object &b_ob, Transform &tfm)
Definition: object_cull.cpp:57
AttributeSet attributes
bool get_cancel() const
Definition: progress.h:90
void set_sync_status(const string &status_, const string &substatus_="")
Definition: progress.h:269
T * resize(size_t newsize)
void push_back_slow(const T &t)
void add(const K &key, T *data)
Definition: id_map.h:77
bool add_or_update(T **r_data, const BL::ID &id)
Definition: id_map.h:100
void pre_sync()
Definition: id_map.h:71
void used(T *data)
Definition: id_map.h:136
T * find(const BL::ID &id)
Definition: id_map.h:41
void post_sync(bool do_delete=true)
Definition: id_map.h:147
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
static uint object_ray_visibility(BL::Object &b_ob)
static uint object_motion_steps(BL::Object &b_parent, BL::Object &b_ob, const int max_steps=INT_MAX)
static float get_float(PointerRNA &ptr, const char *name)
static bool get_boolean(PointerRNA &ptr, const char *name)
static float3 get_float3(const BL::Array< float, 2 > &array)
static string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path)
static float2 get_float2(const BL::Array< float, 2 > &array)
static Transform get_transform(const BL::Array< float, 16 > &array)
static BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob, bool *has_subdivision_modifier)
static bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob)
BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType
double time
SyclQueue void void size_t num_bytes void
static uint hash_string(const char *str)
Definition: hash.h:363
ccl_device_inline uint hash_uint2(uint kx, uint ky)
Definition: hash.h:70
ccl_device_inline Transform transform_empty()
ccl_device_inline float3 object_color(KernelGlobals kg, int object)
@ ATTR_STD_MOTION_VERTEX_POSITION
Definition: kernel/types.h:624
@ PATH_RAY_ALL_VISIBILITY
Definition: kernel/types.h:217
@ PATH_RAY_CAMERA
Definition: kernel/types.h:194
@ MOTION_POSITION_END
Definition: kernel/types.h:487
@ MOTION_POSITION_START
Definition: kernel/types.h:483
@ MOTION_POSITION_CENTER
Definition: kernel/types.h:485
#define VLOG_WORK
Definition: log.h:80
ccl_device_inline float2 zero_float2()
Definition: math_float2.h:62
ccl_device_inline float3 zero_float3()
Definition: math_float3.h:80
ccl_device_inline float4 zero_float4()
Definition: math_float4.h:92
#define floorf(x)
Definition: metal/compat.h:224
#define make_float4(x, y, z, w)
Definition: metal/compat.h:205
#define make_float3(x, y, z)
Definition: metal/compat.h:204
void python_thread_state_restore(void **python_thread_state)
Definition: python.cpp:93
void python_thread_state_save(void **python_thread_state)
Definition: python.cpp:88
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2767
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
Definition: rna_access.c:2879
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5167
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1010
const PointerRNA PointerRNA_NULL
Definition: rna_access.c:61
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2429
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:1075
bool RNA_path_resolve(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition: rna_path.cc:503
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition: string.cpp:22
BL::Object real_object
BL::Object iter_object
bool is_real_object_data() const
ustring name
Definition: graph/node.h:174
bool is_modified() const
Definition: graph/node.cpp:804
int motion_step(float time) const
bool use_motion() const
static const uint MAX_MOTION_STEPS
Definition: scene/object.h:90
struct Object * parent
float motion_time(int step) const
T * create_node(Args &&...args)
Definition: scene.h:284
vector< Geometry * > geometry
Definition: scene.h:214
MotionType need_motion() const
Definition: scene.cpp:387
MotionType
Definition: scene.h:259
@ MOTION_PASS
Definition: scene.h:259
@ MOTION_NONE
Definition: scene.h:259
@ MOTION_BLUR
Definition: scene.h:259
struct Object * camera
float motion_shutter_time()
Definition: scene.cpp:397
void wait_work(Summary *stats=NULL)
Definition: task.cpp:29
float max
PointerRNA * ptr
Definition: wm_files.c:3480