Spaces:
Running
Running
Download preflight.py from STATICAI/Motion-Rig: direct link, hf CLI and curl.
- Browser
- Download file 3.89 kB
-
https://huggingface.co/spaces/STATICAI/Motion-Rig/resolve/main/preflight.py
- Command line
-
hf download hf://spaces/STATICAI/Motion-Rig/preflight.py
-
curl -L -o preflight.py https://huggingface.co/spaces/STATICAI/Motion-Rig/resolve/main/preflight.py
3.89 kB
| """Bounded GLB metadata preflight; does not load textures or allocate mesh arrays.""" | |
| import json | |
| import struct | |
| from pathlib import Path | |
| MAX_FACES = 500_000 | |
| MAX_VERTICES = 500_000 | |
| MAX_JSON = 16 * 1024 * 1024 | |
| def inspect_glb(path): | |
| path = Path(path) | |
| size = path.stat().st_size | |
| with path.open("rb") as stream: | |
| header = stream.read(20) | |
| if len(header) != 20: | |
| raise ValueError("Truncated GLB header") | |
| magic, version, length, json_length, chunk = struct.unpack("<4sIIII", header) | |
| if magic != b"glTF" or version != 2 or length != size or chunk != 0x4E4F534A: | |
| raise ValueError("Invalid GLB 2.0 header or file length") | |
| if json_length > MAX_JSON or json_length > size - 20: | |
| raise ValueError("GLB metadata is too large or truncated") | |
| doc = json.loads(stream.read(json_length)) | |
| meshes = doc.get("meshes", []) | |
| accessors = doc.get("accessors", []) | |
| vertices = faces = 0 | |
| unsupported = False | |
| for mesh in meshes: | |
| for primitive in mesh.get("primitives", []): | |
| if primitive.get("mode", 4) != 4: | |
| unsupported = True | |
| continue | |
| position = primitive.get("attributes", {}).get("POSITION") | |
| if position is None: | |
| raise ValueError("Mesh primitive has no POSITION accessor") | |
| count = int(accessors[position]["count"]) | |
| index = primitive.get("indices") | |
| indices = int(accessors[index]["count"]) if index is not None else count | |
| if count < 0 or indices < 0 or indices % 3: | |
| raise ValueError("Invalid vertex or triangle count") | |
| vertices += count | |
| faces += indices // 3 | |
| # Count node instances because upstream merges transformed scene geometry. | |
| nodes = doc.get("nodes", []) | |
| instances = {} | |
| for node in nodes: | |
| if "mesh" in node: | |
| instances[node["mesh"]] = instances.get(node["mesh"], 0) + 1 | |
| instantiated_faces = 0 | |
| instantiated_vertices = 0 | |
| for i, mesh in enumerate(meshes): | |
| multiplicity = max(1, instances.get(i, 0)) | |
| for primitive in mesh.get("primitives", []): | |
| pos = primitive.get("attributes", {}).get("POSITION") | |
| if pos is None: | |
| continue | |
| count = int(accessors[pos]["count"]) | |
| index = primitive.get("indices") | |
| n = int(accessors[index]["count"]) if index is not None else count | |
| instantiated_vertices += count * multiplicity | |
| if primitive.get("mode", 4) == 4: | |
| instantiated_faces += n // 3 * multiplicity | |
| required_extensions = doc.get("extensionsRequired", []) | |
| unsupported = unsupported or any(x in required_extensions for x in | |
| ("KHR_draco_mesh_compression", "EXT_meshopt_compression")) | |
| dense = instantiated_faces > MAX_FACES or instantiated_vertices > MAX_VERTICES or size > 512 * 1024**2 | |
| warning = ("Preprocessing/decimation required: this input exceeds the conservative " | |
| "500,000-face or 500,000-vertex limit. The original is preserved; " | |
| "inference has not started.") if dense else "" | |
| if unsupported: | |
| warning = "Preprocessing required: export uncompressed triangle geometry before inference." | |
| return dict(file_size_bytes=size, mesh_count=len(meshes), vertices=vertices, | |
| triangles=faces, instantiated_vertices=instantiated_vertices, | |
| instantiated_triangles=instantiated_faces, | |
| materials=len(doc.get("materials", [])), | |
| textures_present=bool(doc.get("textures") or doc.get("images")), | |
| density_risk="high" if dense else "within conservative limit", | |
| inference_allowed=bool(meshes) and faces > 0 and not dense and not unsupported, | |
| warning=warning) | |