static int rna_Object_is_modified(Object *ob, Scene *scene, int settings) { return BKE_object_is_modified(scene, ob) & settings; }
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; }
void BlenderSync::sync_curve_settings() { PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves"); CurveSystemManager *curve_system_manager = scene->curve_system_manager; CurveSystemManager prev_curve_system_manager = *curve_system_manager; curve_system_manager->use_curves = get_boolean(csscene, "use_curves"); curve_system_manager->primitive = (CurvePrimitiveType)get_enum( csscene, "primitive", CURVE_NUM_PRIMITIVE_TYPES, CURVE_LINE_SEGMENTS); curve_system_manager->curve_shape = (CurveShapeType)get_enum( csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK); curve_system_manager->resolution = get_int(csscene, "resolution"); curve_system_manager->subdivisions = get_int(csscene, "subdivisions"); curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing"); /* Triangles */ if (curve_system_manager->primitive == CURVE_TRIANGLES) { /* camera facing planes */ if (curve_system_manager->curve_shape == CURVE_RIBBON) { curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES; curve_system_manager->resolution = 1; } else if (curve_system_manager->curve_shape == CURVE_THICK) { curve_system_manager->triangle_method = CURVE_TESSELATED_TRIANGLES; } } /* Line Segments */ else if (curve_system_manager->primitive == CURVE_LINE_SEGMENTS) { if (curve_system_manager->curve_shape == CURVE_RIBBON) { /* tangent shading */ curve_system_manager->line_method = CURVE_UNCORRECTED; curve_system_manager->use_encasing = true; curve_system_manager->use_backfacing = false; curve_system_manager->use_tangent_normal_geometry = true; } else if (curve_system_manager->curve_shape == CURVE_THICK) { curve_system_manager->line_method = CURVE_ACCURATE; curve_system_manager->use_encasing = false; curve_system_manager->use_tangent_normal_geometry = false; } } /* Curve Segments */ else if (curve_system_manager->primitive == CURVE_SEGMENTS) { if (curve_system_manager->curve_shape == CURVE_RIBBON) { curve_system_manager->primitive = CURVE_RIBBONS; curve_system_manager->use_backfacing = false; } } if (curve_system_manager->modified_mesh(prev_curve_system_manager)) { BL::BlendData::objects_iterator b_ob; for (b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) { if (object_is_mesh(*b_ob)) { BL::Object::particle_systems_iterator b_psys; for (b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) { if ((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) && (b_psys->settings().type() == BL::ParticleSettings::type_HAIR)) { BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data(); mesh_map.set_recalc(key); object_map.set_recalc(*b_ob); } } } } } if (curve_system_manager->modified(prev_curve_system_manager)) curve_system_manager->tag_update(scene); }
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; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Sync recalc flags from blender to OctaneRender. Actual update is done separate, // so we can do it later on if doing it immediate is not suitable. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool BlenderSync::sync_recalc() { BL::BlendData::materials_iterator b_mat; for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) if(b_mat->is_updated() || (b_mat->node_tree() && b_mat->node_tree().is_updated())) shader_map.set_recalc(*b_mat); //FIXME: Perhaps not needed... BL::BlendData::textures_iterator b_tex; for(b_data.textures.begin(b_tex); b_tex != b_data.textures.end(); ++b_tex) if(b_tex->is_updated() || (b_tex->node_tree() && b_tex->node_tree().is_updated())) shader_map.set_recalc(*b_tex); BL::BlendData::lamps_iterator b_lamp; for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp) if(b_lamp->is_updated() || (b_lamp->node_tree() && b_lamp->node_tree().is_updated())) shader_map.set_recalc(*b_lamp); BL::BlendData::objects_iterator b_ob; for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) { if(b_ob->is_updated()) { if(object_is_light(*b_ob)) light_object_map.set_recalc(*b_ob); else object_map.set_recalc(*b_ob); } BL::SmokeDomainSettings b_domain = BlenderSync::object_smoke_domain_find(*b_ob); if(b_domain && b_domain.cache_file_format() == BL::SmokeDomainSettings::cache_file_format_OPENVDB) { // Workaround, smoke is not tagged for update by BKE_scene_update_for_newframe() bool is_export = scene->session->b_session && scene->session->b_session->export_type != ::OctaneEngine::OctaneClient::SceneExportTypes::NONE; BL::ID b_ob_data = b_ob->data(); PointerRNA oct_mesh = RNA_pointer_get(&b_ob_data.ptr, "octane"); bool is_reshapable = scene->meshes_type == Mesh::RESHAPABLE_PROXY || (scene->meshes_type == Mesh::AS_IS && static_cast<Mesh::MeshType>(RNA_enum_get(&oct_mesh, "mesh_type")) == Mesh::RESHAPABLE_PROXY); if(is_export) { BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data(); mesh_map.set_recalc(key); } else if((interactive && is_reshapable) || (!interactive && (scene->anim_mode == FULL || (scene->anim_mode == MOVABLE_PROXIES && is_reshapable)))) { BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data(); mesh_map.set_recalc(key); } } else if(object_is_curve(*b_ob)) { // Workaround, curves are not tagged for update by BKE_scene_update_for_newframe() if(b_ob->is_updated_data() || b_ob->data().is_updated()) { BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data(); mesh_map.set_recalc(key); } else { bool is_export = scene->session->b_session && scene->session->b_session->export_type != ::OctaneEngine::OctaneClient::SceneExportTypes::NONE; BL::ID b_ob_data = b_ob->data(); PointerRNA oct_mesh = RNA_pointer_get(&b_ob_data.ptr, "octane"); bool is_reshapable = scene->meshes_type == Mesh::RESHAPABLE_PROXY || (scene->meshes_type == Mesh::AS_IS && static_cast<Mesh::MeshType>(RNA_enum_get(&oct_mesh, "mesh_type")) == Mesh::RESHAPABLE_PROXY); if(is_export) { BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data(); mesh_map.set_recalc(key); } else if((interactive && is_reshapable) || (!interactive && (scene->anim_mode == FULL || (scene->anim_mode == MOVABLE_PROXIES && is_reshapable)))) { BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data(); mesh_map.set_recalc(key); } } } else if(object_is_mesh(*b_ob)) { if(b_ob->is_updated_data() || b_ob->data().is_updated()) { BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data(); mesh_map.set_recalc(key); } else if(!interactive && BKE_object_is_modified(*b_ob)) { // Workaround, some modified meshes are not tagged for update by BKE_scene_update_for_newframe() bool is_export = scene->session->b_session && scene->session->b_session->export_type != ::OctaneEngine::OctaneClient::SceneExportTypes::NONE; BL::ID b_ob_data = b_ob->data(); PointerRNA oct_mesh = RNA_pointer_get(&b_ob_data.ptr, "octane"); bool is_reshapable = scene->meshes_type == Mesh::RESHAPABLE_PROXY || (scene->meshes_type == Mesh::AS_IS && static_cast<Mesh::MeshType>(RNA_enum_get(&oct_mesh, "mesh_type")) == Mesh::RESHAPABLE_PROXY); if(is_export) { BL::ID key = *b_ob; mesh_map.set_recalc(key); } else if(scene->anim_mode == FULL || (scene->anim_mode == MOVABLE_PROXIES && is_reshapable)) { BL::ID key = *b_ob; mesh_map.set_recalc(key); } } } else if(object_is_light(*b_ob)) { if(b_ob->is_updated_data() || b_ob->data().is_updated()) light_map.set_recalc(b_ob->data()); } } //BL::BlendData::meshes_iterator b_mesh; //for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh) // if(b_mesh->is_updated() || b_mesh->is_updated_data()) // mesh_map.set_recalc(*b_mesh); BL::BlendData::worlds_iterator b_world; for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world) { if(world_map == b_world->ptr.data && (b_world->is_updated() || (b_world->node_tree() && b_world->node_tree().is_updated()))) { world_recalc = true; } } bool recalc = shader_map.has_recalc() || object_map.has_recalc() || light_map.has_recalc() || mesh_map.has_recalc() || BlendDataObjects_is_updated_get(&b_data.ptr) || world_recalc; return recalc; } //sync_recalc()