1
$\begingroup$

I am trying to automate some fairly tedious model prep steps before exporting a mesh to Unity. It creates 2 extra UV maps with special conditions and then slices and resizes all the mesh faces to very small sizes using the Individual Origins pivot for each face. Unfortunately, the line of code that actually runs the resizing instantly crashes Blender with no error that I can find. I have also tried iterating through the faces to resize them individually instead of all at once.

What am I doing wrong here? I am a novice at python and blender automations but I am bumbling my way through it. The problem is the very last line. Everything else works up until then.

import os

# Get the directory of the current .blend file
current_directory = os.path.dirname(bpy.data.filepath)
export_directory = os.path.join(current_directory, "export")

# Create the export directory if it doesn't exist
os.makedirs(export_directory, exist_ok=True)

# Store the current area type
previous_area_type = bpy.context.area.type

# Activate the UV/Image Editor
bpy.context.area.ui_type = 'UV'


# Loop through all objects in the scene
for obj in bpy.context.scene.objects:
    if obj.type == 'MESH':
        # Remember the active object
        original_object = obj

        # Step 1: Create a second UV map
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.uv_texture_add()

        # Step 2: Default UV unwrap for the second UV map
        bpy.ops.uv.unwrap()

        # Step 3: Reset UVs on the second UV map
        bpy.ops.mesh.select_all(action='SELECT')  # Select all faces/UVs
        bpy.ops.uv.select_all(action='SELECT')
        bpy.ops.uv.reset()
        bpy.context.object.data.uv_layers.active.name = "ResetMap"  # Rename the second UV map

        # Step 4: Create a third UV map
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.select_all(action='DESELECT')
        original_object.select_set(True)
        bpy.context.view_layer.objects.active = original_object

        # Create a new UV map for the active object
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.uv_texture_add()
        bpy.ops.object.mode_set(mode='OBJECT')

        # Rename the UV map to "RandomMap"
        original_object.data.uv_layers[-1].name = "RandomMap"

        # Step 5: Lightmap Pack project the UVs on the third UV map
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.uv.lightmap_pack(PREF_CONTEXT='SEL_FACES', PREF_PACK_IN_ONE=True, PREF_NEW_UVLAYER=False, PREF_BOX_DIV=12, PREF_MARGIN_DIV=0.1)

        # Step 6: Switch to UV Editing mode
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.uv.unwrap(method='ANGLE_BASED')  # Angle-based unwrap for the third UV map

       # Step 7: Scale UVs on the third UV map
        bpy.context.area.type = 'IMAGE_EDITOR'
        bpy.ops.uv.select_all(action='SELECT')
        bpy.context.space_data.pivot_point = 'INDIVIDUAL_ORIGINS'
        bpy.ops.transform.resize(value=(0.01, 0.01, 0.01), orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', mirror=False, use_proportional_edit=True, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False, snap=False, snap_elements={'INCREMENT'}, use_snap_project=False, snap_target='CLOSEST', use_snap_self=True, use_snap_edit=True, use_snap_nonedit=True, use_snap_selectable=False)



        # Step 8: Split the mesh 'Faces by Edges'
        bpy.context.area.ui_type = 'VIEW_3D'
        bpy.ops.mesh.select_all(action='SELECT')
        bpy.ops.mesh.split()
        bpy.context.scene.tool_settings.transform_pivot_point = 'INDIVIDUAL_ORIGINS'
        bpy.ops.transform.resize(value=(0.001, 0.001, 0.001), orient_type='LOCAL')
$\endgroup$

1 Answer 1

3
$\begingroup$

The culprit is not the last line but bpy.context.area.ui_type = 'VIEW_3D'. You can verify this by running this minimal script

import bpy

for obj in bpy.context.scene.objects:
    if obj.type == 'MESH':
        #bpy.context.area.ui_type = 'VIEW_3D'   # <-- enable for crash
        bpy.ops.transform.resize(value=(0.001, 0.001, 0.001), orient_type='LOCAL')
    

You need to use the correct context and normally you use some temporary override. Here is how it's done the old way but since some Blender 3.x you get a warning in the system console (but its still working):

DeprecationWarning: Passing in context overrides is deprecated in favor of Context.temp_override(..)

Therefore, try this code for Step 8. Overriding the context avoids the crash and also makes sure that the individual origin option works.

# Step 8: Split the mesh 'Faces by Edges'
bpy.context.area.ui_type = 'VIEW_3D'

area = [area for area in bpy.context.screen.areas if area.type == "VIEW_3D"][0]
region = [region for region in area.regions if region.type == 'WINDOW'][0]

with bpy.context.temp_override(area=area, region=region):
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_mode(type='EDGE')
    bpy.ops.mesh.select_all(action='SELECT')
    
    bpy.ops.mesh.edge_split()

    bpy.ops.mesh.select_mode(type='FACE')
    bpy.context.scene.tool_settings.transform_pivot_point = 'INDIVIDUAL_ORIGINS'
    bpy.ops.transform.resize(value=(0.001, 0.001, 0.001), orient_type='LOCAL')
$\endgroup$
2
  • 1
    $\begingroup$ Awesome, I will give this a try. I am learning a lot about contexts and how tricky they can be. $\endgroup$ Aug 14, 2023 at 18:15
  • 1
    $\begingroup$ the old way of context override will stop working in version 4.0. for more info on context overriding see here $\endgroup$ Aug 16, 2023 at 12:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .