Cycles: Added Cryptomatte output.
[blender.git] / intern / cycles / blender / blender_object.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "render/camera.h"
18 #include "render/integrator.h"
19 #include "render/graph.h"
20 #include "render/light.h"
21 #include "render/mesh.h"
22 #include "render/object.h"
23 #include "render/scene.h"
24 #include "render/nodes.h"
25 #include "render/particles.h"
26 #include "render/shader.h"
27
28 #include "blender/blender_object_cull.h"
29 #include "blender/blender_sync.h"
30 #include "blender/blender_util.h"
31
32 #include "util/util_foreach.h"
33 #include "util/util_hash.h"
34 #include "util/util_logging.h"
35
36 CCL_NAMESPACE_BEGIN
37
38 /* Utilities */
39
40 bool BlenderSync::BKE_object_is_modified(BL::Object& b_ob)
41 {
42         /* test if we can instance or if the object is modified */
43         if(b_ob.type() == BL::Object::type_META) {
44                 /* multi-user and dupli metaballs are fused, can't instance */
45                 return true;
46         }
47         else if(ccl::BKE_object_is_modified(b_ob, b_scene, preview)) {
48                 /* modifiers */
49                 return true;
50         }
51         else {
52                 /* object level material links */
53                 BL::Object::material_slots_iterator slot;
54                 for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
55                         if(slot->link() == BL::MaterialSlot::link_OBJECT)
56                                 return true;
57         }
58
59         return false;
60 }
61
62 bool BlenderSync::object_is_mesh(BL::Object& b_ob)
63 {
64         BL::ID b_ob_data = b_ob.data();
65
66         if(!b_ob_data) {
67                 return false;
68         }
69
70         if(b_ob.type() == BL::Object::type_CURVE) {
71                 /* Skip exporting curves without faces, overhead can be
72                  * significant if there are many for path animation. */
73                 BL::Curve b_curve(b_ob.data());
74
75                 return (b_curve.bevel_object() ||
76                         b_curve.extrude() != 0.0f ||
77                         b_curve.bevel_depth() != 0.0f ||
78                         b_curve.dimensions() == BL::Curve::dimensions_2D ||
79                         b_ob.modifiers.length());
80         }
81         else {
82                 return (b_ob_data.is_a(&RNA_Mesh) ||
83                         b_ob_data.is_a(&RNA_Curve) ||
84                         b_ob_data.is_a(&RNA_MetaBall));
85         }
86 }
87
88 bool BlenderSync::object_is_light(BL::Object& b_ob)
89 {
90         BL::ID b_ob_data = b_ob.data();
91
92         return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
93 }
94
95 static uint object_ray_visibility(BL::Object& b_ob)
96 {
97         PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
98         uint flag = 0;
99
100         flag |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0;
101         flag |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0;
102         flag |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0;
103         flag |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0;
104         flag |= get_boolean(cvisibility, "shadow")? PATH_RAY_SHADOW: 0;
105         flag |= get_boolean(cvisibility, "scatter")? PATH_RAY_VOLUME_SCATTER: 0;
106
107         return flag;
108 }
109
110 /* Light */
111
112 void BlenderSync::sync_light(BL::Object& b_parent,
113                              int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
114                              BL::Object& b_ob,
115                              BL::DupliObject& b_dupli_ob,
116                              Transform& tfm,
117                              bool *use_portal)
118 {
119         /* test if we need to sync */
120         Light *light;
121         ObjectKey key(b_parent, persistent_id, b_ob);
122
123         if(!light_map.sync(&light, b_ob, b_parent, key)) {
124                 if(light->is_portal)
125                         *use_portal = true;
126                 return;
127         }
128
129         BL::Lamp b_lamp(b_ob.data());
130
131         /* type */
132         switch(b_lamp.type()) {
133                 case BL::Lamp::type_POINT: {
134                         BL::PointLamp b_point_lamp(b_lamp);
135                         light->size = b_point_lamp.shadow_soft_size();
136                         light->type = LIGHT_POINT;
137                         break;
138                 }
139                 case BL::Lamp::type_SPOT: {
140                         BL::SpotLamp b_spot_lamp(b_lamp);
141                         light->size = b_spot_lamp.shadow_soft_size();
142                         light->type = LIGHT_SPOT;
143                         light->spot_angle = b_spot_lamp.spot_size();
144                         light->spot_smooth = b_spot_lamp.spot_blend();
145                         break;
146                 }
147                 case BL::Lamp::type_HEMI: {
148                         light->type = LIGHT_DISTANT;
149                         light->size = 0.0f;
150                         break;
151                 }
152                 case BL::Lamp::type_SUN: {
153                         BL::SunLamp b_sun_lamp(b_lamp);
154                         light->size = b_sun_lamp.shadow_soft_size();
155                         light->type = LIGHT_DISTANT;
156                         break;
157                 }
158                 case BL::Lamp::type_AREA: {
159                         BL::AreaLamp b_area_lamp(b_lamp);
160                         light->size = 1.0f;
161                         light->axisu = transform_get_column(&tfm, 0);
162                         light->axisv = transform_get_column(&tfm, 1);
163                         light->sizeu = b_area_lamp.size();
164                         if(b_area_lamp.shape() == BL::AreaLamp::shape_RECTANGLE)
165                                 light->sizev = b_area_lamp.size_y();
166                         else
167                                 light->sizev = light->sizeu;
168                         light->type = LIGHT_AREA;
169                         break;
170                 }
171         }
172
173         /* location and (inverted!) direction */
174         light->co = transform_get_column(&tfm, 3);
175         light->dir = -transform_get_column(&tfm, 2);
176         light->tfm = tfm;
177
178         /* shader */
179         vector<Shader*> used_shaders;
180         find_shader(b_lamp, used_shaders, scene->default_light);
181         light->shader = used_shaders[0];
182
183         /* shadow */
184         PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
185         PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
186         light->cast_shadow = get_boolean(clamp, "cast_shadow");
187         light->use_mis = get_boolean(clamp, "use_multiple_importance_sampling");
188
189         int samples = get_int(clamp, "samples");
190         if(get_boolean(cscene, "use_square_samples"))
191                 light->samples = samples * samples;
192         else
193                 light->samples = samples;
194
195         light->max_bounces = get_int(clamp, "max_bounces");
196
197         if(b_dupli_ob) {
198                 light->random_id = b_dupli_ob.random_id();
199         }
200         else {
201                 light->random_id = hash_int_2d(hash_string(b_ob.name().c_str()), 0);
202         }
203
204         if(light->type == LIGHT_AREA)
205                 light->is_portal = get_boolean(clamp, "is_portal");
206         else
207                 light->is_portal = false;
208
209         if(light->is_portal)
210                 *use_portal = true;
211
212         /* visibility */
213         uint visibility = object_ray_visibility(b_ob);
214         light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0;
215         light->use_glossy = (visibility & PATH_RAY_GLOSSY) != 0;
216         light->use_transmission = (visibility & PATH_RAY_TRANSMIT) != 0;
217         light->use_scatter = (visibility & PATH_RAY_VOLUME_SCATTER) != 0;
218
219         /* tag */
220         light->tag_update(scene);
221 }
222
223 void BlenderSync::sync_background_light(bool use_portal)
224 {
225         BL::World b_world = b_scene.world();
226
227         if(b_world) {
228                 PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
229                 PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
230
231                 enum SamplingMethod {
232                         SAMPLING_NONE = 0,
233                         SAMPLING_AUTOMATIC,
234                         SAMPLING_MANUAL,
235                         SAMPLING_NUM
236                 };
237                 int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC);
238                 bool sample_as_light = (sampling_method != SAMPLING_NONE);
239
240                 if(sample_as_light || use_portal) {
241                         /* test if we need to sync */
242                         Light *light;
243                         ObjectKey key(b_world, 0, b_world);
244
245                         if(light_map.sync(&light, b_world, b_world, key) ||
246                             world_recalc ||
247                             b_world.ptr.data != world_map)
248                         {
249                                 light->type = LIGHT_BACKGROUND;
250                                 if(sampling_method == SAMPLING_MANUAL) {
251                                         light->map_resolution = get_int(cworld, "sample_map_resolution");
252                                 }
253                                 else {
254                                         light->map_resolution = 0;
255                                 }
256                                 light->shader = scene->default_background;
257                                 light->use_mis = sample_as_light;
258                                 light->max_bounces = get_int(cworld, "max_bounces");
259
260                                 int samples = get_int(cworld, "samples");
261                                 if(get_boolean(cscene, "use_square_samples"))
262                                         light->samples = samples * samples;
263                                 else
264                                         light->samples = samples;
265
266                                 light->tag_update(scene);
267                                 light_map.set_recalc(b_world);
268                         }
269                 }
270         }
271
272         world_map = b_world.ptr.data;
273         world_recalc = false;
274 }
275
276 /* Object */
277
278 Object *BlenderSync::sync_object(BL::Object& b_parent,
279                                  int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
280                                  BL::DupliObject& b_dupli_ob,
281                                  Transform& tfm,
282                                  uint layer_flag,
283                                  float motion_time,
284                                  bool hide_tris,
285                                  BlenderObjectCulling& culling,
286                                  bool *use_portal)
287 {
288         BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
289         bool motion = motion_time != 0.0f;
290
291         /* light is handled separately */
292         if(object_is_light(b_ob)) {
293                 /* don't use lamps for excluded layers used as mask layer */
294                 if(!motion && !((layer_flag & render_layer.holdout_layer) && (layer_flag & render_layer.exclude_layer)))
295                         sync_light(b_parent, persistent_id, b_ob, b_dupli_ob, tfm, use_portal);
296
297                 return NULL;
298         }
299
300         /* only interested in object that we can create meshes from */
301         if(!object_is_mesh(b_ob)) {
302                 return NULL;
303         }
304
305         /* Perform object culling. */
306         if(culling.test(scene, b_ob, tfm)) {
307                 return NULL;
308         }
309
310         /* Visibility flags for both parent and child. */
311         PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
312         bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0 ||
313                            get_boolean(cobject, "is_holdout");
314         uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY;
315
316         if(b_parent.ptr.data != b_ob.ptr.data) {
317                 visibility &= object_ray_visibility(b_parent);
318         }
319
320         /* Make holdout objects on excluded layer invisible for non-camera rays. */
321         if(use_holdout && (layer_flag & render_layer.exclude_layer)) {
322                 visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA);
323         }
324
325         /* Hide objects not on render layer from camera rays. */
326         if(!(layer_flag & render_layer.layer)) {
327                 visibility &= ~PATH_RAY_CAMERA;
328         }
329
330         /* Don't export completely invisible objects. */
331         if(visibility == 0) {
332                 return NULL;
333         }
334
335         /* key to lookup object */
336         ObjectKey key(b_parent, persistent_id, b_ob);
337         Object *object;
338
339         /* motion vector case */
340         if(motion) {
341                 object = object_map.find(key);
342
343                 if(object && object->use_motion()) {
344                         /* Set transform at matching motion time step. */
345                         int time_index = object->motion_step(motion_time);
346                         if(time_index >= 0) {
347                                 object->motion[time_index] = tfm;
348                         }
349
350                         /* mesh deformation */
351                         if(object->mesh)
352                                 sync_mesh_motion(b_ob, object, motion_time);
353                 }
354
355                 return object;
356         }
357
358         /* test if we need to sync */
359         bool object_updated = false;
360
361         if(object_map.sync(&object, b_ob, b_parent, key))
362                 object_updated = true;
363
364         /* mesh sync */
365         object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
366
367         /* special case not tracked by object update flags */
368
369         /* holdout */
370         if(use_holdout != object->use_holdout) {
371                 object->use_holdout = use_holdout;
372                 scene->object_manager->tag_update(scene);
373                 object_updated = true;
374         }
375
376         if(visibility != object->visibility) {
377                 object->visibility = visibility;
378                 object_updated = true;
379         }
380
381         bool is_shadow_catcher = get_boolean(cobject, "is_shadow_catcher");
382         if(is_shadow_catcher != object->is_shadow_catcher) {
383                 object->is_shadow_catcher = is_shadow_catcher;
384                 object_updated = true;
385         }
386
387         /* sync the asset name for Cryptomatte */
388         BL::Object parent = b_ob.parent();
389         ustring parent_name;
390         if(parent) {
391                 while(parent.parent()) {
392                         parent = parent.parent();
393                 }
394                 parent_name = parent.name();
395         }
396         else {
397                 parent_name = b_ob.name();
398         }
399         if(object->asset_name != parent_name) {
400                 object->asset_name = parent_name;
401                 object_updated = true;
402         }
403
404         /* object sync
405          * transform comparison should not be needed, but duplis don't work perfect
406          * in the depsgraph and may not signal changes, so this is a workaround */
407         if(object_updated || (object->mesh && object->mesh->need_update) || tfm != object->tfm) {
408                 object->name = b_ob.name().c_str();
409                 object->pass_id = b_ob.pass_index();
410                 object->tfm = tfm;
411                 object->motion.clear();
412
413                 /* motion blur */
414                 Scene::MotionType need_motion = scene->need_motion();
415                 if(need_motion != Scene::MOTION_NONE && object->mesh) {
416                         Mesh *mesh = object->mesh;
417                         mesh->use_motion_blur = false;
418                         mesh->motion_steps = 0;
419
420                         uint motion_steps;
421
422                         if(scene->need_motion() == Scene::MOTION_BLUR) {
423                                 motion_steps = object_motion_steps(b_parent, b_ob);
424                                 mesh->motion_steps = motion_steps;
425                                 if(motion_steps && object_use_deform_motion(b_parent, b_ob)) {
426                                         mesh->use_motion_blur = true;
427                                 }
428                         }
429                         else {
430                                 motion_steps = 3;
431                                 mesh->motion_steps = motion_steps;
432                         }
433
434                         object->motion.clear();
435                         object->motion.resize(motion_steps, transform_empty());
436
437                         if(motion_steps) {
438                                 object->motion[motion_steps/2] = tfm;
439
440                                 for(size_t step = 0; step < motion_steps; step++) {
441                                         motion_times.insert(object->motion_time(step));
442                                 }
443                         }
444                 }
445
446                 /* dupli texture coordinates and random_id */
447                 if(b_dupli_ob) {
448                         object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f);
449                         object->dupli_uv = get_float2(b_dupli_ob.uv());
450                         object->random_id = b_dupli_ob.random_id();
451                 }
452                 else {
453                         object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f);
454                         object->dupli_uv = make_float2(0.0f, 0.0f);
455                         object->random_id =  hash_int_2d(hash_string(object->name.c_str()), 0);
456                 }
457
458                 object->tag_update(scene);
459         }
460
461         return object;
462 }
463
464 static bool object_render_hide_original(BL::Object::type_enum ob_type,
465                                         BL::Object::dupli_type_enum dupli_type)
466 {
467         /* metaball exception, they duplicate self */
468         if(ob_type == BL::Object::type_META)
469                 return false;
470
471         return (dupli_type == BL::Object::dupli_type_VERTS ||
472                 dupli_type == BL::Object::dupli_type_FACES ||
473                 dupli_type == BL::Object::dupli_type_FRAMES);
474 }
475
476 static bool object_render_hide(BL::Object& b_ob,
477                                bool top_level,
478                                bool parent_hide,
479                                bool& hide_triangles)
480 {
481         /* check if we should render or hide particle emitter */
482         BL::Object::particle_systems_iterator b_psys;
483
484         bool hair_present = false;
485         bool show_emitter = false;
486         bool hide_emitter = false;
487         bool hide_as_dupli_parent = false;
488         bool hide_as_dupli_child_original = false;
489
490         for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) {
491                 if((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) &&
492                    (b_psys->settings().type()==BL::ParticleSettings::type_HAIR))
493                         hair_present = true;
494
495                 if(b_psys->settings().use_render_emitter())
496                         show_emitter = true;
497                 else
498                         hide_emitter = true;
499         }
500
501         if(show_emitter)
502                 hide_emitter = false;
503
504         /* duplicators hidden by default, except dupliframes which duplicate self */
505         if(b_ob.is_duplicator())
506                 if(top_level || b_ob.dupli_type() != BL::Object::dupli_type_FRAMES)
507                         hide_as_dupli_parent = true;
508
509         /* hide original object for duplis */
510         BL::Object parent = b_ob.parent();
511         while(parent) {
512                 if(object_render_hide_original(b_ob.type(),
513                                                parent.dupli_type()))
514                 {
515                         if(parent_hide) {
516                                 hide_as_dupli_child_original = true;
517                                 break;
518                         }
519                 }
520                 parent = parent.parent();
521         }
522
523         hide_triangles = hide_emitter;
524
525         if(show_emitter) {
526                 return false;
527         }
528         else if(hair_present) {
529                 return hide_as_dupli_child_original;
530         }
531         else {
532                 return (hide_as_dupli_parent || hide_as_dupli_child_original);
533         }
534 }
535
536 static bool object_render_hide_duplis(BL::Object& b_ob)
537 {
538         BL::Object parent = b_ob.parent();
539
540         return (parent && object_render_hide_original(b_ob.type(), parent.dupli_type()));
541 }
542
543 /* Object Loop */
544
545 void BlenderSync::sync_objects(float motion_time)
546 {
547         /* layer data */
548         uint scene_layer = render_layer.scene_layer;
549         bool motion = motion_time != 0.0f;
550
551         if(!motion) {
552                 /* prepare for sync */
553                 light_map.pre_sync();
554                 mesh_map.pre_sync();
555                 object_map.pre_sync();
556                 particle_system_map.pre_sync();
557                 motion_times.clear();
558         }
559         else {
560                 mesh_motion_synced.clear();
561         }
562
563         /* initialize culling */
564         BlenderObjectCulling culling(scene, b_scene);
565
566         /* object loop */
567         BL::Scene::object_bases_iterator b_base;
568         BL::Scene b_sce = b_scene;
569         /* modifier result type (not exposed as enum in C++ API)
570          * 1 : DAG_EVAL_PREVIEW
571          * 2 : DAG_EVAL_RENDER
572          */
573         int dupli_settings = (render_layer.use_viewport_visibility) ? 1 : 2;
574
575         bool cancel = false;
576         bool use_portal = false;
577
578         uint layer_override = get_layer(b_engine.layer_override());
579         for(; b_sce && !cancel; b_sce = b_sce.background_set()) {
580                 /* Render layer's scene_layer is affected by local view already,
581                  * which is not a desired behavior here.
582                  */
583                 uint scene_layers = layer_override ? layer_override : get_layer(b_scene.layers());
584                 for(b_sce.object_bases.begin(b_base); b_base != b_sce.object_bases.end() && !cancel; ++b_base) {
585                         BL::Object b_ob = b_base->object();
586                         bool hide = (render_layer.use_viewport_visibility)? b_ob.hide(): b_ob.hide_render();
587                         uint ob_layer = get_layer(b_base->layers(),
588                                                   b_base->layers_local_view(),
589                                                   object_is_light(b_ob),
590                                                   scene_layers);
591                         hide = hide || !(ob_layer & scene_layer);
592
593                         if(!hide) {
594                                 progress.set_sync_status("Synchronizing object", b_ob.name());
595
596                                 /* load per-object culling data */
597                                 culling.init_object(scene, b_ob);
598
599                                 if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) {
600                                         /* dupli objects */
601                                         b_ob.dupli_list_create(b_data, b_scene, dupli_settings);
602
603                                         BL::Object::dupli_list_iterator b_dup;
604
605                                         for(b_ob.dupli_list.begin(b_dup); b_dup != b_ob.dupli_list.end(); ++b_dup) {
606                                                 Transform tfm = get_transform(b_dup->matrix());
607                                                 BL::Object b_dup_ob = b_dup->object();
608                                                 bool dup_hide = (render_layer.use_viewport_visibility)? b_dup_ob.hide(): b_dup_ob.hide_render();
609                                                 bool in_dupli_group = (b_dup->type() == BL::DupliObject::type_GROUP);
610                                                 bool hide_tris;
611
612                                                 if(!(b_dup->hide() || dup_hide || object_render_hide(b_dup_ob, false, in_dupli_group, hide_tris))) {
613                                                         /* the persistent_id allows us to match dupli objects
614                                                          * between frames and updates */
615                                                         BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
616
617                                                         /* sync object and mesh or light data */
618                                                         Object *object = sync_object(b_ob,
619                                                                                      persistent_id.data,
620                                                                                      *b_dup,
621                                                                                      tfm,
622                                                                                      ob_layer,
623                                                                                      motion_time,
624                                                                                      hide_tris,
625                                                                                      culling,
626                                                                                      &use_portal);
627
628                                                         /* sync possible particle data, note particle_id
629                                                          * starts counting at 1, first is dummy particle */
630                                                         if(!motion && object) {
631                                                                 sync_dupli_particle(b_ob, *b_dup, object);
632                                                         }
633
634                                                 }
635                                         }
636
637                                         b_ob.dupli_list_clear();
638                                 }
639
640                                 /* test if object needs to be hidden */
641                                 bool hide_tris;
642
643                                 if(!object_render_hide(b_ob, true, true, hide_tris)) {
644                                         /* object itself */
645                                         Transform tfm = get_transform(b_ob.matrix_world());
646                                         BL::DupliObject b_empty_dupli_ob(PointerRNA_NULL);
647                                         sync_object(b_ob,
648                                                     NULL,
649                                                     b_empty_dupli_ob,
650                                                     tfm,
651                                                     ob_layer,
652                                                     motion_time,
653                                                     hide_tris,
654                                                     culling,
655                                                     &use_portal);
656                                 }
657                         }
658
659                         cancel = progress.get_cancel();
660                 }
661         }
662
663         progress.set_sync_status("");
664
665         if(!cancel && !motion) {
666                 sync_background_light(use_portal);
667
668                 /* handle removed data and modified pointers */
669                 if(light_map.post_sync())
670                         scene->light_manager->tag_update(scene);
671                 if(mesh_map.post_sync())
672                         scene->mesh_manager->tag_update(scene);
673                 if(object_map.post_sync())
674                         scene->object_manager->tag_update(scene);
675                 if(particle_system_map.post_sync())
676                         scene->particle_system_manager->tag_update(scene);
677         }
678
679         if(motion)
680                 mesh_motion_synced.clear();
681 }
682
683 void BlenderSync::sync_motion(BL::RenderSettings& b_render,
684                               BL::Object& b_override,
685                               int width, int height,
686                               void **python_thread_state)
687 {
688         if(scene->need_motion() == Scene::MOTION_NONE)
689                 return;
690
691         /* get camera object here to deal with camera switch */
692         BL::Object b_cam = b_scene.camera();
693         if(b_override)
694                 b_cam = b_override;
695
696         Camera prevcam = *(scene->camera);
697
698         int frame_center = b_scene.frame_current();
699         float subframe_center = b_scene.frame_subframe();
700         float frame_center_delta = 0.0f;
701
702         if(scene->need_motion() != Scene::MOTION_PASS &&
703            scene->camera->motion_position != Camera::MOTION_POSITION_CENTER)
704         {
705                 float shuttertime = scene->camera->shuttertime;
706                 if(scene->camera->motion_position == Camera::MOTION_POSITION_END) {
707                         frame_center_delta = -shuttertime * 0.5f;
708                 }
709                 else {
710                         assert(scene->camera->motion_position == Camera::MOTION_POSITION_START);
711                         frame_center_delta = shuttertime * 0.5f;
712                 }
713                 float time = frame_center + subframe_center + frame_center_delta;
714                 int frame = (int)floorf(time);
715                 float subframe = time - frame;
716                 python_thread_state_restore(python_thread_state);
717                 b_engine.frame_set(frame, subframe);
718                 python_thread_state_save(python_thread_state);
719                 sync_camera_motion(b_render, b_cam, width, height, 0.0f);
720                 sync_objects(0.0f);
721         }
722
723         /* always sample these times for camera motion */
724         motion_times.insert(-1.0f);
725         motion_times.insert(1.0f);
726
727         /* note iteration over motion_times set happens in sorted order */
728         foreach(float relative_time, motion_times) {
729                 /* center time is already handled. */
730                 if(relative_time == 0.0f) {
731                         continue;
732                 }
733
734                 VLOG(1) << "Synchronizing motion for the relative time "
735                         << relative_time << ".";
736
737                 /* fixed shutter time to get previous and next frame for motion pass */
738                 float shuttertime = scene->motion_shutter_time();
739
740                 /* compute frame and subframe time */
741                 float time = frame_center + subframe_center + frame_center_delta + relative_time * shuttertime * 0.5f;
742                 int frame = (int)floorf(time);
743                 float subframe = time - frame;
744
745                 /* change frame */
746                 python_thread_state_restore(python_thread_state);
747                 b_engine.frame_set(frame, subframe);
748                 python_thread_state_save(python_thread_state);
749
750                 /* sync camera, only supports two times at the moment */
751                 if(relative_time == -1.0f || relative_time == 1.0f) {
752                         sync_camera_motion(b_render,
753                                            b_cam,
754                                            width, height,
755                                            relative_time);
756                 }
757
758                 /* sync object */
759                 sync_objects(relative_time);
760         }
761
762         /* we need to set the python thread state again because this
763          * function assumes it is being executed from python and will
764          * try to save the thread state */
765         python_thread_state_restore(python_thread_state);
766         b_engine.frame_set(frame_center, subframe_center);
767         python_thread_state_save(python_thread_state);
768
769         /* tag camera for motion update */
770         if(scene->camera->motion_modified(prevcam))
771                 scene->camera->tag_update();
772 }
773
774 CCL_NAMESPACE_END