Maddyson & ScanPatch
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.
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.
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.
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.
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.
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.
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.