Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'doc/python_api/examples')
-rw-r--r--doc/python_api/examples/bpy.types.Depsgraph.1.py60
-rw-r--r--doc/python_api/examples/bpy.types.Depsgraph.2.py45
-rw-r--r--doc/python_api/examples/bpy.types.Depsgraph.3.py42
-rw-r--r--doc/python_api/examples/bpy.types.Depsgraph.4.py62
-rw-r--r--doc/python_api/examples/bpy.types.Depsgraph.5.py61
5 files changed, 270 insertions, 0 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()