Using AI to Write Blender Python Scripts for Your Unity Pipeline

Illustration: a code ribbon wrapping around a 3D model and exporting it as a glowing package

If you export more than a handful of models from Blender to Unity, the same chores come up every time: apply transforms, fix names, move each object to the origin, export with the right FBX settings, repeat. Blender’s Python API can do all of it in one click, and AI assistants are good at writing that code once you know how to steer them. This guide shows how to use AI to write Blender Python scripts for your Unity pipeline: batch FBX export, applying transforms, renaming, generating LODs, running scripts headless, and debugging the errors AI-written bpy code throws.

Why AI and bpy Are a Good Match (With Caveats)

Blender’s Python module, bpy, exposes nearly everything in the UI. Pipeline scripts are short, repetitive and well documented, which is the sweet spot for AI code generation.

The catch is that the API has changed a lot. Code from the Blender 2.7x era used obj.select = True and scene.objects.active, which no longer exist. Blender 4.0 removed the old dictionary-style context override for operators. Blender 4.1 removed mesh.use_auto_smooth. AI models have seen years of old forum answers, so they mix eras. Always tell the AI your exact Blender version, and expect to fix a line or two.

A Prompt That Gets Working bpy Code

Write a Blender Python script for Blender 4.2 LTS.

Context: I export models to Unity 6. Each top-level mesh object in the
"Export" collection should become its own FBX file in a folder called
"exports" next to the .blend file.

Rules:
- Use the current 4.x API only. No 2.7x APIs, no dict context overrides
  (use bpy.context.temp_override if a context is needed).
- Prefer bpy.data over bpy.ops where possible.
- Restore the original selection and object positions at the end.
- Print one line per exported file and a summary.
- Add a DRY_RUN flag at the top that prints what would happen
  without writing files.

FBX settings: apply_scale_options='FBX_SCALE_UNITS', axis_forward='-Z',
axis_up='Y', bake_space_transform=True, use_mesh_modifiers=True,
add_leaf_bones=False, no animation.

Spelling out the FBX settings matters. If you leave them out, the AI picks its own, and you’re back to models importing rotated or at the wrong scale. Use whatever settings you settled on in our Blender to Unity FBX export settings guide, which explains what each one does.

The DRY_RUN flag is a cheap safety net. Scripts that rename or apply things change your .blend, and Blender’s undo doesn’t always cover everything a script does. Save first, or work on a copy.

Script 1: Batch Export Each Object to FBX

Here is a cleaned-up version of what that prompt should produce. It exports every top-level object in a collection named Export, with its children, moved to the world origin so the pivot lands at zero in Unity.

import bpy
import os

COLLECTION_NAME = "Export"
EXPORT_DIR = bpy.path.abspath("//exports")
DRY_RUN = False


def export_object(obj):
    # Select the object and its whole hierarchy
    bpy.ops.object.select_all(action='DESELECT')
    obj.select_set(True)
    for child in obj.children_recursive:
        child.select_set(True)
    bpy.context.view_layer.objects.active = obj

    file_name = bpy.path.clean_name(obj.name) + ".fbx"
    path = os.path.join(EXPORT_DIR, file_name)

    if DRY_RUN:
        print("Would export:", path)
        return

    bpy.ops.export_scene.fbx(
        filepath=path,
        use_selection=True,
        object_types={'EMPTY', 'MESH', 'ARMATURE'},
        apply_unit_scale=True,
        apply_scale_options='FBX_SCALE_UNITS',
        axis_forward='-Z',
        axis_up='Y',
        bake_space_transform=True,
        use_mesh_modifiers=True,
        mesh_smooth_type='FACE',
        add_leaf_bones=False,
        bake_anim=False,
        path_mode='AUTO',
    )
    print("Exported:", path)


