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, 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<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(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(Shader *shader, mesh->used_shaders) if(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 */ array<int> 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*/ array<float3> oldcurve_keys = mesh->curve_keys; array<float> oldcurve_radius = 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) { /* 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); mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental); BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed, mesh->subdivision_type); if(b_mesh) { if(render_layer.use_surfaces && !hide_tris) { 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()); } if(render_layer.use_hair && mesh->subdivision_type == Mesh::SUBDIVISION_NONE) 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, false); } } mesh->geometry_flags = requested_geometry_flags; /* fluid motion */ sync_mesh_fluid_motion(b_ob, scene, mesh); /* 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(int)*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(float3)*oldcurve_keys.size()) != 0) rebuild = true; } if(oldcurve_radius.size() != mesh->curve_radius.size()) rebuild = true; else if(oldcurve_radius.size()) { if(memcmp(&oldcurve_radius[0], &mesh->curve_radius[0], sizeof(float)*oldcurve_radius.size()) != 0) rebuild = true; } mesh->tag_update(scene, rebuild); return mesh; }