2 * Copyright 2011, Blender Foundation.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include "blender_sync.h"
29 #include "blender_util.h"
31 #include "util_foreach.h"
32 #include "util_hash.h"
38 bool BlenderSync::BKE_object_is_modified(BL::Object b_ob)
40 /* test if we can instance or if the object is modified */
41 if(ccl::BKE_object_is_modified(b_ob, b_scene, preview)) {
46 /* object level material links */
47 BL::Object::material_slots_iterator slot;
48 for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
49 if(slot->link() == BL::MaterialSlot::link_OBJECT)
56 bool BlenderSync::object_is_mesh(BL::Object b_ob)
58 BL::ID b_ob_data = b_ob.data();
60 return (b_ob_data && (b_ob_data.is_a(&RNA_Mesh) ||
61 b_ob_data.is_a(&RNA_Curve) || b_ob_data.is_a(&RNA_MetaBall)));
64 bool BlenderSync::object_is_light(BL::Object b_ob)
66 BL::ID b_ob_data = b_ob.data();
68 return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
71 static uint object_ray_visibility(BL::Object b_ob)
73 PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
76 flag |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0;
77 flag |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0;
78 flag |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0;
79 flag |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0;
80 flag |= get_boolean(cvisibility, "shadow")? PATH_RAY_SHADOW: 0;
87 void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm)
89 /* test if we need to sync */
91 ObjectKey key(b_parent, b_index, b_ob);
93 if(!light_map.sync(&light, b_ob, b_parent, key))
96 BL::Lamp b_lamp(b_ob.data());
99 switch(b_lamp.type()) {
100 case BL::Lamp::type_POINT: {
101 BL::PointLamp b_point_lamp(b_lamp);
102 light->size = b_point_lamp.shadow_soft_size();
103 light->type = LIGHT_POINT;
106 case BL::Lamp::type_SPOT: {
107 BL::SpotLamp b_spot_lamp(b_lamp);
108 light->size = b_spot_lamp.shadow_soft_size();
109 light->type = LIGHT_SPOT;
110 light->spot_angle = b_spot_lamp.spot_size();
111 light->spot_smooth = b_spot_lamp.spot_blend();
114 case BL::Lamp::type_HEMI: {
115 light->type = LIGHT_DISTANT;
119 case BL::Lamp::type_SUN: {
120 BL::SunLamp b_sun_lamp(b_lamp);
121 light->size = b_sun_lamp.shadow_soft_size();
122 light->type = LIGHT_DISTANT;
125 case BL::Lamp::type_AREA: {
126 BL::AreaLamp b_area_lamp(b_lamp);
128 light->axisu = make_float3(tfm.x.x, tfm.y.x, tfm.z.x);
129 light->axisv = make_float3(tfm.x.y, tfm.y.y, tfm.z.y);
130 light->sizeu = b_area_lamp.size();
131 if(b_area_lamp.shape() == BL::AreaLamp::shape_RECTANGLE)
132 light->sizev = b_area_lamp.size_y();
134 light->sizev = light->sizeu;
135 light->type = LIGHT_AREA;
140 /* location and (inverted!) direction */
141 light->co = make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
142 light->dir = -make_float3(tfm.x.z, tfm.y.z, tfm.z.z);
145 vector<uint> used_shaders;
147 find_shader(b_lamp, used_shaders, scene->default_light);
149 if(used_shaders.size() == 0)
150 used_shaders.push_back(scene->default_light);
152 light->shader = used_shaders[0];
155 PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
156 light->cast_shadow = get_boolean(clamp, "cast_shadow");
157 light->samples = get_int(clamp, "samples");
160 light->tag_update(scene);
163 void BlenderSync::sync_background_light()
165 BL::World b_world = b_scene.world();
168 PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
169 bool sample_as_light = get_boolean(cworld, "sample_as_light");
171 if(sample_as_light) {
172 /* test if we need to sync */
174 ObjectKey key(b_world, 0, b_world);
176 if(light_map.sync(&light, b_world, b_world, key) ||
178 b_world.ptr.data != world_map)
180 light->type = LIGHT_BACKGROUND;
181 light->map_resolution = get_int(cworld, "sample_map_resolution");
182 light->samples = get_int(cworld, "samples");
183 light->shader = scene->default_background;
185 light->tag_update(scene);
186 light_map.set_recalc(b_world);
191 world_map = b_world.ptr.data;
192 world_recalc = false;
197 void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint layer_flag, int motion, int particle_id)
199 /* light is handled separately */
200 if(object_is_light(b_ob)) {
202 sync_light(b_parent, b_index, b_ob, tfm);
206 /* only interested in object that we can create meshes from */
207 if(!object_is_mesh(b_ob))
210 /* key to lookup object */
211 ObjectKey key(b_parent, b_index, b_ob);
214 /* motion vector case */
216 object = object_map.find(key);
219 if(tfm != object->tfm) {
221 object->motion.pre = tfm;
223 object->motion.post = tfm;
225 object->use_motion = true;
228 sync_mesh_motion(b_ob, object->mesh, motion);
234 /* test if we need to sync */
235 bool object_updated = false;
237 if(object_map.sync(&object, b_ob, b_parent, key))
238 object_updated = true;
240 bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
243 object->mesh = sync_mesh(b_ob, object_updated);
245 if(use_holdout != object->use_holdout) {
246 object->use_holdout = use_holdout;
247 scene->object_manager->tag_update(scene);
251 /* transform comparison should not be needed, but duplis don't work perfect
252 * in the depsgraph and may not signal changes, so this is a workaround */
253 if(object_updated || (object->mesh && object->mesh->need_update) || tfm != object->tfm) {
254 object->name = b_ob.name().c_str();
255 object->pass_id = b_ob.pass_index();
257 object->motion.pre = tfm;
258 object->motion.post = tfm;
259 object->use_motion = false;
261 object->random_id = hash_int_2d(hash_string(object->name.c_str()), b_index);
263 /* visibility flags for both parent */
264 object->visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL;
265 if(b_parent.ptr.data != b_ob.ptr.data) {
266 object->visibility &= object_ray_visibility(b_parent);
267 object->random_id ^= hash_int(hash_string(b_parent.name().c_str()));
270 /* camera flag is not actually used, instead is tested
271 * against render layer flags */
272 if(object->visibility & PATH_RAY_CAMERA) {
273 object->visibility |= layer_flag << PATH_RAY_LAYER_SHIFT;
274 object->visibility &= ~PATH_RAY_CAMERA;
277 object->particle_id = particle_id;
279 object->tag_update(scene);
285 void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
288 uint scene_layer = render_layer.scene_layer;
291 /* prepare for sync */
292 light_map.pre_sync();
294 object_map.pre_sync();
299 BL::Scene::objects_iterator b_ob;
300 BL::Scene b_sce = b_scene;
301 int particle_offset = 1; /* first particle is dummy for regular, non-instanced objects */
305 for(; b_sce && !cancel; b_sce = b_sce.background_set()) {
306 for(b_sce.objects.begin(b_ob); b_ob != b_sce.objects.end() && !cancel; ++b_ob) {
307 bool hide = (render_layer.use_viewport_visibility)? b_ob->hide(): b_ob->hide_render();
308 uint ob_layer = get_layer(b_ob->layers(), b_ob->layers_local_view(), render_layer.use_localview, object_is_light(*b_ob));
309 hide = hide || !(ob_layer & scene_layer);
312 progress.set_status("Synchronizing object", (*b_ob).name());
314 int num_particles = object_count_particles(*b_ob);
316 if(b_ob->is_duplicator()) {
317 hide = true; /* duplicators hidden by default */
320 object_create_duplilist(*b_ob, b_scene);
322 BL::Object::dupli_list_iterator b_dup;
325 for(b_ob->dupli_list.begin(b_dup); b_dup != b_ob->dupli_list.end(); ++b_dup) {
326 Transform tfm = get_transform(b_dup->matrix());
327 BL::Object b_dup_ob = b_dup->object();
328 bool dup_hide = (b_v3d)? b_dup_ob.hide(): b_dup_ob.hide_render();
330 if(!(b_dup->hide() || dup_hide)) {
331 sync_object(*b_ob, b_index, b_dup_ob, tfm, ob_layer, motion, b_dup->particle_index() + particle_offset);
337 object_free_duplilist(*b_ob);
340 /* check if we should render or hide particle emitter */
341 BL::Object::particle_systems_iterator b_psys;
342 for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
343 if(b_psys->settings().use_render_emitter())
348 Transform tfm = get_transform(b_ob->matrix_world());
349 sync_object(*b_ob, 0, *b_ob, tfm, ob_layer, motion, 0);
352 particle_offset += num_particles;
355 cancel = progress.get_cancel();
359 if(!cancel && !motion) {
360 sync_background_light();
362 /* handle removed data and modified pointers */
363 if(light_map.post_sync())
364 scene->light_manager->tag_update(scene);
365 if(mesh_map.post_sync())
366 scene->mesh_manager->tag_update(scene);
367 if(object_map.post_sync())
368 scene->object_manager->tag_update(scene);
373 void BlenderSync::sync_motion(BL::SpaceView3D b_v3d, BL::Object b_override)
375 if(scene->need_motion() == Scene::MOTION_NONE)
378 /* get camera object here to deal with camera switch */
379 BL::Object b_cam = b_scene.camera();
383 /* go back and forth one frame */
384 int frame = b_scene.frame_current();
386 for(int motion = -1; motion <= 1; motion += 2) {
387 scene_frame_set(b_scene, frame + motion);
391 sync_camera_motion(b_cam, motion);
394 sync_objects(b_v3d, motion);
397 scene_frame_set(b_scene, frame);