def main():
    if not bpy.data.filepath:
        raise RuntimeError("Save the .blend first so the export folder has a location.")
    if bpy.context.mode != 'OBJECT':
        bpy.ops.object.mode_set(mode='OBJECT')

    collection = bpy.data.collections.get(COLLECTION_NAME)
    if collection is None:
        raise RuntimeError(f"No collection named '{COLLECTION_NAME}'.")

    os.makedirs(EXPORT_DIR, exist_ok=True)
    original_selection = list(bpy.context.selected_objects)
    original_active = bpy.context.view_layer.objects.active

    roots = [o for o in collection.objects if o.parent is None]
    for obj in roots:
        saved_location = obj.location.copy()
        obj.location = (0.0, 0.0, 0.0)
        try:
            export_object(obj)
        finally:
            obj.location = saved_location

    bpy.ops.object.select_all(action='DESELECT')
    for o in original_selection:
        o.select_set(True)
    bpy.context.view_layer.objects.active = original_active
    print(f"Done: {len(roots)} object(s).")


main()

Notes on the choices:

  • bpy.path.abspath("//exports") resolves // to the folder of the saved .blend, which is why the script refuses to run on an unsaved file.
  • try/finally puts each object back where it was, even if an export fails halfway.
  • Objects that are hidden or disabled in the viewport can’t be selected, so they won’t export. That’s a frequent “why is the FBX empty” cause.
  • Textures: path_mode='AUTO' keeps texture paths as-is. If you want textures packed inside the FBX, use path_mode='COPY' with embed_textures=True.

Script 2: Apply Transforms and Clean Names

Unapplied rotation and scale are the root of most “rotated 90 degrees” and “wrong scale” problems in Unity. This script applies rotation and scale on every selected mesh, strips Blender’s .001 suffixes, adds an SM_ prefix, and renames the mesh data to match.

import bpy
import re

PREFIX = "SM_"

meshes = [o for o in bpy.context.selected_objects if o.type == 'MESH']

# Apply rotation and scale (location stays, so objects don't jump)
bpy.ops.object.select_all(action='DESELECT')
for obj in meshes:
    obj.select_set(True)
if meshes:
    bpy.context.view_layer.objects.active = meshes[0]
    bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)

# Clean names
for obj in meshes:
    base = re.sub(r"\.\d{3}$", "", obj.name)
    if not base.startswith(PREFIX):
        base = PREFIX + base
    obj.name = base
    obj.data.name = obj.name   # mesh data name shows up in Unity too
    print("Cleaned:", obj.name)

Two honest caveats. If two objects end up with the same clean name, Blender adds .001 again, because names must be unique. And transform_apply refuses to run on meshes shared by several objects (linked duplicates). See the troubleshooting section for that error. The manual version of this fix, and why it matters, is in our guide to the -90 X rotation problem.

💻 Batch exports eat CPU time

Scripts make export fast, but decimating, baking and rendering previews for a big asset library still lean hard on your CPU and RAM. If Blender and Unity together slow your machine to a crawl, see the laptops we tested that handle both without costing a fortune.

See our budget Unity laptop picks →

Script 3: Generate LOD Copies

Unity can build a LOD Group for you on import when meshes are named with _LOD0, _LOD1 and so on. This script makes decimated copies of each selected mesh with those names, using a Decimate modifier so the original stays editable.

import bpy

RATIOS = [0.5, 0.25]   # LOD1 = 50% of the triangles, LOD2 = 25%

for obj in [o for o in bpy.context.selected_objects if o.type == 'MESH']:
    base = obj.name.removesuffix("_LOD0")
    obj.name = base + "_LOD0"

    for level, ratio in enumerate(RATIOS, start=1):
        lod = obj.copy()
        lod.data = obj.data.copy()
        lod.name = f"{base}_LOD{level}"
        for collection in obj.users_collection:
            collection.objects.link(lod)

        mod = lod.modifiers.new(name="LOD_Decimate", type='DECIMATE')
        mod.decimate_type = 'COLLAPSE'
        mod.ratio = ratio
        print("Created", lod.name, "ratio", ratio)

