{"id":1742,"date":"2017-08-02T18:05:54","date_gmt":"2017-08-02T16:05:54","guid":{"rendered":"http:\/\/www.edy.es\/dev\/?page_id=1742"},"modified":"2024-02-12T16:14:26","modified_gmt":"2024-02-12T15:14:26","slug":"blender-scripting-cookbook","status":"publish","type":"page","link":"https:\/\/www.edy.es\/dev\/docs\/blender-scripting-cookbook\/","title":{"rendered":"Blender Scripting Cookbook"},"content":{"rendered":"<h2>Using scripts in Blender<\/h2>\n<p>Easy:<\/p>\n<ol>\n<li>Open the <strong>Text Editor<\/strong>.<\/li>\n<li>Press <strong>New<\/strong> to create new text. Give an optional name.<\/li>\n<li>Write \/ paste the script.<\/li>\n<li>Press <strong>Run Script<\/strong>.<\/li>\n<\/ol>\n<p>It really worth learning some <a href=\"https:\/\/en.wikibooks.org\/wiki\/Python_Programming\">Python basics<\/a>!<\/p>\n<p style=\"padding-left: 30px;\"><a href=\"https:\/\/docs.blender.org\/api\/blender_python_api_current\/\">Blender API reference<\/a><\/p>\n<p style=\"padding-left: 30px;\"><a href=\"https:\/\/docs.blender.org\/api\/blender_python_api_current\/bpy.ops.html\">Operator reference<\/a>: operations in the same way as they would be done by interacting with the editor. Example: <a href=\"https:\/\/docs.blender.org\/api\/blender_python_api_current\/bpy.ops.mesh.html\">mesh operators<\/a><br \/>\n<a href=\"https:\/\/docs.blender.org\/api\/blender_python_api_current\/bpy.types.html\">Types reference<\/a>: properties and methods available from scripting at datablock level. Example:\u00a0<a href=\"https:\/\/docs.blender.org\/api\/blender_python_api_current\/bpy.types.Mesh.html\">mesh types<\/a><\/p>\n<p>Some useful collections:<\/p>\n<pre>bpy.context.object                # Active object (last object selected)\r\nbpy.context.selected_objects      # All selected objects \r\ncontext.scene.objects             # All objects in current scene\r\nbpy.data.objects                  # All objects \r\nbpy.data.meshes                   # All meshes<\/pre>\n<p><a href=\"https:\/\/docs.blender.org\/api\/blender_python_api_2_76b_release\/bpy.types.BlendData.html#bpy.types.BlendData\">All bpy.data elements<\/a><\/p>\n<h3>Reset Parent Inverse<\/h3>\n<p>Clear the parent inverse without actually moving the\u00a0object.<\/p>\n<p><em>This script assumes you have the child selected.<\/em><\/p>\n<pre>import bpy\r\nob = bpy.context.object\r\n\r\n# store a copy of the objects final transformation\r\n# so we can read from it later.\r\nob_matrix_orig = ob.matrix_world.copy()\r\n\r\n# reset parent inverse matrix\r\n# (relationship created when parenting)\r\nob.matrix_parent_inverse.identity()\r\n\r\n# re-apply the difference between parent\/child\r\n# (this writes directly into the loc\/scale\/rot) via a matrix.\r\nob.matrix_basis = ob.parent.matrix_world.inverted() @ ob_matrix_orig<\/pre>\n<p><a href=\"https:\/\/blender.stackexchange.com\/questions\/28896\/how-to-clear-parent-inverse-without-actually-moving-the-object\/28897#28897\">Source<\/a><\/p>\n<h3>Remove animation data<\/h3>\n<pre>import bpy\r\n\r\ncontext = bpy.context\r\nfor ob in context.selected_objects:\r\n    ob.animation_data_clear()<\/pre>\n<p>Replace <code>context.selected_objects<\/code> with <code>context.scene.objects<\/code> for all in the current scene, or <code>bpy.data.objects<\/code> to remove all animation data from all objects.<\/p>\n<p><a href=\"https:\/\/blender.stackexchange.com\/questions\/15198\/delete-animation-of-object\/43162#43162\">Source<\/a><\/p>\n<h3>Update image files to other format (e.g. dds to png) (Blender 2.8+)<\/h3>\n<pre>import os \r\n\r\nfor img in bpy.data.images:\r\n    if img.source == \"FILE\":\r\n        img.filepath = os.path.splitext(img.filepath)[0] + '.png'\r\n        img.reload()<\/pre>\n<p>Use after converting .dds images to .png with some tool (e.g. <a href=\"https:\/\/www.edy.es\/dev\/docs\/imagemagick-cookbook\/\">image magick<\/a>).<\/p>\n<h3>Remove inactive UV maps from the selected objects (Blender 2.8+)<\/h3>\n<pre>import bpy\r\n\r\nfor ob in bpy.context.selected_objects:\r\n    if ob.type == 'MESH':\r\n        i = 0\r\n        while i &lt; len(ob.data.uv_layers):\r\n            ob.data.uv_layers.active_index = i\r\n            if ob.data.uv_layers.active.active_render:\r\n                i += 1\r\n            else:\r\n                ob.data.uv_layers.remove(ob.data.uv_layers.active)<\/pre>\n<h3>Remove vertex colors<\/h3>\n<p>This script also shows how to remove all elements in a <code>bpi_prop_collection<\/code> list (it seems there&#8217;s no <em>clear<\/em> method or equivalent).<\/p>\n<p><em>This script assumes you have a mesh object selected.<\/em><\/p>\n<pre>import bpy\r\n\r\nob = bpy.context.object\r\nwhile len(ob.data.vertex_colors) &gt; 0:\r\n    ob.data.vertex_colors.active_index = 0\r\n    ob.data.vertex_colors.remove(ob.data.vertex_colors.active)<\/pre>\n<h3>Find broken images<\/h3>\n<p>Selects objects containing materials with textures pointing to missing image files<\/p>\n<pre>import bpy\r\n\r\ncontext = bpy.context\r\nfor ob in bpy.data.objects:\r\n    if ob.type == 'MESH':\r\n        for mat in ob.data.materials:\r\n            for tex in mat.texture_slots:\r\n                if tex and tex.texture and tex.texture.image and not tex.texture.image.has_data:\r\n                    print(ob.name, mat.name, tex.texture.image.filepath)\r\n                    ob.select_set(True)<\/pre>\n<h3>Animate labels\u00a0in the video sequencer<\/h3>\n<p><a href=\"https:\/\/blender.stackexchange.com\/questions\/7904\/how-can-i-make-dynamic-text-in-an-animation\">Source<\/a><\/p>\n<h4>Show current frame<\/h4>\n<pre>import bpy\r\n\r\nscene = bpy.context.scene\r\nobj = scene.sequence_editor.sequences_all[\"Text.001\"]\r\n\r\ndef recalculate_text(scene):\r\n  obj.text = 'Current frame: ' + str(scene.frame_current)\r\n\r\nbpy.app.handlers.frame_change_pre.append(recalculate_text)<\/pre>\n<h4>Show elapsed time<\/h4>\n<pre>import bpy\r\n\r\nscene = bpy.context.scene\r\nobj = scene.sequence_editor.sequences_all[\"Text.001\"]\r\n\r\ndef recalculate_text(scene):\r\n   fps = scene.render.fps \/ scene.render.fps_base # actual framerate\r\n   obj.text = 'Elapsed time: {0:.1f} seconds'.format(scene.frame_current\/fps)\r\n\r\nbpy.app.handlers.frame_change_pre.append(recalculate_text)<\/pre>\n<h2>Bonus: Writing Blender Addons (updated for Blender 2.80)<\/h2>\n<p>Any of the above scripts may be added to Blender as operator via add-on.<\/p>\n<p>Useful: Addon for\u00a0<a href=\"https:\/\/blenderartists.org\/forum\/showthread.php?312821-Run-Script-in-PyConsole-%2528Menu%2529\">Running scripts in the Python console<\/a>\u00a0(or\u00a0<a href=\"https:\/\/blender.stackexchange.com\/questions\/5394\/is-there-anyway-to-make-blender-print-errors-in-the-ui\/81897#81897\">directly using the python console<\/a>, no addon)<\/p>\n<p>Example: this is the script Clear parent inverse without actually moving the object turned into addon:<\/p>\n<pre>bl_info = {\r\n    \"name\": \"Reset Parent Inverse\",\r\n    \"category\": \"Object\",\r\n    \"blender\": (2, 80, 0),\r\n}\r\n\r\nimport bpy\r\n\r\nclass ObjectResetParentInverse(bpy.types.Operator):\r\n    \"\"\"Applies parent inverse and resets it. Object transform becomes relative to the parent. Actual visible position won't change.\"\"\"      # blender will use this as a tooltip for menu items and buttons.\r\n    bl_idname = \"object.reset_parent_inverse\"                                                                                               # unique identifier for buttons and menu items to reference.\r\n    bl_label = \"Reset Parent Inverse\"                                                                                                       # display name in the interface.\r\n    bl_options = {'REGISTER', 'UNDO'}                                                                                                       # enable undo for the operator.\r\n\r\n    def execute(self, context):        # execute() is called by blender when running the operator.\r\n        \r\n        for ob in context.selected_objects:\r\n            # store a copy of the objects final transformation\r\n            # so we can read from it later.\r\n            ob_matrix_orig = ob.matrix_world.copy()\r\n\r\n            # reset parent inverse matrix\r\n            # (relationship created when parenting)\r\n            ob.matrix_parent_inverse.identity()\r\n\r\n            # re-apply the difference between parent\/child\r\n            # (this writes directly into the loc\/scale\/rot) via a matrix.\r\n            ob.matrix_basis = ob.parent.matrix_world.inverted() @ ob_matrix_orig\r\n        \r\n        return {'FINISHED'}            # this lets blender know the operator finished successfully.\r\n    \r\ndef register():\r\n    bpy.utils.register_class(ObjectResetParentInverse)\r\n\r\ndef unregister():\r\n    bpy.utils.unregister_class(ObjectResetParentInverse)\r\n\r\n# This allows you to run the script directly from blenders text editor\r\n# to test the addon without having to install it.\r\nif __name__ == \"__main__\":\r\n    register()<\/pre>\n<h4>Write and test the addon:<\/h4>\n<ol>\n<li>Open the Text Editor.<\/li>\n<li>Create new text (New button). Give an optional name.<\/li>\n<li>Write \/ paste the script.<\/li>\n<li>Run Script. This\u00a0registers the operator, but doesn&#8217;t run it.<\/li>\n<li>Press SpaceBar to bring up the operator search dialog and type in the operator&#8217;s label, then press Enter.<\/li>\n<\/ol>\n<p><a href=\"https:\/\/docs.blender.org\/api\/blender_python_api_2_65_release\/info_tutorial_addon.html#write-the-addon-simple\">Source<\/a><\/p>\n<h4>Install the addon:<\/h4>\n<ol>\n<li>Save the file to disk (<strong>Text -&gt; Save As<\/strong> in the Text Editor) with <code>.py<\/code> extension.<\/li>\n<li><strong>File -&gt; User Preferences<\/strong>, selected the <strong>Addon<\/strong> section, press <strong>Install Addon&#8230;<\/strong> and select the file.<\/li>\n<li>Enable the addon by pressing the check-box.<\/li>\n<li>Press <strong>Save User Settings<\/strong>\u00a0if you want it to be enabled on other files.<\/li>\n<\/ol>\n<p><a href=\"https:\/\/docs.blender.org\/api\/blender_python_api_2_65_release\/info_tutorial_addon.html#install-the-addon\">Source<\/a><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using scripts in Blender Easy: Open the Text Editor. Press New to create new text. Give an optional name. Write \/ paste the script. Press Run Script. It really worth learning some Python basics! Blender API reference Operator reference: operations in the same way as they would be done by interacting with the editor. Example: [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1755,"parent":228,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"page-c.php","meta":{"jetpack_post_was_ever_published":false,"footnotes":""},"class_list":["post-1742","page","type-page","status-publish","has-post-thumbnail","hentry"],"jetpack_shortlink":"https:\/\/wp.me\/P1PjRF-s6","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/pages\/1742","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/comments?post=1742"}],"version-history":[{"count":28,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/pages\/1742\/revisions"}],"predecessor-version":[{"id":2007,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/pages\/1742\/revisions\/2007"}],"up":[{"embeddable":true,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/pages\/228"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/media\/1755"}],"wp:attachment":[{"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/media?parent=1742"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}