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