Files
animation/characters/work/lena/37_sheets.py
T
jeremy 3d8825f5a9 reorg(characters): ship-time folders — lena_base_v01 ships, lane moves to work/lena
REGISTRY rewritten around the central rule: a character folder is born only
when a body ships to ariki-game (<character>_base_v<NN> = ship ordinal).
lena_nude dissolves accordingly:
- characters/female/lena_base_v01/ — SHIPPED 2026-08-10: AccuRig GLB carrier,
  T-pose/rig FBX + JSON, previews, frozen README
- characters/work/lena/ — the live lane: recipes 01-47 (incl. new 36-47:
  refill/sheets/clay/despeckle/musculature/spin/AccuRig export/graft/pose QC),
  masters (athletic_v04 blend + textures, accurig blend), lane-history README
- hires_claude/hires_work intermediates (blends, logs, probes) pruned

Supporting docs: AGENTS.md, working-files rule, rig-graft plan addendum,
originals README, prune_lane.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 07:17:15 -07:00

79 lines
2.6 KiB
Python

# Stage 37 (read-only): compose before/after review sheets.
#
# blender --background --python 37_sheets.py -- <out_dir>
#
# "Before" is the body as it was handed to this lane: decimated v01, Tripo's 5,870-chart atlas,
# single-sided (so the inward-wound patches are culled into grey tears). "After" is v04.
import bpy, sys, os
import numpy as np
OUT = os.path.abspath(sys.argv[sys.argv.index("--") + 1])
os.makedirs(OUT, exist_ok=True)
HERE = os.path.dirname(os.path.abspath(__file__))
def load(p):
im = bpy.data.images.load(p)
w, h = im.size
b = np.empty(w * h * 4, dtype=np.float32)
im.pixels.foreach_get(b)
a = b.reshape(h, w, 4)[:, :, :3].copy()
bpy.data.images.remove(im)
return a[::-1]
def fit(a, w, h):
ys = (np.arange(h) * (a.shape[0] / h)).astype(int).clip(0, a.shape[0] - 1)
xs = (np.arange(w) * (a.shape[1] / w)).astype(int).clip(0, a.shape[1] - 1)
return a[ys][:, xs]
def save(a, name):
h, w = a.shape[:2]
img = bpy.data.images.new(name, w, h, alpha=False)
buf = np.ones((h, w, 4), dtype=np.float32)
buf[:, :, :3] = np.clip(a, 0, 1)[::-1]
img.pixels.foreach_set(buf.reshape(-1))
p = os.path.join(OUT, name)
img.file_format = 'JPEG'
img.filepath_raw = p
img.save(filepath=p)
print(f"wrote {p} {w}x{h} {os.path.getsize(p)/1e6:.2f} MB", flush=True)
GAP = 10
BG = 0.10
def grid(rows, cell_w, cell_h):
nrow, ncol = len(rows), max(len(r) for r in rows)
W = ncol * cell_w + (ncol + 1) * GAP
H = nrow * cell_h + (nrow + 1) * GAP
sheet = np.full((H, W, 3), BG)
for r, row in enumerate(rows):
for c, p in enumerate(row):
if p is None:
continue
y = GAP + r * (cell_h + GAP)
x = GAP + c * (cell_w + GAP)
sheet[y:y + cell_h, x:x + cell_w] = fit(load(p), cell_w, cell_h)
return sheet
B4 = os.path.join(HERE, "beauty_input_v01") # as handed over: Tripo atlas, single-sided
AF = os.path.join(HERE, "beauty_refill_v04") # now
save(grid([[os.path.join(B4, "full_front.png"), os.path.join(AF, "full_front.png")],
[os.path.join(B4, "chest.png"), os.path.join(AF, "chest.png")],
[os.path.join(B4, "hip.png"), os.path.join(AF, "hip.png")]],
900, 900), "sheet_body_before_after.jpg")
save(grid([[os.path.join(HERE, "probe_atlas", "basecolor.png"),
os.path.join(HERE, "refill_v04", "lena_nude_refill_base.jpg")]],
1000, 1000), "sheet_atlas_before_after.jpg")
save(grid([[os.path.join(HERE, "probe_atlas", "islands.png"),
os.path.join(HERE, "atlas_v03", "charts.png")]],
1000, 1000), "sheet_charts_before_after.jpg")
print("SHEETS_DONE")