generate_asset: meshgod-grade metal PBR lane — RAM-sized face cap, forced-opaque alpha, 4096 textures
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
0db816b55d
commit
ba4e2ad42b
@ -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("<III", data, 0)
|
||||
if magic != 0x46546C67: # b'glTF'
|
||||
return
|
||||
json_len, json_type = struct.unpack_from("<II", data, 12)
|
||||
if json_type != 0x4E4F534A: # b'JSON'
|
||||
return
|
||||
gltf = json.loads(data[20:20 + json_len])
|
||||
changed = False
|
||||
for material in gltf.get("materials") or []:
|
||||
if material.get("alphaMode", "OPAQUE") != "OPAQUE":
|
||||
material["alphaMode"] = "OPAQUE"
|
||||
material.pop("alphaCutoff", None)
|
||||
changed = True
|
||||
if not changed:
|
||||
return
|
||||
payload = json.dumps(gltf, separators=(",", ":")).encode()
|
||||
payload += b" " * (-len(payload) % 4)
|
||||
rest = data[20 + json_len:]
|
||||
out = struct.pack("<III", magic, version, 20 + len(payload) + len(rest))
|
||||
out += struct.pack("<II", len(payload), json_type) + payload + rest
|
||||
glb_path.write_bytes(out)
|
||||
print("Forced alphaMode=OPAQUE (TRELLIS2_ALPHA_MODE=auto keeps baked alpha)")
|
||||
|
||||
|
||||
def _metal_baker_available() -> 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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user