Files
2026-08-16 18:33:03 +07:00

39 lines
1.5 KiB
Python

#!/usr/bin/env python3
"""Dump a GLB's baseColor + metallicRoughness atlas images side by side, so the
bake's colour fidelity can be eyeballed without any renderer in the way.
python3 scripts/glb_atlas.py in.glb [out.png]
"""
import sys, numpy as np, trimesh
from PIL import Image
path = sys.argv[1]; out = sys.argv[2] if len(sys.argv) > 2 else "glb_atlas.png"
scene = trimesh.load(path, process=False)
mesh = scene if isinstance(scene, trimesh.Trimesh) else list(scene.geometry.values())[0]
attrs = getattr(mesh.visual, "vertex_attributes", {})
if "color" in attrs:
color = np.asarray(attrs["color"])
print(f"vertex-colour GLB: {len(color):,} COLOR_0 values ({color.dtype}); no UV atlas")
sys.exit(0)
mat = mesh.visual.material
bc = mat.baseColorTexture.convert("RGB")
try:
mr = mat.metallicRoughnessTexture.convert("RGB")
except Exception:
mr = Image.new("RGB", bc.size)
W, H = bc.size
# downscale for a quick look if huge
scale = 1024 / max(W, H)
if scale < 1:
bc = bc.resize((int(W*scale), int(H*scale)))
mr = mr.resize((int(W*scale), int(H*scale)))
w, h = bc.size
canvas = Image.new("RGB", (w*2 + 16, h), (30, 30, 30))
canvas.paste(bc, (0, 0)); canvas.paste(mr, (w + 16, 0))
canvas.save(out)
a = np.asarray(bc, np.float64) / 255
nz = a.reshape(-1, 3); nz = nz[nz.sum(1) > 0.05]
print(f"atlas {W}x{H} baseColor mean(nonblack)={nz.mean(0).round(3) if len(nz) else 'n/a'} "
f"filled={len(nz)/(w*h)*100:.0f}%", flush=True)
print("wrote", out, flush=True)