CCL_NAMESPACE_BEGIN /* Utilities */ bool BlenderSync::BKE_object_is_modified(BL::Object& b_ob) { /* test if we can instance or if the object is modified */ if(b_ob.type() == BL::Object::type_META) { /* multi-user and dupli metaballs are fused, can't instance */ return true; } else if(ccl::BKE_object_is_modified(b_ob, b_scene, preview)) { /* modifiers */ return true; } else { /* object level material links */ BL::Object::material_slots_iterator slot; for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) if(slot->link() == BL::MaterialSlot::link_OBJECT) return true; } return false; }
Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph, BL::Object &b_ob, BL::Object &b_ob_instance, bool object_updated, bool show_self, bool show_particles) { /* test if we can instance or if the object is modified */ BL::ID b_ob_data = b_ob.data(); BL::ID key = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data; BL::Material material_override = view_layer.material_override; /* find shader indices */ vector<Shader *> used_shaders; BL::Object::material_slots_iterator slot; for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { if (material_override) { find_shader(material_override, used_shaders, scene->default_surface); } else { BL::ID b_material(slot->material()); find_shader(b_material, used_shaders, scene->default_surface); } } if (used_shaders.size() == 0) { if (material_override) find_shader(material_override, used_shaders, scene->default_surface); else used_shaders.push_back(scene->default_surface); } /* test if we need to sync */ int requested_geometry_flags = Mesh::GEOMETRY_NONE; if (view_layer.use_surfaces) { requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES; } if (view_layer.use_hair) { requested_geometry_flags |= Mesh::GEOMETRY_CURVES; } Mesh *mesh; if (!mesh_map.sync(&mesh, key)) { /* if transform was applied to mesh, need full update */ if (object_updated && mesh->transform_applied) ; /* test if shaders changed, these can be object level so mesh * does not get tagged for recalc */ else if (mesh->used_shaders != used_shaders) ; else if (requested_geometry_flags != mesh->geometry_flags) ; else { /* even if not tagged for recalc, we may need to sync anyway * because the shader needs different mesh attributes */ bool attribute_recalc = false; foreach (Shader *shader, mesh->used_shaders) if (shader->need_update_mesh) attribute_recalc = true; if (!attribute_recalc) return mesh; } } /* ensure we only sync instanced meshes once */ if (mesh_synced.find(mesh) != mesh_synced.end()) return mesh; progress.set_sync_status("Synchronizing object", b_ob.name()); mesh_synced.insert(mesh); /* create derived mesh */ array<int> oldtriangles; array<Mesh::SubdFace> oldsubd_faces; array<int> oldsubd_face_corners; oldtriangles.steal_data(mesh->triangles); oldsubd_faces.steal_data(mesh->subd_faces); oldsubd_face_corners.steal_data(mesh->subd_face_corners); /* compares curve_keys rather than strands in order to handle quick hair * adjustments in dynamic BVH - other methods could probably do this better*/ array<float3> oldcurve_keys; array<float> oldcurve_radius; oldcurve_keys.steal_data(mesh->curve_keys); oldcurve_radius.steal_data(mesh->curve_radius); mesh->clear(); mesh->used_shaders = used_shaders; mesh->name = ustring(b_ob_data.name().c_str()); if (requested_geometry_flags != Mesh::GEOMETRY_NONE) { /* Adaptive subdivision setup. Not for baking since that requires * exact mapping to the Blender mesh. */ if (scene->bake_manager->get_baking()) { mesh->subdivision_type = Mesh::SUBDIVISION_NONE; } else { mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental); } /* For some reason, meshes do not need this... */ bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); BL::Mesh b_mesh = object_to_mesh( b_data, b_ob, b_depsgraph, need_undeformed, mesh->subdivision_type); if (b_mesh) { /* Sync mesh itself. */ if (view_layer.use_surfaces && show_self) { if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions); else create_mesh(scene, mesh, b_mesh, used_shaders, false); create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current()); } /* Sync hair curves. */ if (view_layer.use_hair && show_particles && mesh->subdivision_type == Mesh::SUBDIVISION_NONE) { sync_curves(mesh, b_mesh, b_ob, false); } free_object_to_mesh(b_data, b_ob, b_mesh); } } mesh->geometry_flags = requested_geometry_flags; /* fluid motion */ sync_mesh_fluid_motion(b_ob, scene, mesh); /* tag update */ bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) || (oldsubd_face_corners != mesh->subd_face_corners) || (oldcurve_keys != mesh->curve_keys) || (oldcurve_radius != mesh->curve_radius); mesh->tag_update(scene, rebuild); return mesh; }
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated) { /* test if we can instance or if the object is modified */ BL::ID b_ob_data = b_ob.data(); BL::ID key = (object_is_modified(b_ob))? b_ob: b_ob_data; /* find shader indices */ vector<uint> used_shaders; BL::Object::material_slots_iterator slot; for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { BL::Material material_override = render_layers.front().material_override; if(material_override) find_shader(material_override, used_shaders, scene->default_surface); else find_shader(slot->material(), used_shaders, scene->default_surface); } if(used_shaders.size() == 0) used_shaders.push_back(scene->default_surface); /* test if we need to sync */ Mesh *mesh; if(!mesh_map.sync(&mesh, key)) { /* if transform was applied to mesh, need full update */ if(object_updated && mesh->transform_applied); /* test if shaders changed, these can be object level so mesh does not get tagged for recalc */ else if(mesh->used_shaders != used_shaders); else { /* even if not tagged for recalc, we may need to sync anyway * because the shader needs different mesh attributes */ bool attribute_recalc = false; foreach(uint shader, mesh->used_shaders) if(scene->shaders[shader]->need_update_attributes) attribute_recalc = true; if(!attribute_recalc) return mesh; } } /* ensure we only sync instanced meshes once */ if(mesh_synced.find(mesh) != mesh_synced.end()) return mesh; mesh_synced.insert(mesh); /* create derived mesh */ BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview); PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles"); vector<Mesh::Triangle> oldtriangle = mesh->triangles; mesh->clear(); mesh->used_shaders = used_shaders; mesh->name = ustring(b_ob_data.name().c_str()); if(b_mesh) { if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision")) create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders); else create_mesh(scene, mesh, b_mesh, used_shaders); /* free derived mesh */ object_remove_mesh(b_data, b_mesh); } /* displacement method */ if(cmesh.data) { int method = RNA_enum_get(&cmesh, "displacement_method"); if(method == 0 || !experimental) mesh->displacement_method = Mesh::DISPLACE_BUMP; else if(method == 1) mesh->displacement_method = Mesh::DISPLACE_TRUE; else mesh->displacement_method = Mesh::DISPLACE_BOTH; } /* tag update */ bool rebuild = false; if(oldtriangle.size() != mesh->triangles.size()) rebuild = true; else if(oldtriangle.size()) { if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0) rebuild = true; } mesh->tag_update(scene, rebuild); return mesh; }
Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, bool object_updated, bool hide_tris) { /* When viewport display is not needed during render we can force some * caches to be releases from blender side in order to reduce peak memory * footprint during synchronization process. */ const bool is_interface_locked = b_engine.render() && b_engine.render().use_lock_interface(); const bool can_free_caches = BlenderSession::headless || is_interface_locked; /* test if we can instance or if the object is modified */ BL::ID b_ob_data = b_ob.data(); BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data; BL::Material material_override = render_layer.material_override; /* find shader indices */ vector<uint> used_shaders; BL::Object::material_slots_iterator slot; for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { if(material_override) { find_shader(material_override, used_shaders, scene->default_surface); } else { BL::ID b_material(slot->material()); find_shader(b_material, used_shaders, scene->default_surface); } } if(used_shaders.size() == 0) { if(material_override) find_shader(material_override, used_shaders, scene->default_surface); else used_shaders.push_back(scene->default_surface); } /* test if we need to sync */ int requested_geometry_flags = Mesh::GEOMETRY_NONE; if(render_layer.use_surfaces) { requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES; } if(render_layer.use_hair) { requested_geometry_flags |= Mesh::GEOMETRY_CURVES; } Mesh *mesh; if(!mesh_map.sync(&mesh, key)) { /* if transform was applied to mesh, need full update */ if(object_updated && mesh->transform_applied); /* test if shaders changed, these can be object level so mesh * does not get tagged for recalc */ else if(mesh->used_shaders != used_shaders); else if(requested_geometry_flags != mesh->geometry_flags); else { /* even if not tagged for recalc, we may need to sync anyway * because the shader needs different mesh attributes */ bool attribute_recalc = false; foreach(uint shader, mesh->used_shaders) if(scene->shaders[shader]->need_update_attributes) attribute_recalc = true; if(!attribute_recalc) return mesh; } } /* ensure we only sync instanced meshes once */ if(mesh_synced.find(mesh) != mesh_synced.end()) return mesh; mesh_synced.insert(mesh); /* create derived mesh */ PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles"); vector<Mesh::Triangle> oldtriangle = mesh->triangles; /* compares curve_keys rather than strands in order to handle quick hair * adjustments in dynamic BVH - other methods could probably do this better*/ vector<float4> oldcurve_keys = mesh->curve_keys; mesh->clear(); mesh->used_shaders = used_shaders; mesh->name = ustring(b_ob_data.name().c_str()); if(requested_geometry_flags != Mesh::GEOMETRY_NONE) { /* mesh objects does have special handle in the dependency graph, * they're ensured to have properly updated. * * updating meshes here will end up having derived mesh referencing * freed data from the blender side. */ if(preview && b_ob.type() != BL::Object::type_MESH) b_ob.update_from_editmode(); bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed); if(b_mesh) { if(render_layer.use_surfaces && !hide_tris) { if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision")) create_subd_mesh(scene, mesh, b_mesh, &cmesh, used_shaders); else create_mesh(scene, mesh, b_mesh, used_shaders); create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current()); } if(render_layer.use_hair) sync_curves(mesh, b_mesh, b_ob, false); if(can_free_caches) { b_ob.cache_release(); } /* free derived mesh */ b_data.meshes.remove(b_mesh); } } mesh->geometry_flags = requested_geometry_flags; /* displacement method */ if(cmesh.data) { const int method = get_enum(cmesh, "displacement_method"); if(method == 0 || !experimental) mesh->displacement_method = Mesh::DISPLACE_BUMP; else if(method == 1) mesh->displacement_method = Mesh::DISPLACE_TRUE; else mesh->displacement_method = Mesh::DISPLACE_BOTH; } /* tag update */ bool rebuild = false; if(oldtriangle.size() != mesh->triangles.size()) rebuild = true; else if(oldtriangle.size()) { if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0) rebuild = true; } if(oldcurve_keys.size() != mesh->curve_keys.size()) rebuild = true; else if(oldcurve_keys.size()) { if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0) rebuild = true; } mesh->tag_update(scene, rebuild); return mesh; }
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris) { /* test if we can instance or if the object is modified */ BL::ID b_ob_data = b_ob.data(); BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data; BL::Material material_override = render_layer.material_override; /* find shader indices */ vector<uint> used_shaders; BL::Object::material_slots_iterator slot; for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { if(material_override) find_shader(material_override, used_shaders, scene->default_surface); else find_shader(slot->material(), used_shaders, scene->default_surface); } if(used_shaders.size() == 0) { if(material_override) find_shader(material_override, used_shaders, scene->default_surface); else used_shaders.push_back(scene->default_surface); } /* test if we need to sync */ Mesh *mesh; if(!mesh_map.sync(&mesh, key)) { /* if transform was applied to mesh, need full update */ if(object_updated && mesh->transform_applied); /* test if shaders changed, these can be object level so mesh * does not get tagged for recalc */ else if(mesh->used_shaders != used_shaders); else { /* even if not tagged for recalc, we may need to sync anyway * because the shader needs different mesh attributes */ bool attribute_recalc = false; foreach(uint shader, mesh->used_shaders) if(scene->shaders[shader]->need_update_attributes) attribute_recalc = true; if(!attribute_recalc) return mesh; } } /* ensure we only sync instanced meshes once */ if(mesh_synced.find(mesh) != mesh_synced.end()) return mesh; mesh_synced.insert(mesh); /* create derived mesh */ PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles"); vector<Mesh::Triangle> oldtriangle = mesh->triangles; /* compares curve_keys rather than strands in order to handle quick hair * adjustsments in dynamic BVH - other methods could probably do this better*/ vector<float4> oldcurve_keys = mesh->curve_keys; mesh->clear(); mesh->used_shaders = used_shaders; mesh->name = ustring(b_ob_data.name().c_str()); if(render_layer.use_surfaces || render_layer.use_hair) { if(preview) b_ob.update_from_editmode(); bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed); if(b_mesh) { if(render_layer.use_surfaces && !hide_tris) { if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision")) create_subd_mesh(scene, mesh, b_mesh, &cmesh, used_shaders); else create_mesh(scene, mesh, b_mesh, used_shaders); create_mesh_volume_attributes(scene, b_ob, mesh); } if(render_layer.use_hair) sync_curves(mesh, b_mesh, b_ob, false); /* free derived mesh */ b_data.meshes.remove(b_mesh); } } /* displacement method */ if(cmesh.data) { const int method = RNA_enum_get(&cmesh, "displacement_method"); if(method == 0 || !experimental) mesh->displacement_method = Mesh::DISPLACE_BUMP; else if(method == 1) mesh->displacement_method = Mesh::DISPLACE_TRUE; else mesh->displacement_method = Mesh::DISPLACE_BOTH; } /* tag update */ bool rebuild = false; if(oldtriangle.size() != mesh->triangles.size()) rebuild = true; else if(oldtriangle.size()) { if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0) rebuild = true; } if(oldcurve_keys.size() != mesh->curve_keys.size()) rebuild = true; else if(oldcurve_keys.size()) { if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0) rebuild = true; } mesh->tag_update(scene, rebuild); return mesh; }