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