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>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# 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")
|
||||
Reference in New Issue
Block a user