From ba4e2ad42b15baeed9d3b29113fb0c3c2931c469 Mon Sep 17 00:00:00 2001 From: m3ultra Date: Wed, 22 Jul 2026 19:36:04 +1000 Subject: [PATCH] =?UTF-8?q?generate=5Fasset:=20meshgod-grade=20metal=20PBR?= =?UTF-8?q?=20lane=20=E2=80=94=20RAM-sized=20face=20cap,=20forced-opaque?= =?UTF-8?q?=20alpha,=204096=20textures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SAFETY_FACE_TARGET: flat 200k laptop mtlbvh guard -> RAM-sized (>=96GB Studios get 500k ~ fal-parity detail; TRELLIS2_MAX_BAKE_FACES override, 0 = uncapped) - _force_opaque: rewrite GLB materials to alphaMode OPAQUE after metal/ kdtree bakes — o_voxel's noisy baked alpha + min<250 BLEND auto-detect rendered solid hair as a transparent speckle veil (TRELLIS2_ALPHA_MODE=auto keeps baked alpha for glassy subjects) - --texture-size: allow 4096 m3ultra verified (seed 0, 1024_cascade, metal@500k): 156s total, 26.2GB peak, candidate_pbr 391,782 tris + 2048 PBR textures, raw master 2.19M tris — vs 94,535-face BLEND output before. Co-Authored-By: Claude Fable 5 --- scripts/generate_asset.py | 59 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/scripts/generate_asset.py b/scripts/generate_asset.py index f91987f..f4422d4 100755 --- a/scripts/generate_asset.py +++ b/scripts/generate_asset.py @@ -37,7 +37,23 @@ from trellis2.model_revisions import ( # noqa: E402 TRELLIS_REVISION, ) -SAFETY_FACE_TARGET = 200_000 +def _default_safety_faces() -> int: + """RAM-sized pre-bake face cap (MODELBEAST BENCHMARKS 2026-07-22): the + flat 200k laptop mtlbvh guard crushed 2.2M-tri decodes to ~95k-face GLBs + (fal ships ~495k from the same weights). 500k is verified crash-free on + the M3 Ultra Studio; small-memory boxes keep the safe cap. Env override: + TRELLIS2_MAX_BAKE_FACES (0 = uncapped).""" + env = os.environ.get("TRELLIS2_MAX_BAKE_FACES") + if env is not None: + return int(env) or 10_000_000 + try: + mem_gb = os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES") / 1e9 + except (ValueError, OSError): + mem_gb = 0 + return 500_000 if mem_gb >= 96 else 200_000 + + +SAFETY_FACE_TARGET = _default_safety_faces() WATCHDOG_SIGNATURES = ( "non-zero size", "BVH needs at least 8 triangles", @@ -165,6 +181,43 @@ def _export_raw(mesh, path: Path) -> dict[str, Any]: } +def _force_opaque(glb_path: Path) -> None: + """Rewrite every material's alphaMode to OPAQUE in a GLB, in place. + + The o_voxel Metal baker samples the decoder's alpha attr noisily (same + family as the dark-patch base-color bug): solid hair bakes with scattered + near-zero alpha texels, to_glb's min<250 auto-detect flips the material + to BLEND, and the model renders as a transparent speckle veil. + TRELLIS2_ALPHA_MODE=auto keeps the baked behaviour for genuinely + transparent subjects (glass etc.); the default assumes solid objects. + """ + import struct + + data = glb_path.read_bytes() + magic, version, _length = struct.unpack_from(" tuple[bool, str]: try: from trellis2.backends import probe_metal_backends @@ -273,6 +326,8 @@ def _export_pbr(mesh, path: Path, *, baker: str, target: Optional[int], texture_ verbose=True, ) result.export(path) + if os.environ.get("TRELLIS2_ALPHA_MODE", "opaque") != "auto": + _force_opaque(Path(path)) return result, pre_simplified @@ -437,7 +492,7 @@ def _parse_args(): 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) - parser.add_argument("--texture-size", type=int, choices=(512, 1024, 2048), default=1024) + parser.add_argument("--texture-size", type=int, choices=(512, 1024, 2048, 4096), default=1024) parser.add_argument("--background", choices=("auto", "keep"), default="auto") parser.add_argument("--pbr-decimation-target", type=_parse_target, default=None, metavar="none|N") parser.add_argument("--cache-dir", type=Path)