diff options
21 files changed, 568 insertions, 383 deletions
diff --git a/doc/python_api/examples/bpy.types.Depsgraph.1.py b/doc/python_api/examples/bpy.types.Depsgraph.1.py new file mode 100644 index 00000000000..d972c076c97 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Depsgraph.1.py @@ -0,0 +1,60 @@ +""" +Dependency graph: Evaluated ID example +++++++++++++++++++++++++++++++++++++++ + +This example demonstrates access to the evaluated ID (such as object, material, etc.) state from +an original ID. +This is needed every time one needs to access state with animation, constraints, and modifiers +taken into account. +""" +import bpy + + +class OBJECT_OT_evaluated_example(bpy.types.Operator): + """Access evaluated object state and do something with it""" + bl_label = "DEG Access Evaluated Object" + bl_idname = "object.evaluated_example" + + def execute(self, context): + # This is an original object. Its data does not have any modifiers applied. + object = context.object + if object is None or object.type != 'MESH': + self.report({'INFO'}, "No active mesh object to get info from") + return {'CANCELLED'} + # Evaluated object exists within a specific dependency graph. + # We will request evaluated object from the dependency graph which corresponds to the + # current scene and view layer. + # + # NOTE: This call ensure the dependency graph is fully evaluated. This might be expensive + # if changes were made made to the scene, but is needed to ensure no dangling or incorrect + # pointers are exposed. + depsgraph = context.evaluated_depsgraph_get() + # Actually request evaluated object. + # + # This object has animation and drivers applied on it, together with constraints and + # modifiers. + # + # For mesh objects the object.data will be a mesh with all modifiers applied. + # This means that in access to vertices or faces after modifier stack happens via fields of + # object_eval.object. + # + # For other types of objects the object_eval.data does not have modifiers applied on it, + # but has animation applied. + # + # NOTE: All ID types have `evaluated_get()`, including materials, node trees, worlds. + object_eval = object.evaluated_get(depsgraph) + mesh_eval = object_eval.data + self.report({'INFO'}, f"Number of evaluated vertices: {len(mesh_eval.vertices)}") + return {'FINISHED'} + + +def register(): + bpy.utils.register_class(OBJECT_OT_evaluated_example) + + +def unregister(): + bpy.utils.unregister_class(OBJECT_OT_evaluated_example) + + +if __name__ == "__main__": + register() diff --git a/doc/python_api/examples/bpy.types.Depsgraph.2.py b/doc/python_api/examples/bpy.types.Depsgraph.2.py new file mode 100644 index 00000000000..8639ffc0267 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Depsgraph.2.py @@ -0,0 +1,45 @@ +""" +Dependency graph: Original object example ++++++++++++++++++++++++++++++++++++++++++ + +This example demonstrates access to the original ID. +Such access is needed to check whether object is selected, or to compare pointers. +""" +import bpy + + +class OBJECT_OT_original_example(bpy.types.Operator): + """Access original object and do something with it""" + bl_label = "DEG Access Original Object" + bl_idname = "object.original_example" + + def check_object_selected(self, object_eval): + # Selection depends on a context and is only valid for original objects. This means we need + # to request the original object from the known evaluated one. + # + # NOTE: All ID types have an `original` field. + object = object_eval.original + return object.select_get() + + def execute(self, context): + # NOTE: It seems redundant to iterate over original objects to request evaluated ones + # just to get original back. But we want to keep example as short as possible, but in real + # world there are cases when evaluated object is coming from a more meaningful source. + depsgraph = context.evaluated_depsgraph_get() + for object in context.editable_objects: + object_eval = object.evaluated_get(depsgraph) + if self.check_object_selected(object_eval): + self.report({'INFO'}, f"Object is selected: {object_eval.name}") + return {'FINISHED'} + + +def register(): + bpy.utils.register_class(OBJECT_OT_original_example) + + +def unregister(): + bpy.utils.unregister_class(OBJECT_OT_original_example) + + +if __name__ == "__main__": + register() diff --git a/doc/python_api/examples/bpy.types.Depsgraph.3.py b/doc/python_api/examples/bpy.types.Depsgraph.3.py new file mode 100644 index 00000000000..25411597dd3 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Depsgraph.3.py @@ -0,0 +1,42 @@ +""" +Dependency graph: Iterate over all object instances ++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Sometimes it is needed to know all the instances with their matrices (for example, when writing an +exporter or a custom render engine). +This example shows how to access all objects and instances in the scene. +""" +import bpy + + +class OBJECT_OT_object_instances(bpy.types.Operator): + """Access original object and do something with it""" + bl_label = "DEG Iterate Object Instances" + bl_idname = "object.object_instances" + + def execute(self, context): + depsgraph = context.evaluated_depsgraph_get() + for object_instance in depsgraph.object_instances: + # This is an object which is being instanced. + object = object_instance.object + # `is_instance` denotes whether the object is coming from instances (as an opposite of + # being an emitting object. ) + if not object_instance.is_instance: + print(f"Object {object.name} at {object_instance.matrix_world}") + else: + # Instanced will additionally have fields like uv, random_id and others which are + # specific for instances. See Python API for DepsgraphObjectInstance for details, + print(f"Instance of {object.name} at {object_instance.matrix_world}") + return {'FINISHED'} + + +def register(): + bpy.utils.register_class(OBJECT_OT_object_instances) + + +def unregister(): + bpy.utils.unregister_class(OBJECT_OT_object_instances) + + +if __name__ == "__main__": + register() diff --git a/doc/python_api/examples/bpy.types.Depsgraph.4.py b/doc/python_api/examples/bpy.types.Depsgraph.4.py new file mode 100644 index 00000000000..5c7b76edab6 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Depsgraph.4.py @@ -0,0 +1,62 @@ +""" +Dependency graph: Object.to_mesh() ++++++++++++++++++++++++++++++++++++ + +Object.to_mesh() (and bpy.data.meshes.new_from_object()) are closely interacting with dependency +graph: their behavior depends on whether they are used on original or evaluated object. + +When is used on original object, the result mesh is calculated from the object without taking +animation or modifiers into account: + +- For meshes this is similar to duplicating the source mesh. +- For curves this disables own modifiers, and modifiers of objects used as bevel and taper. +- For metaballs this produces an empty mesh since polygonization is done as a modifier evaluation. + +When is used on evaluated object all modifiers are taken into account. + +.. note:: The result mesh is added to the main database. +.. note:: If object does not have geometry (i.e. camera) the functions returns None. +""" +import bpy + + +class OBJECT_OT_object_to_mesh(bpy.types.Operator): + """Convert selected object to mesh and show number of vertices""" + bl_label = "DEG Object to Mesh" + bl_idname = "object.object_to_mesh" + + def execute(self, context): + # Access input original object. + object = context.object + if object is None: + self.report({'INFO'}, "No active mesh object to convert to mesh") + return {'CANCELLED'} + # Avoid annoying None checks later on. + if object.type not in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: + self.report({'INFO'}, "Object can not be converted to mesh") + return {'CANCELLED'} + depsgraph = context.evaluated_depsgraph_get() + # Invoke to_mesh() for original object. + mesh_from_orig = object.to_mesh() + self.report({'INFO'}, f"{len(mesh_from_orig.vertices)} in new mesh without modifiers.") + # Remove temporary mesh. + bpy.data.meshes.remove(mesh_from_orig) + # Invoke to_mesh() for evaluated object. + object_eval = object.evaluated_get(depsgraph) + mesh_from_eval = object_eval.to_mesh() + self.report({'INFO'}, f"{len(mesh_from_eval.vertices)} in new mesh with modifiers.") + # Remove temporary mesh. + bpy.data.meshes.remove(mesh_from_eval) + return {'FINISHED'} + + +def register(): + bpy.utils.register_class(OBJECT_OT_object_to_mesh) + + +def unregister(): + bpy.utils.unregister_class(OBJECT_OT_object_to_mesh) + + +if __name__ == "__main__": + register() diff --git a/doc/python_api/examples/bpy.types.Depsgraph.5.py b/doc/python_api/examples/bpy.types.Depsgraph.5.py new file mode 100644 index 00000000000..781d0202931 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Depsgraph.5.py @@ -0,0 +1,61 @@ +""" +Dependency graph: Simple exporter ++++++++++++++++++++++++++++++++++ + +This example is a combination of all previous ones, and shows how to write a simple exporter +script. +""" +import bpy + + +class OBJECT_OT_simple_exporter(bpy.types.Operator): + """Simple (fake) exporter of selected objects""" + bl_label = "DEG Export Selected" + bl_idname = "object.simple_exporter" + + apply_modifiers: bpy.props.BoolProperty(name="Apply Modifiers") + + def execute(self, context): + depsgraph = context.evaluated_depsgraph_get() + for object_instance in depsgraph.object_instances: + if not self.is_object_instance_from_selected(object_instance): + # We only export selected objects + continue + # NOTE: This will create a mesh for every instance, which is not ideal at all. In + # reality destination format will support some sort of instancing mechanism, so the + # code here will simply say "instance this object at object_instance.matrix_world". + mesh = self.create_mesh_for_object_instance(object_instance) + if mesh is None: + # Happens for non-geometry objects. + continue + print(f"Exporting mesh with {len(mesh.vertices)} vertices " + f"at {object_instance.matrix_world}") + bpy.data.meshes.remove(mesh) + + return {'FINISHED'} + + def is_object_instance_from_selected(self, object_instance): + # For instanced objects we check selection of their instancer (more accurately: check + # selection status of the original object corresponding to the instancer). + if object_instance.parent: + return object_instance.parent.original.select_get() + # For non-instanced objects we check selection state of the original object. + return object_instance.object.original.select_get() + + def create_mesh_for_object_instance(self, object_instance): + if self.apply_modifiers: + return object_instance.object.to_mesh() + else: + return object_instance.object.original.to_mesh() + + +def register(): + bpy.utils.register_class(OBJECT_OT_simple_exporter) + + +def unregister(): + bpy.utils.unregister_class(OBJECT_OT_simple_exporter) + + +if __name__ == "__main__": + register() diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index 93a1271b4b4..a8e7428a50f 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -88,15 +88,17 @@ class CyclesRender(bpy.types.RenderEngine): # viewport render def view_update(self, context): + depsgraph = context.evaluated_depsgraph_get() if not self.session: engine.create(self, context.blend_data, context.region, context.space_data, context.region_data) - engine.reset(self, context.blend_data, context.depsgraph) - engine.sync(self, context.depsgraph, context.blend_data) + engine.reset(self, context.blend_data, depsgraph) + engine.sync(self, depsgraph, context.blend_data) def view_draw(self, context): - engine.draw(self, context.depsgraph, context.region, context.space_data, context.region_data) + depsgraph = context.evaluated_depsgraph_get() + engine.draw(self, depsgraph, context.region, context.space_data, context.region_data) def update_script_node(self, node): if engine.with_osl(): diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 500634e7526..2a964d0e4d0 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -45,8 +45,8 @@ void python_thread_state_restore(void **python_thread_state); static inline BL::Mesh object_to_mesh(BL::BlendData &data, BL::Object &object, - BL::Depsgraph &depsgraph, - bool calc_undeformed, + BL::Depsgraph & /*depsgraph*/, + bool /*calc_undeformed*/, Mesh::SubdivisionType subdivision_type) { /* TODO: make this work with copy-on-write, modifiers are already evaluated. */ @@ -75,11 +75,11 @@ static inline BL::Mesh object_to_mesh(BL::BlendData &data, * UV are not empty. */ if (mesh.is_editmode() || (mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) { - mesh = data.meshes.new_from_object(depsgraph, object, false, false); + mesh = data.meshes.new_from_object(object); } } else { - mesh = data.meshes.new_from_object(depsgraph, object, true, calc_undeformed); + mesh = data.meshes.new_from_object(object); } #if 0 diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 8be43a50be6..0d2998cc51e 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -311,8 +311,23 @@ int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list); int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list); int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list); +/* Gets pointer to the dependency graph. + * If it doesn't exist yet, it will be allocated. + * + * The result dependency graph is NOT guaranteed to be up-to-date neither from relation nor from + * evaluated data points of view. + * + * NOTE: Can not be used if access to a fully evaluated datablock is needed. */ struct Depsgraph *CTX_data_depsgraph(const bContext *C); +/* Gets fully updated and evaluated dependency graph. + * + * All the relations and evaluated objects are guaranteed to be up to date. + * + * NOTE: Will be expensive if there are relations or objects tagged for update. + * NOTE: If there are pending updates depsgraph hooks will be invoked. */ +struct Depsgraph *CTX_data_evaluated_depsgraph(const bContext *C); + /* Will Return NULL if depsgraph is not allocated yet. * Only used by handful of operators which are run on file load. */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index b094dc5f400..8ea54457f38 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -208,12 +208,7 @@ float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3]; void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals); -struct Mesh *BKE_mesh_new_from_object(struct Depsgraph *depsgraph, - struct Main *bmain, - struct Scene *sce, - struct Object *ob, - const bool apply_modifiers, - const bool calc_undeformed); +struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Object *object); struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob_eval, diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 4383b6a1f9b..dd326ba13db 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -1315,6 +1315,14 @@ Depsgraph *CTX_data_depsgraph(const bContext *C) return BKE_scene_get_depsgraph(scene, view_layer, true); } +Depsgraph *CTX_data_evaluated_depsgraph(const bContext *C) +{ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Main *bmain = CTX_data_main(C); + BKE_scene_graph_update_tagged(depsgraph, bmain); + return depsgraph; +} + Depsgraph *CTX_data_depsgraph_on_load(const bContext *C) { Scene *scene = CTX_data_scene(C); diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index fe8d053c1df..a5c97cd1182 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -892,302 +892,219 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene), } } -/* settings: 1 - preview, 2 - render +/* Create a temporary object to be used for nurbs-to-mesh conversion. * - * The convention goes as following: - * - * - Passing original object with apply_modifiers=false will give a - * non-modified non-deformed mesh. - * The result mesh will point to datablocks from the original "domain". For - * example, materials will be original. - * - * - Passing original object with apply_modifiers=true will give a mesh which - * has all modifiers applied. - * The result mesh will point to datablocks from the original "domain". For - * example, materials will be original. - * - * - Passing evaluated object will ignore apply_modifiers argument, and the - * result always contains all modifiers applied. - * The result mesh will point to an evaluated datablocks. For example, - * materials will be an evaluated IDs from the dependency graph. - */ -Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph, - Main *bmain, - Scene *sce, - Object *ob, - const bool apply_modifiers, - const bool calc_undeformed) + * This is more complex that it should be because BKE_mesh_from_nurbs_displist() will do more than + * simply conversion and will attempt to take over ownership of evaluated result and will also + * modify the input object. */ +static Object *object_for_curve_to_mesh_create(Object *object) { - Mesh *tmpmesh; - Curve *tmpcu = NULL, *copycu; - int i; - const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); - bool effective_apply_modifiers = apply_modifiers; - bool do_mat_id_data_us = true; - - Object *object_input = ob; - Object *object_eval = DEG_get_evaluated_object(depsgraph, object_input); - Object object_for_eval; - - if (object_eval == object_input) { - /* Evaluated mesh contains all modifiers applied already. - * The other types of object has them applied, but are stored in other - * data structures than a mesh. So need to apply modifiers again on a - * temporary copy before converting result to mesh. */ - if (object_input->type == OB_MESH) { - effective_apply_modifiers = false; - } - else { - effective_apply_modifiers = true; - } - object_for_eval = *object_eval; + Curve *curve = (Curve *)object->data; + + /* Create object itself. */ + Object *temp_object; + BKE_id_copy_ex(NULL, &object->id, (ID **)&temp_object, LIB_ID_COPY_LOCALIZE); + + /* Remove all modifiers, since we don't want them to be applied. */ + BKE_object_free_modifiers(temp_object, LIB_ID_CREATE_NO_USER_REFCOUNT); + + /* Copy relevant evaluated fields of curve cache. + * + * Note that there are extra fields in there like bevel and path, but those are not needed during + * conversion, so they are not copied to save unnecessary allocations. */ + if (object->runtime.curve_cache != NULL) { + temp_object->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), + "CurveCache for curve types"); + BKE_displist_copy(&temp_object->runtime.curve_cache->disp, &object->runtime.curve_cache->disp); } - else { - if (apply_modifiers) { - object_for_eval = *object_eval; - if (object_for_eval.runtime.mesh_orig != NULL) { - object_for_eval.data = object_for_eval.runtime.mesh_orig; - } - } - else { - object_for_eval = *object_input; - } + /* Constructive modifiers will use mesh to store result. */ + if (object->runtime.mesh_eval != NULL) { + BKE_id_copy_ex(NULL, + &object->runtime.mesh_eval->id, + (ID **)&temp_object->runtime.mesh_eval, + LIB_ID_COPY_LOCALIZE); } - const bool cage = !effective_apply_modifiers; + /* Need to create copy of curve itself as well, it will be freed by underlying conversion + * functions. + * + * NOTE: Copies the data, but not the shapekeys. */ + BKE_id_copy_ex(NULL, object->data, (ID **)&temp_object->data, LIB_ID_COPY_LOCALIZE); + Curve *temp_curve = (Curve *)temp_object->data; - /* perform the mesh extraction based on type */ - switch (object_for_eval.type) { - case OB_FONT: - case OB_CURVE: - case OB_SURF: { - ListBase dispbase = {NULL, NULL}; - Mesh *me_eval_final = NULL; - int uv_from_orco; - - /* copies object and modifiers (but not the data) */ - Object *tmpobj; - BKE_id_copy_ex(NULL, &object_for_eval.id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE); - tmpcu = (Curve *)tmpobj->data; - - /* Copy cached display list, it might be needed by the stack evaluation. - * Ideally stack should be able to use render-time display list, but doing - * so is quite tricky and not safe so close to the release. - * - * TODO(sergey): Look into more proper solution. - */ - if (object_for_eval.runtime.curve_cache != NULL) { - if (tmpobj->runtime.curve_cache == NULL) { - tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), - "CurveCache for curve types"); - } - BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, - &object_for_eval.runtime.curve_cache->disp); - } + /* Make sure texture space is calculated for a copy of curve, it will be used for the final + * result. */ + BKE_curve_texspace_calc(temp_curve); - /* if getting the original caged mesh, delete object modifiers */ - if (cage) { - BKE_object_free_modifiers(tmpobj, LIB_ID_CREATE_NO_USER_REFCOUNT); - } + /* Temporarily set edit so we get updates from edit mode, but also because for text datablocks + * copying it while in edit mode gives invalid data structures. */ + temp_curve->editfont = curve->editfont; + temp_curve->editnurb = curve->editnurb; - /* copies the data, but *not* the shapekeys. */ - BKE_id_copy_ex(NULL, object_for_eval.data, (ID **)©cu, LIB_ID_COPY_LOCALIZE); - tmpobj->data = copycu; - - /* make sure texture space is calculated for a copy of curve, - * it will be used for the final result. - */ - BKE_curve_texspace_calc(copycu); - - /* temporarily set edit so we get updates from edit mode, but - * also because for text datablocks copying it while in edit - * mode gives invalid data structures */ - copycu->editfont = tmpcu->editfont; - copycu->editnurb = tmpcu->editnurb; - - /* get updated display list, and convert to a mesh */ - BKE_displist_make_curveTypes_forRender( - depsgraph, sce, tmpobj, &dispbase, &me_eval_final, false, NULL); - - copycu->editfont = NULL; - copycu->editnurb = NULL; - - tmpobj->runtime.mesh_eval = me_eval_final; - - /* convert object type to mesh */ - uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0; - BKE_mesh_from_nurbs_displist( - bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true); - /* Function above also frees copycu (aka tmpobj->data), make this obvious here. */ - copycu = NULL; - - tmpmesh = tmpobj->data; - id_us_min( - &tmpmesh->id); /* Gets one user from its creation in BKE_mesh_from_nurbs_displist(). */ - - BKE_displist_free(&dispbase); - - /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. - * if it didn't the curve did not have any segments or otherwise - * would have generated an empty mesh */ - if (tmpobj->type != OB_MESH) { - BKE_id_free(NULL, tmpobj); - return NULL; - } - - BKE_id_free(NULL, tmpobj); + return temp_object; +} - /* XXX The curve to mesh conversion is convoluted... - * But essentially, BKE_mesh_from_nurbs_displist() - * already transfers the ownership of materials from the temp copy of the Curve ID to the - * new Mesh ID, so we do not want to increase materials' usercount later. */ - do_mat_id_data_us = false; +static void curve_to_mesh_eval_ensure(Object *object) +{ + if (object->runtime.curve_cache == NULL) { + object->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); + } + Curve *curve = (Curve *)object->data; + Curve remapped_curve = *curve; + Object remapped_object = *object; + remapped_object.data = &remapped_curve; - break; - } + /* Clear all modifiers for the bevel object. + * + * This is because they can not be reliably evaluated for an original object (at least because + * the state of dependencies is not know). + * + * So we create temporary copy of the object which will use same data as the original bevel, but + * will have no modifiers. */ + Object bevel_object = {NULL}; + if (remapped_curve.bevobj != NULL) { + bevel_object = *remapped_curve.bevobj; + BLI_listbase_clear(&bevel_object.modifiers); + remapped_curve.bevobj = &bevel_object; + } - case OB_MBALL: { - /* metaballs don't have modifiers, so just convert to mesh */ - Object *basis_ob = BKE_mball_basis_find(sce, object_input); - /* todo, re-generatre for render-res */ - /* metaball_polygonize(scene, ob) */ + /* Same thing for taper. */ + Object taper_object = {NULL}; + if (remapped_curve.taperobj != NULL) { + taper_object = *remapped_curve.taperobj; + BLI_listbase_clear(&taper_object.modifiers); + remapped_curve.taperobj = &taper_object; + } - if (basis_ob != object_input) { - /* Only do basis metaball. */ - return NULL; - } + /* NOTE: We don't have dependency graph or scene here, so we pass NULL. This is all fine since + * they are only used for modifier stack, which we have explicitly disabled for all objects. + * + * TODO(sergey): This is a very fragile logic, but proper solution requires re-writing quite a + * bit of internal functions (BKE_mesh_from_nurbs_displist, BKE_mesh_nomain_to_mesh) and also + * Mesh From Curve operator. + * Brecht says hold off with that. */ + BKE_displist_make_curveTypes_forRender(NULL, + NULL, + &remapped_object, + &remapped_object.runtime.curve_cache->disp, + &remapped_object.runtime.mesh_eval, + false, + NULL); + + BKE_object_free_curve_cache(&bevel_object); + BKE_object_free_curve_cache(&taper_object); +} - tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2); - /* BKE_mesh_add gives us a user count we don't need */ - id_us_min(&tmpmesh->id); +static Mesh *mesh_new_from_curve_type_object(Main *bmain, Object *object) +{ + Curve *curve = object->data; + const bool uv_from_orco = (curve->flag & CU_UV_ORCO) != 0; - if (render) { - ListBase disp = {NULL, NULL}; - BKE_displist_make_mball_forRender(depsgraph, sce, &object_for_eval, &disp); - BKE_mesh_from_metaball(&disp, tmpmesh); - BKE_displist_free(&disp); - } - else { - ListBase disp = {NULL, NULL}; - if (object_for_eval.runtime.curve_cache) { - disp = object_for_eval.runtime.curve_cache->disp; - } - BKE_mesh_from_metaball(&disp, tmpmesh); - } + Object *temp_object = object_for_curve_to_mesh_create(object); + Curve *temp_curve = (Curve *)temp_object->data; - BKE_mesh_texspace_copy_from_object(tmpmesh, &object_for_eval); + /* When input object is an original one, we don't have evaluated curve cache yet, so need to + * create it in the temporary object. */ + if (!DEG_is_evaluated_object(object)) { + curve_to_mesh_eval_ensure(temp_object); + } - break; - } - case OB_MESH: - /* copies object and modifiers (but not the data) */ - if (cage) { - /* copies the data (but *not* the shapekeys). */ - Mesh *mesh = object_for_eval.data; - BKE_id_copy_ex(bmain, &mesh->id, (ID **)&tmpmesh, 0); - /* XXX BKE_mesh_copy() already handles materials usercount. */ - do_mat_id_data_us = false; - } - /* if not getting the original caged mesh, get final derived mesh */ - else { - /* Make a dummy mesh, saves copying */ - Mesh *me_eval; - CustomData_MeshMasks mask = CD_MASK_MESH; /* this seems more suitable, exporter, - * for example, needs CD_MASK_MDEFORMVERT */ + /* Reset pointers before conversion. */ + temp_curve->editfont = NULL; + temp_curve->editnurb = NULL; + + /* Convert to mesh. */ + BKE_mesh_from_nurbs_displist(bmain, + temp_object, + &temp_object->runtime.curve_cache->disp, + uv_from_orco, + curve->id.name + 2, + true); + + /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. If it didn't the curve did + * not have any segments or otherwise would have generated an empty mesh. */ + if (temp_object->type != OB_MESH) { + BKE_id_free(NULL, temp_object); + return NULL; + } - if (calc_undeformed) { - mask.vmask |= CD_MASK_ORCO; - } + Mesh *mesh_result = temp_object->data; - if (render) { - me_eval = mesh_create_eval_final_render(depsgraph, sce, &object_for_eval, &mask); - } - else { - me_eval = mesh_create_eval_final_view(depsgraph, sce, &object_for_eval, &mask); - } + BKE_id_free(NULL, temp_object); - tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2); - BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, &object_for_eval, &mask, true); + /* NOTE: Materials are copied in BKE_mesh_from_nurbs_displist(). */ - /* Copy autosmooth settings from original mesh. */ - Mesh *me = (Mesh *)object_for_eval.data; - tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH); - tmpmesh->smoothresh = me->smoothresh; - } + return mesh_result; +} - /* BKE_mesh_add/copy gives us a user count we don't need */ - id_us_min(&tmpmesh->id); +static Mesh *mesh_new_from_mball_object(Main *bmain, Object *object) +{ + MetaBall *mball = (MetaBall *)object->data; - break; - default: - /* "Object does not have geometry data") */ - return NULL; + /* NOTE: We can only create mesh for a polygonized meta ball. This figures out all original meta + * balls and all evaluated child meta balls (since polygonization is only stored in the mother + * ball). + * + * We create empty mesh so scripters don't run into None objects. */ + if (!DEG_is_evaluated_object(object) || object->runtime.curve_cache == NULL || + BLI_listbase_is_empty(&object->runtime.curve_cache->disp)) { + return BKE_mesh_add(bmain, mball->id.name + 2); } - /* Copy materials to new mesh */ - switch (object_for_eval.type) { - case OB_SURF: - case OB_FONT: - case OB_CURVE: - tmpmesh->totcol = tmpcu->totcol; - - /* free old material list (if it exists) and adjust user counts */ - if (tmpcu->mat) { - for (i = tmpcu->totcol; i-- > 0;) { - /* are we an object material or data based? */ - tmpmesh->mat[i] = give_current_material(object_input, i + 1); + Mesh *mesh_result = BKE_mesh_add(bmain, ((ID *)object->data)->name + 2); + BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result); - if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && - tmpmesh->mat[i]) { - id_us_plus(&tmpmesh->mat[i]->id); - } - } - } - break; + /* Copy materials. */ + mesh_result->totcol = mball->totcol; + mesh_result->mat = MEM_dupallocN(mball->mat); + if (mball->mat != NULL) { + for (int i = mball->totcol; i-- > 0;) { + mesh_result->mat[i] = give_current_material(object, i + 1); + } + } - case OB_MBALL: { - MetaBall *tmpmb = (MetaBall *)object_for_eval.data; - tmpmesh->mat = MEM_dupallocN(tmpmb->mat); - tmpmesh->totcol = tmpmb->totcol; + return mesh_result; +} - /* free old material list (if it exists) and adjust user counts */ - if (tmpmb->mat) { - for (i = tmpmb->totcol; i-- > 0;) { - /* are we an object material or data based? */ - tmpmesh->mat[i] = give_current_material(object_input, i + 1); +static Mesh *mesh_new_from_mesh_object(Main *bmain, Object *object) +{ + Mesh *mesh_input = object->data; + Mesh *mesh_result = NULL; + BKE_id_copy_ex(bmain, &mesh_input->id, (ID **)&mesh_result, 0); + /* NOTE: Materials should already be copied. */ + return mesh_result; +} - if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && - tmpmesh->mat[i]) { - id_us_plus(&tmpmesh->mat[i]->id); - } - } - } +Mesh *BKE_mesh_new_from_object(Main *bmain, Object *object) +{ + Mesh *new_mesh = NULL; + switch (object->type) { + case OB_FONT: + case OB_CURVE: + case OB_SURF: + new_mesh = mesh_new_from_curve_type_object(bmain, object); + break; + case OB_MBALL: + new_mesh = mesh_new_from_mball_object(bmain, object); break; - } - case OB_MESH: - if (!cage) { - Mesh *origmesh = object_for_eval.data; - tmpmesh->flag = origmesh->flag; - tmpmesh->mat = MEM_dupallocN(origmesh->mat); - tmpmesh->totcol = origmesh->totcol; - tmpmesh->smoothresh = origmesh->smoothresh; - if (origmesh->mat) { - for (i = origmesh->totcol; i-- > 0;) { - /* are we an object material or data based? */ - tmpmesh->mat[i] = give_current_material(object_input, i + 1); - - if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && - tmpmesh->mat[i]) { - id_us_plus(&tmpmesh->mat[i]->id); - } - } - } - } + new_mesh = mesh_new_from_mesh_object(bmain, object); break; - } /* end copy materials */ - - return tmpmesh; + default: + /* Object does not have geometry data. */ + return NULL; + } + if (new_mesh == NULL) { + /* Happens in special cases like request of mesh for non-mother meta ball. */ + return NULL; + } + /* The result must have 0 users, since it's just a mesh which is free-dangling in the main + * database. All the copy and allocation functions to manipulate new Mesh datablock are ensuring + * an user. + * Here we control that user management went the way it's expected, and cancel out the user. */ + BLI_assert(new_mesh->id.us == 1); + id_us_min(&new_mesh->id); + return new_mesh; } static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src) diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index da95db92332..4f26ae27d9c 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -705,10 +705,9 @@ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *re } /* create new mesh with edit mode changes and modifiers applied */ -static Mesh *bake_mesh_new_from_object(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *ob) +static Mesh *bake_mesh_new_from_object(Main *bmain, Object *object) { - bool apply_modifiers = (ob->type != OB_MESH); - Mesh *me = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob, apply_modifiers, false); + Mesh *me = BKE_mesh_new_from_object(bmain, object); if (me->flag & ME_AUTOSMOOTH) { BKE_mesh_split_faces(me, true); @@ -904,7 +903,7 @@ static int bake(Render *re, ob_low_eval = DEG_get_evaluated_object(depsgraph, ob_low); /* get the mesh as it arrives in the renderer */ - me_low = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval); + me_low = bake_mesh_new_from_object(bmain, ob_low_eval); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) { @@ -918,7 +917,7 @@ static int bake(Render *re, /* prepare cage mesh */ if (ob_cage) { - me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_cage_eval); + me_cage = bake_mesh_new_from_object(bmain, ob_cage_eval); if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { BKE_report(reports, RPT_ERROR, @@ -947,7 +946,7 @@ static int bake(Render *re, md = md_next; } - me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval); + me_cage = bake_mesh_new_from_object(bmain, ob_low_eval); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } @@ -966,7 +965,7 @@ static int bake(Render *re, highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER); - highpoly[i].me = bake_mesh_new_from_object(depsgraph, bmain, scene, highpoly[i].ob_eval); + highpoly[i].me = bake_mesh_new_from_object(bmain, highpoly[i].ob_eval); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); @@ -1089,7 +1088,7 @@ static int bake(Render *re, } /* Evaluate modifiers again. */ - me_nores = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval, true, false); + me_nores = BKE_mesh_new_from_object(bmain, ob_low_eval); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index 06a356dd232..ed553c9583c 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -98,10 +98,7 @@ NodeGroup *BlenderFileLoader::Load() continue; } - bool apply_modifiers = false; - bool calc_undeformed = false; - Mesh *mesh = BKE_mesh_new_from_object( - _depsgraph, _re->main, _re->scene, ob, apply_modifiers, calc_undeformed); + Mesh *mesh = BKE_mesh_new_from_object(_re->main, ob); if (mesh) { insertShapeNode(ob, mesh, ++id); diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 149cd7caf84..97d3d03468b 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -435,6 +435,11 @@ StructRNA *rna_PropertyGroup_refine(PointerRNA *ptr) return ptr->type; } +static ID *rna_ID_evaluated_get(ID *id, struct Depsgraph *depsgraph) +{ + return DEG_get_evaluated_id(depsgraph, id); +} + static ID *rna_ID_copy(ID *id, Main *bmain) { ID *newid; @@ -1446,6 +1451,15 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_IDPreview_get", NULL, NULL, NULL); /* functions */ + func = RNA_def_function(srna, "evaluated_get", "rna_ID_evaluated_get"); + RNA_def_function_ui_description( + func, "Get corresponding evaluated ID from the given dependency graph"); + parm = RNA_def_pointer( + func, "depsgraph", "Depsgraph", "", "Dependency graph to perform lookup in"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID"); + RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "copy", "rna_ID_copy"); RNA_def_function_ui_description( func, "Create a copy of this data-block (not supported for all data-blocks)"); diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c index 75f8b97b99d..a2ac7cb40ba 100644 --- a/source/blender/makesrna/intern/rna_context.c +++ b/source/blender/makesrna/intern/rna_context.c @@ -135,12 +135,6 @@ static PointerRNA rna_Context_main_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_BlendData, CTX_data_main(C)); } -static PointerRNA rna_Context_depsgraph_get(PointerRNA *ptr) -{ - bContext *C = (bContext *)ptr->data; - return rna_pointer_inherit_refine(ptr, &RNA_Depsgraph, CTX_data_depsgraph(C)); -} - static PointerRNA rna_Context_scene_get(PointerRNA *ptr) { bContext *C = (bContext *)ptr->data; @@ -204,6 +198,11 @@ static int rna_Context_mode_get(PointerRNA *ptr) return CTX_data_mode_enum(C); } +static struct Depsgraph *rna_Context_evaluated_depsgraph_get(bContext *C) +{ + return CTX_data_evaluated_depsgraph(C); +} + #else void RNA_def_context(BlenderRNA *brna) @@ -211,6 +210,9 @@ void RNA_def_context(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; + srna = RNA_def_struct(brna, "Context", NULL); RNA_def_struct_ui_text(srna, "Context", "Current windowmanager and data context"); RNA_def_struct_sdna(srna, "bContext"); @@ -267,11 +269,6 @@ void RNA_def_context(BlenderRNA *brna) RNA_def_property_struct_type(prop, "BlendData"); RNA_def_property_pointer_funcs(prop, "rna_Context_main_get", NULL, NULL, NULL); - prop = RNA_def_property(srna, "depsgraph", PROP_POINTER, PROP_NONE); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_struct_type(prop, "Depsgraph"); - RNA_def_property_pointer_funcs(prop, "rna_Context_depsgraph_get", NULL, NULL, NULL); - prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "Scene"); @@ -310,6 +307,16 @@ void RNA_def_context(BlenderRNA *brna) RNA_def_property_enum_items(prop, rna_enum_context_mode_items); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_enum_funcs(prop, "rna_Context_mode_get", NULL, NULL); + + func = RNA_def_function(srna, "evaluated_depsgraph_get", "rna_Context_evaluated_depsgraph_get"); + RNA_def_function_ui_description( + func, + "Get the dependency graph for the current scene and view layer, to access to data-blocks " + "with animation and modifiers applied. If any data-blocks have been edited, the dependency " + "graph will be updated. This invalidates all references to evaluated data-blocks from the " + "dependency graph."); + parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "Evaluated dependency graph"); + RNA_def_function_return(func, parm); } #endif diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index 447318da744..08f37de26ee 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -41,6 +41,7 @@ # include "BKE_anim.h" # include "BKE_object.h" +# include "BKE_scene.h" # include "DEG_depsgraph_build.h" # include "DEG_depsgraph_debug.h" @@ -256,6 +257,11 @@ static void rna_Depsgraph_debug_stats(Depsgraph *depsgraph, char *result) outer); } +static void rna_Depsgraph_update(Depsgraph *depsgraph, Main *bmain) +{ + BKE_scene_graph_update_tagged(depsgraph, bmain); +} + /* Iteration over objects, simple version */ static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) @@ -636,6 +642,15 @@ static void rna_def_depsgraph(BlenderRNA *brna) RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */ RNA_def_function_output(func, parm); + /* Updates. */ + + func = RNA_def_function(srna, "update", "rna_Depsgraph_update"); + RNA_def_function_ui_description( + func, + "Re-evaluate any modified data-blocks, for example for animation or modifiers. " + "This invalidates all references to evaluated data-blocks from this dependency graph."); + RNA_def_function_flag(func, FUNC_USE_MAIN); + /* Queries for original datablockls (the ones depsgraph is built for). */ prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index fc0950c1bb0..d93f8c4414b 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -550,10 +550,7 @@ int rna_parameter_size(struct PropertyRNA *parm); struct Mesh *rna_Main_meshes_new_from_object(struct Main *bmain, struct ReportList *reports, - struct Depsgraph *depsgraph, - struct Object *ob, - bool apply_modifiers, - bool calc_undeformed); + struct Object *object); /* XXX, these should not need to be defined here~! */ struct MTex *rna_mtex_texture_slots_add(struct ID *self, diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index b21cd3324b8..8f48738a27e 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -317,16 +317,9 @@ static Mesh *rna_Main_meshes_new(Main *bmain, const char *name) } /* copied from Mesh_getFromObject and adapted to RNA interface */ -Mesh *rna_Main_meshes_new_from_object(Main *bmain, - ReportList *reports, - Depsgraph *depsgraph, - Object *ob, - bool apply_modifiers, - bool calc_undeformed) +Mesh *rna_Main_meshes_new_from_object(Main *bmain, ReportList *reports, Object *object) { - Scene *sce = DEG_get_evaluated_scene(depsgraph); - - switch (ob->type) { + switch (object->type) { case OB_FONT: case OB_CURVE: case OB_SURF: @@ -338,7 +331,7 @@ Mesh *rna_Main_meshes_new_from_object(Main *bmain, return NULL; } - return BKE_mesh_new_from_object(depsgraph, bmain, sce, ob, apply_modifiers, calc_undeformed); + return BKE_mesh_new_from_object(bmain, object); } static Light *rna_Main_lights_new(Main *bmain, const char *name, int type) @@ -951,24 +944,13 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_return(func, parm); func = RNA_def_function(srna, "new_from_object", "rna_Main_meshes_new_from_object"); - RNA_def_function_ui_description(func, - "Add a new mesh created from object with modifiers applied"); + RNA_def_function_ui_description( + func, + "Add a new mesh created from given object (undeformed geometry if object is original, and " + "final evaluated geometry, with all modifiers etc., if object is evaluated)"); RNA_def_function_flag(func, FUNC_USE_REPORTS); - parm = RNA_def_pointer(func, - "depsgraph", - "Depsgraph", - "Dependency Graph", - "Evaluated dependency graph within which to evaluate modifiers"); - RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "object", "Object", "", "Object to create mesh from"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); - parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - RNA_def_boolean(func, - "calc_undeformed", - false, - "Calculate Undeformed", - "Calculate undeformed vertex coordinates"); parm = RNA_def_pointer(func, "mesh", "Mesh", diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index c997a82f02d..d94abd4066a 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -375,18 +375,11 @@ static void rna_Object_camera_fit_coords( } /* copied from Mesh_getFromObject and adapted to RNA interface */ -/* settings: 0 - preview, 1 - render */ -static Mesh *rna_Object_to_mesh(Object *ob, - bContext *C, - ReportList *reports, - Depsgraph *depsgraph, - bool apply_modifiers, - bool calc_undeformed) +static Mesh *rna_Object_to_mesh(Object *object, bContext *C, ReportList *reports) { Main *bmain = CTX_data_main(C); - return rna_Main_meshes_new_from_object( - bmain, reports, depsgraph, ob, apply_modifiers, calc_undeformed); + return rna_Main_meshes_new_from_object(bmain, reports, object); } static PointerRNA rna_Object_shape_key_add( @@ -882,22 +875,10 @@ void RNA_api_object(StructRNA *srna) /* mesh */ func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh"); - RNA_def_function_ui_description(func, "Create a Mesh data-block with modifiers applied"); + RNA_def_function_ui_description(func, + "Create a Mesh data-block from the current state of the object"); RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, - "depsgraph", - "Depsgraph", - "Dependency Graph", - "Evaluated dependency graph within which to evaluate modifiers"); - RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); - parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - RNA_def_boolean(func, - "calc_undeformed", - false, - "Calculate Undeformed", - "Calculate undeformed vertex coordinates"); - parm = RNA_def_pointer(func, "mesh", "Mesh", "", diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index e29891b60db..1d4d2e9cdd9 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -116,23 +116,6 @@ static void rna_Scene_uvedit_aspect(Scene *scene, Object *ob, float *aspect) aspect[0] = aspect[1] = 1.0f; } -static void rna_Scene_update_tagged(Scene *scene, Main *bmain) -{ -# ifdef WITH_PYTHON - BPy_BEGIN_ALLOW_THREADS; -# endif - - for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL; - view_layer = view_layer->next) { - Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); - BKE_scene_graph_update_tagged(depsgraph, bmain); - } - -# ifdef WITH_PYTHON - BPy_END_ALLOW_THREADS; -# endif -} - static void rna_SceneRender_get_frame_path( RenderData *rd, Main *bmain, int frame, bool preview, const char *view, char *name) { @@ -303,11 +286,6 @@ void RNA_api_scene(StructRNA *srna) func, "subframe", 0.0, 0.0, 1.0, "", "Sub-frame time, between 0.0 and 1.0", 0.0, 1.0); RNA_def_function_flag(func, FUNC_USE_MAIN); - func = RNA_def_function(srna, "update", "rna_Scene_update_tagged"); - RNA_def_function_ui_description( - func, "Update data tagged to be updated from previous access to data or operators"); - RNA_def_function_flag(func, FUNC_USE_MAIN); - func = RNA_def_function(srna, "uvedit_aspect", "rna_Scene_uvedit_aspect"); RNA_def_function_ui_description(func, "Get uv aspect for current object"); parm = RNA_def_pointer(func, "object", "Object", "", "Object"); diff --git a/tests/python/bl_alembic_import_test.py b/tests/python/bl_alembic_import_test.py index 2cde6d57a7f..63624270bd8 100644 --- a/tests/python/bl_alembic_import_test.py +++ b/tests/python/bl_alembic_import_test.py @@ -92,8 +92,10 @@ class SimpleImportTest(AbstractAlembicTest): # translates to "no parent" in Blender. self.assertIsNone(objects['locator2'].parent) + depsgraph = bpy.context.evaluated_depsgraph_get() + # Shouldn't have inherited the ABC parent's transform. - loc2 = bpy.context.depsgraph.id_eval_get(objects['locator2']) + loc2 = depsgraph.id_eval_get(objects['locator2']) x, y, z = objects['locator2'].matrix_world.to_translation() self.assertAlmostEqual(0, x) self.assertAlmostEqual(0, y) @@ -103,7 +105,7 @@ class SimpleImportTest(AbstractAlembicTest): self.assertEqual(objects['locator2'], objects['locatorShape2'].parent) # Should have inherited its ABC parent's transform. - locshp2 = bpy.context.depsgraph.id_eval_get(objects['locatorShape2']) + locshp2 = depsgraph.id_eval_get(objects['locatorShape2']) x, y, z = locshp2.matrix_world.to_translation() self.assertAlmostEqual(0, x) self.assertAlmostEqual(0, y) @@ -142,9 +144,11 @@ class SimpleImportTest(AbstractAlembicTest): self.assertEqual({'FINISHED'}, res) cube = bpy.context.active_object + depsgraph = bpy.context.evaluated_depsgraph_get() + # Check that the file loaded ok. bpy.context.scene.frame_set(10) - cube = bpy.context.depsgraph.id_eval_get(cube) + cube = depsgraph.id_eval_get(cube) x, y, z = cube.matrix_world.to_euler('XYZ') self.assertAlmostEqual(x, 0) self.assertAlmostEqual(y, 0) @@ -155,7 +159,7 @@ class SimpleImportTest(AbstractAlembicTest): bpy.data.cache_files[fname].filepath = relpath bpy.context.scene.frame_set(10) - cube = bpy.context.depsgraph.id_eval_get(cube) + cube = depsgraph.id_eval_get(cube) x, y, z = cube.matrix_world.to_euler('XYZ') self.assertAlmostEqual(x, 0) self.assertAlmostEqual(y, 0) @@ -163,9 +167,9 @@ class SimpleImportTest(AbstractAlembicTest): # Replace the Alembic file; this should apply new animation. bpy.data.cache_files[fname].filepath = relpath.replace('1.abc', '2.abc') - bpy.context.scene.update() + depsgraph.update() - cube = bpy.context.depsgraph.id_eval_get(cube) + cube = depsgraph.id_eval_get(cube) x, y, z = cube.matrix_world.to_euler('XYZ') self.assertAlmostEqual(x, math.pi / 2, places=5) self.assertAlmostEqual(y, 0) @@ -180,10 +184,13 @@ class SimpleImportTest(AbstractAlembicTest): self.assertEqual({'FINISHED'}, res) plane = bpy.context.active_object + depsgraph = bpy.context.evaluated_depsgraph_get() + # Check that the file loaded ok. bpy.context.scene.frame_set(6) scene = bpy.context.scene - mesh = plane.to_mesh(bpy.context.depsgraph, apply_modifiers=True, calc_undeformed=False) + plane_eval = plane.evaluated_get(depsgraph) + mesh = plane_eval.to_mesh() self.assertAlmostEqual(-1, mesh.vertices[0].co.x) self.assertAlmostEqual(-1, mesh.vertices[0].co.y) self.assertAlmostEqual(0.5905638933181763, mesh.vertices[0].co.z) @@ -193,7 +200,8 @@ class SimpleImportTest(AbstractAlembicTest): bpy.data.cache_files[fname].filepath = relpath scene.frame_set(6) - mesh = plane.to_mesh(bpy.context.depsgraph, apply_modifiers=True, calc_undeformed=False) + plane_eval = plane.evaluated_get(depsgraph) + mesh = plane_eval.to_mesh() self.assertAlmostEqual(1, mesh.vertices[3].co.x) self.assertAlmostEqual(1, mesh.vertices[3].co.y) self.assertAlmostEqual(0.5905638933181763, mesh.vertices[3].co.z) |