obj.copy() keeps the same parent and transform, and use_mesh_modifiers=True in the export script bakes the Decimate result into the FBX. Decimate is quick, not pretty: check each LOD in the viewport, especially UV seams and thin parts. Grouping, naming rules and sensible triangle budgets are covered in our Blender LODs for Unity guide.

Running Scripts in Blender and Headless

Inside Blender: switch to the Scripting workspace, click New in the Text Editor, paste the script and use Text > Run Script (Alt+P). Output from print() goes to the system console, not the Python Console panel. On Windows, open it with Window > Toggle System Console.

Headless, from a terminal: no UI, ideal for exporting a whole folder of .blend files or letting an AI agent run the pipeline for you.

blender -b "C:\Art\props.blend" --python export_collection.py

-b runs in background mode. Anything after -- is ignored by Blender and left for your script, which you can read with sys.argv[sys.argv.index("--") + 1:]. A terminal-based assistant such as Claude Code can run this command, read the printed output and fix its own script, though you should still review changes before letting it overwrite files.

Some operators depend on the UI and fail in background mode. Scripts that stick to bpy.data and object-mode operators like the ones above work fine.

Debugging AI-Written Blender Scripts

When a script fails, give the AI what it needs to fix it:

  • The full traceback from the system console, not just the last line.
  • Your Blender version from Help > About Blender, again.
  • What the scene looked like: which mode you were in, what was selected, which collection.

Two built-in tools help you check AI claims:

  • Python tooltips. Enable them in Edit > Preferences > Interface. Hovering any button then shows its Python path, so you can see the real property or operator name.
  • The Info editor logs the Python call for operators you run by hand. Do the step manually once, copy the logged line and give it to the AI as ground truth.

A good follow-up prompt: “Before fixing, tell me which Blender version introduced or removed each API you used.” It won’t always be right, but it often flags its own outdated calls.

Troubleshooting

“AttributeError: ‘Object’ object has no attribute ‘select’”

2.7x code. Replace obj.select = True with obj.select_set(True), and scene.objects.active = obj with bpy.context.view_layer.objects.active = obj.

“AttributeError: ‘Mesh’ object has no attribute ‘use_auto_smooth’”

Auto Smooth was removed in Blender 4.1. Ask the AI for a version that uses Shade Auto Smooth (bpy.ops.object.shade_auto_smooth()) or just shade_smooth, depending on what you need.

“RuntimeError: Operator bpy.ops.object.mode_set.poll() failed, context is incorrect”

The operator ran without an active object, or in a context where it isn’t allowed, such as background mode with nothing selected. Set an active object first, or use bpy.context.temp_override() to supply the context.

“Cannot apply to a multi user”

The mesh is shared by linked duplicates. Make it single-user first (Object > Relations > Make Single User) or skip shared meshes in the script.

The FBX exports but is empty, or missing objects

Objects were hidden, disabled in the viewport, or excluded from the view layer, so they couldn’t be selected. Also check that object_types includes everything you need.

Everything imports into Unity rotated or scaled wrong

The AI changed your FBX settings or left them at defaults. Compare every argument in the export call against the settings you trust.

FAQ

Can ChatGPT or Claude write Blender Python scripts?

Yes, and they are usually close. Expect version-related mistakes, so always state your Blender version and test on a copy of your file.

Should I use bpy.ops or bpy.data?

Prefer bpy.data for creating, renaming and editing data, because it doesn’t depend on selection or context. Use bpy.ops for things only operators do, like the FBX exporter or applying transforms.

Can I turn a script into a button in Blender?

Yes. Ask the AI to wrap it in an Operator class and a Panel in the sidebar, registered as an add-on. That’s a natural next step once the script works.

Can Unity run my Blender export automatically?

Unity can import .blend files directly if Blender is installed, but a scripted FBX export gives you control over settings and works on machines without Blender.

Is it safe to run AI-generated Python in Blender?

Python in Blender can read and delete files like any program. Read the script before running it, and be wary of anything touching paths outside your project.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *