generate_asset: --baker vertex — IDW voxel-grid vertex-color baker (dark-patch fix)
Some checks are pending
CodeQL Advanced / Analyze (${{ matrix.language }}) (none, c-cpp) (push) Waiting to run
CodeQL Advanced / Analyze (${{ matrix.language }}) (none, python) (push) Waiting to run

Same sampler as trellis-mac TRELLIS2_BAKER=vertex; Metal texel path retained
as-is. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
m3ultra 2026-07-19 19:16:08 +10:00
parent 754d403e62
commit 746e727da2

View File

@ -212,6 +212,40 @@ def _export_pbr(mesh, path: Path, *, baker: str, target: Optional[int], texture_
faces = torch.from_numpy(simplified_faces).to(dtype=mesh.faces.dtype)
pre_simplified = True
if baker == "vertex":
# Dark-patch fix (MODELBEAST BENCHMARKS 2026-07-19): the Metal texel
# sampler mangles clean decoder attrs; sample the voxel grid at mesh
# vertices (cKDTree IDW, ~0.3s) and ship linear vertex colors.
import numpy as np
import trimesh
from scipy.spatial import cKDTree
v_np = vertices.numpy()
f_np = faces.numpy()
coords_np = mesh.coords.cpu().numpy().astype(np.float32)
if coords_np.shape[1] == 4:
coords_np = coords_np[:, 1:4]
attrs_np = mesh.attrs.float().cpu().numpy()
vsz = float(mesh.voxel_size)
origin = np.array([-0.5, -0.5, -0.5], np.float32)
tree = cKDTree(coords_np * vsz + origin + vsz * 0.5)
d, idx = tree.query(v_np, k=4, workers=-1)
w = 1.0 / (d + vsz * 0.05) ** 2
w[d > vsz * 1.5] = 0.0
ws = w.sum(1, keepdims=True)
has = (ws > 0).squeeze()
ws[ws == 0] = 1.0
rgb = np.clip(((attrs_np[idx] * (w / ws)[..., None]).sum(1))[:, 0:3], 0, 1)
rgb[~has] = np.clip(attrs_np[idx[~has, 0], 0:3], 0, 1)
v_gltf = np.stack([v_np[:, 0], v_np[:, 2], -v_np[:, 1]], axis=1)
out = trimesh.Trimesh(vertices=v_gltf, faces=f_np, process=False)
rgba = np.concatenate([rgb, np.ones((len(v_gltf), 1))], 1)
out.visual = trimesh.visual.ColorVisuals(
out, vertex_colors=(rgba * 255).astype(np.uint8)) # LINEAR
out.export(str(path))
return {"baker": "vertex", "pre_simplified": pre_simplified,
"triangles": int(len(f_np)), "vertices": int(len(v_np))}
if baker == "metal":
available, reason = _metal_baker_available()
if not available:
@ -394,7 +428,7 @@ def _parse_args():
parser.add_argument("image", type=Path)
parser.add_argument("--output-dir", type=Path, required=True)
parser.add_argument("--backend", choices=("auto", "mps", "mlx-experimental"), default="auto")
parser.add_argument("--baker", choices=("auto", "metal", "kdtree"), default="auto")
parser.add_argument("--baker", choices=("auto", "metal", "kdtree", "vertex"), default="auto")
parser.add_argument("--pipeline-type", choices=("512", "1024", "1024_cascade"), default="512")
parser.add_argument("--seed", type=int, default=42)
parser.add_argument("--steps", type=int)