Maddyson & ScanPatch
Maddyson Maddyson
Got a few ideas for streamlining the UV packing and script generation. Let’s hash out a workflow that cuts cycle time but keeps the precision we need.
ScanPatch ScanPatch
Sounds good, let’s nail the workflow. First, write a small batch script that loops through each asset folder, opens it in Blender headless mode, and runs a UV pack operator with a fixed margin. Add a pre‑check step that logs the polygon count and the UV island ratio—skip any mesh under 10k polys because that’s not worth the effort. Then export a CSV with the UV atlas image name, asset ID, and pack success flag. Finally, bundle the script with a one‑click launcher so you can pull the whole stack with a single command. That keeps the precision high and the cycle time low.
Maddyson Maddyson
Sure, here’s a quick outline: 1. `batch_uv_pack.bat` ```bat @echo off setlocal enabledelayedexpansion set LOG=uv_pack_log.txt set OUT=uv_atlas.csv echo AssetID,AtlasImage,Success>!OUT! for /d %%A in ("assets\*") do ( set ID=%%~nA blender --background "%%A\%%~nA.blend" --python-expr " import bpy, sys, os mesh = bpy.data.objects[0] poly_count = len(mesh.data.polygons) uv_ratio = sum([len(uv) for uv in mesh.data.uv_layers]) / poly_count print(f'{ID},{poly_count},{uv_ratio}') if poly_count < 10000: sys.exit() bpy.ops.object.select_all(action='DESELECT') mesh.select_set(True) bpy.ops.object.mode_set(mode='EDIT') bpy.ops.uv.smart_project(angle_limit=66, island_margin=0.02) bpy.ops.object.mode_set(mode='OBJECT') bpy.data.images['UV_Atlas'].save_render('%%A\\uv_atlas.png') " if errorlevel 1 ( echo !ID!,N/A,0>>!OUT! ) else ( echo !ID!,uv_atlas.png,1>>!OUT! ) ) ``` 2. `launcher.cmd` just calls `batch_uv_pack.bat`. Run `launcher.cmd` once, and you’ll get the CSV and logs. That’s the fastest route. Let me know if you need tweaks.
ScanPatch ScanPatch
Nice skeleton—just add a check that the atlas image isn’t >256 mb, otherwise you’ll get weird memory spikes. Also remember to set `UV_Atlas` to the correct name; a typo there will kill the whole batch. Once that’s fixed, a single click and you’ll have a clean log and perfect UVs.
Maddyson Maddyson
batch_uv_pack.bat @echo off setlocal enabledelayedexpansion set LOG=uv_pack_log.txt set OUT=uv_atlas.csv echo AssetID,AtlasImage,Success>!OUT! rem Define the correct image name used in the blend files set ATLAS_IMG=UV_Atlas for /d %%A in ("assets\*") do ( set ID=%%~nA blender --background "%%A\%%~nA.blend" --python-expr " import bpy, sys, os mesh = bpy.data.objects[0] poly_count = len(mesh.data.polygons) uv_ratio = sum([len(uv) for uv in mesh.data.uv_layers]) / poly_count print(f'{ID},{poly_count},{uv_ratio}') if poly_count < 10000: sys.exit() bpy.ops.object.select_all(action='DESELECT') mesh.select_set(True) bpy.ops.object.mode_set(mode='EDIT') bpy.ops.uv.smart_project(angle_limit=66, island_margin=0.02) bpy.ops.object.mode_set(mode='OBJECT') bpy.data.images['%ATLAS_IMG%'].save_render('%%A\\uv_atlas.png') " if errorlevel 1 ( echo !ID!,N/A,0>>!OUT! ) else ( rem Check the file size for %%F in ("%%A\\uv_atlas.png") do set size=%%~zF if !size! GTR 262144000 ( echo !ID!,uv_atlas.png,0>>!OUT! del "%%A\\uv_atlas.png" ) else ( echo !ID!,uv_atlas.png,1>>!OUT! ) ) ) rem End of script launcher.cmd @echo off call batch_uv_pack.bat Run launcher.cmd and you’ll get a clean log, the CSV, and no memory spikes. Let me know if you need anything else.
ScanPatch ScanPatch
Looks solid, just make sure the blend file actually creates an image named UV_Atlas before you call save_render, otherwise the script will crash. Also double‑check that the object list isn’t empty—if the first object isn’t the mesh you’re packing, the poly count will be wrong. Once those edge cases are ironed out, the batch will run cleanly.
Maddyson Maddyson
Got it. Here’s the tightened script. batch_uv_pack.bat @echo off setlocal enabledelayedexpansion set LOG=uv_pack_log.txt set OUT=uv_atlas.csv echo AssetID,AtlasImage,Success>!OUT! set ATLAS_IMG=UV_Atlas for /d %%A in ("assets\*") do ( set ID=%%~nA blender --background "%%A\%%~nA.blend" --python-expr " import bpy, sys # Find the first mesh object, fallback to None mesh = next((o for o in bpy.data.objects if o.type == 'MESH'), None) if not mesh: sys.exit() poly_count = len(mesh.data.polygons) if poly_count < 10000: sys.exit() uv_ratio = sum([len(uv) for uv in mesh.data.uv_layers]) / poly_count print(f'{ID},{poly_count},{uv_ratio}') # Make sure the UV image exists uv_img = bpy.data.images.get('%ATLAS_IMG%') if not uv_img: sys.exit() mesh.select_set(True) bpy.ops.object.mode_set(mode='EDIT') bpy.ops.uv.smart_project(angle_limit=66, island_margin=0.02) bpy.ops.object.mode_set(mode='OBJECT') uv_img.save_render('%%A\\uv_atlas.png') " if errorlevel 1 ( echo !ID!,N/A,0>>!OUT! ) else ( for %%F in ("%%A\\uv_atlas.png") do set size=%%~zF if !size! GTR 262144000 ( echo !ID!,uv_atlas.png,0>>!OUT! del "%%A\\uv_atlas.png" ) else ( echo !ID!,uv_atlas.png,1>>!OUT! ) ) ) launcher.cmd @echo off call batch_uv_pack.bat Run launcher.cmd. Edge cases handled, batch stays clean. Let me know if anything else crops up.