[Bf-blender-cvs] [32d5d127cb4] master: Tweak API to support adding evaluated meshes to main database

Sergey Sharybin noreply at git.blender.org
Thu May 16 16:49:01 CEST 2019


Commit: 32d5d127cb49743578e8e1e9882d8a707a4e848e
Author: Sergey Sharybin
Date:   Thu May 16 13:49:21 2019 +0200
Branches: master
https://developer.blender.org/rB32d5d127cb49743578e8e1e9882d8a707a4e848e

Tweak API to support adding evaluated meshes to main database

One of the usecases is to create mesh from an object is a manner similar to
how Apply Modifiers does it, and have it in the bmain so it can be referenced
by other objects.

This usecase is something what went unnoticed in the previous API changes, so
here is a followup.

Summary of changes:

* bpy.meshes.new_from_object() behaves almost the same as before this change.
  The difference now is that it now ensures all referenced data-blocks are
	original (for example, materials referenced by the mesh).

* object.to_mesh() now creates free-standing Mesh data-block which is outside
  of any bmain. The object owns it, which guarantees the memory never leaks.

  It is possible to force free memory by calling object.to_mesh_clear().

Reviewers: brecht

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D4875

===================================================================

M	doc/python_api/examples/bpy.types.Depsgraph.4.py
M	doc/python_api/examples/bpy.types.Depsgraph.5.py
A	doc/python_api/examples/bpy.types.Depsgraph.6.py
M	intern/cycles/blender/blender_util.h
M	source/blender/blenkernel/BKE_mesh.h
M	source/blender/blenkernel/BKE_object.h
M	source/blender/blenkernel/intern/mesh_convert.c
M	source/blender/blenkernel/intern/object.c
M	source/blender/editors/object/object_bake_api.c
M	source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
M	source/blender/makesdna/DNA_object_types.h
M	source/blender/makesrna/intern/rna_internal.h
M	source/blender/makesrna/intern/rna_main_api.c
M	source/blender/makesrna/intern/rna_object_api.c
M	tests/python/bl_alembic_import_test.py

===================================================================

diff --git a/doc/python_api/examples/bpy.types.Depsgraph.4.py b/doc/python_api/examples/bpy.types.Depsgraph.4.py
index 5c7b76edab6..41f94a32c4c 100644
--- a/doc/python_api/examples/bpy.types.Depsgraph.4.py
+++ b/doc/python_api/examples/bpy.types.Depsgraph.4.py
@@ -2,8 +2,8 @@
 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.
+Object.to_mesh() is closely interacting with dependency graph: its behavior depends on whether it
+is 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:
@@ -14,7 +14,7 @@ animation or modifiers into account:
 
 When is used on evaluated object all modifiers are taken into account.
 
-.. note:: The result mesh is added to the main database.
+.. note:: The result mesh is owned by the object. It can be freed by calling `object.to_mesh_clear()`.
 .. note:: If object does not have geometry (i.e. camera) the functions returns None.
 """
 import bpy
@@ -40,13 +40,13 @@ class OBJECT_OT_object_to_mesh(bpy.types.Operator):
         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)
+        object.to_mesh_clear()
         # 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)
+        object_eval.to_mesh_clear()
         return {'FINISHED'}
 
 
diff --git a/doc/python_api/examples/bpy.types.Depsgraph.5.py b/doc/python_api/examples/bpy.types.Depsgraph.5.py
index 781d0202931..a37d2674ecd 100644
--- a/doc/python_api/examples/bpy.types.Depsgraph.5.py
+++ b/doc/python_api/examples/bpy.types.Depsgraph.5.py
@@ -1,60 +1,56 @@
 """
-Dependency graph: Simple exporter
-+++++++++++++++++++++++++++++++++
+Dependency graph: bpy.data.meshes.new_from_object()
++++++++++++++++++++++++++++++++++++++++++++++++++++
 
-This example is a combination of all previous ones, and shows how to write a simple exporter
-script.
+Object.to_mesh() is closely interacting with dependency graph: its behavior depends on whether it
+is 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.
+
+All the references (such as materials) are re-mapped to original. This ensures validity and
+consistency of the main database.
+
+.. 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_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")
+class OBJECT_OT_mesh_from_object(bpy.types.Operator):
+    """Convert selected object to mesh and show number of vertices"""
+    bl_label = "DEG Mesh From Object"
+    bl_idname = "object.mesh_from_object"
 
     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()
-        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)
-
+        object_eval = object.evaluated_get(depsgraph)
+        mesh_from_eval = bpy.data.meshes.new_from_object(object_eval)
+        self.report({'INFO'}, f"{len(mesh_from_eval.vertices)} in new mesh, and is ready for use!")
         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)
+    bpy.utils.register_class(OBJECT_OT_mesh_from_object)
 
 
 def unregister():
-    bpy.utils.unregister_class(OBJECT_OT_simple_exporter)
+    bpy.utils.unregister_class(OBJECT_OT_mesh_from_object)
 
 
 if __name__ == "__main__":
diff --git a/doc/python_api/examples/bpy.types.Depsgraph.5.py b/doc/python_api/examples/bpy.types.Depsgraph.6.py
similarity index 100%
copy from doc/python_api/examples/bpy.types.Depsgraph.5.py
copy to doc/python_api/examples/bpy.types.Depsgraph.6.py
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 2a964d0e4d0..972d7296727 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -43,7 +43,7 @@ CCL_NAMESPACE_BEGIN
 void python_thread_state_save(void **python_thread_state);
 void python_thread_state_restore(void **python_thread_state);
 
-static inline BL::Mesh object_to_mesh(BL::BlendData &data,
+static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
                                       BL::Object &object,
                                       BL::Depsgraph & /*depsgraph*/,
                                       bool /*calc_undeformed*/,
@@ -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(object);
+      mesh = object.to_mesh();
     }
   }
   else {
-    mesh = data.meshes.new_from_object(object);
+    mesh = object.to_mesh();
   }
 
 #if 0
@@ -102,11 +102,13 @@ static inline BL::Mesh object_to_mesh(BL::BlendData &data,
   return mesh;
 }
 
-static inline void free_object_to_mesh(BL::BlendData &data, BL::Object &object, BL::Mesh &mesh)
+static inline void free_object_to_mesh(BL::BlendData & /*data*/,
+                                       BL::Object &object,
+                                       BL::Mesh &mesh)
 {
   /* Free mesh if we didn't just use the existing one. */
   if (object.data().ptr.data != mesh.ptr.data) {
-    data.meshes.remove(mesh, false, true, false);
+    object.to_mesh_clear();
   }
 }
 
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 8ea54457f38..c410946f438 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -208,7 +208,13 @@ 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 Main *bmain, struct Object *object);
+/* Create new mesh from the given object at its current state.
+ * The owner of this mesh is unknown, it is up to the caller to decide. */
+struct Mesh *BKE_mesh_new_from_object(struct Object *object);
+
+/* This is a version of BKE_mesh_new_from_object() which stores mesh in the given main database. */
+struct Mesh *BKE_mesh_new_from_object_to_bmain(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/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index c373fbfe478..aa4d9696527 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -396,6 +396,15 @@ bool BKE_object_empty_image_frame_is_visible_in_view3d(const struct Object *ob,
 bool BKE_object_empty_image_data_is_visible_in_view3d(const struct Object *ob,
                                                       const struct RegionView3D *rv3d);
 
+/* This is an utility function for Python's object.to_mesh() (the naming is not very clear though).
+ * The result is owned by the object.
+

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list