| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- #!/usr/bin/env python3
- """从 GLB 中删除指定节点,并清理不再使用的网格/accessor,输出更小的文件。
- 支持三种定位方式(可组合):
- --index N 节点下标(0 起,对应文件里 nodes 数组的顺序)
- --label NAME 查看器里显示的标签(同名部件按 three.js 规则:
- 第一个保留原名,其后依次 _1、_2…)
- --name NAME 原始名称精确匹配,删除所有同名节点
- 用法:
- python3 3d/remove_nodes.py --input a.glb --inplace --label 三维立体
- python3 3d/remove_nodes.py --input a.glb --output b.glb --index 0 12
- """
- import argparse, os, sys
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
- from split_glb import read_glb, BandBuilder, world_matrices
- def viewer_labels(gltf):
- """按 three.js GLTFLoader.createUniqueName 的规则,为每个节点算出显示标签。"""
- used = {}
- labels = {}
- for i, n in enumerate(gltf["nodes"]):
- nm = n.get("name", "")
- if not nm:
- continue
- if nm in used:
- used[nm] += 1
- labels[i] = f"{nm}_{used[nm]}"
- else:
- used[nm] = 0
- labels[i] = nm
- return labels
- def main():
- ap = argparse.ArgumentParser()
- ap.add_argument("--input", required=True)
- ap.add_argument("--output")
- ap.add_argument("--inplace", action="store_true")
- ap.add_argument("--index", type=int, nargs="*", default=[])
- ap.add_argument("--label", nargs="*", default=[])
- ap.add_argument("--name", nargs="*", default=[])
- args = ap.parse_args()
- src, src_bin = read_glb(args.input)
- labels = viewer_labels(src)
- drop = set(args.index)
- for i, lb in labels.items():
- if lb in args.label:
- drop.add(i)
- for i, n in enumerate(src["nodes"]):
- if n.get("name", "") in args.name:
- drop.add(i)
- if not drop:
- print("没有匹配到要删除的节点,未做改动。")
- return
- print(f"将删除 {len(drop)} 个节点:")
- for i in sorted(drop):
- n = src["nodes"][i]
- print(f" node{i}: name={n.get('name','')!r} label={labels.get(i,'')!r} mesh={n.get('mesh')}")
- world = world_matrices(src)
- b = BandBuilder(src)
- b.src_bin = src_bin
- kept = 0
- for i, n in enumerate(src["nodes"]):
- if i in drop:
- continue
- if "mesh" not in n:
- continue
- # 节点在原文件里是多层嵌套的,这里把世界变换烘焙进节点后挂到根上,
- # 避免仅复制局部变换导致部件错位。
- b.add_verbatim_node(i, world[i])
- kept += 1
- out = args.output or (args.input if args.inplace else args.input + ".removed.glb")
- if args.inplace:
- tmp = out + ".tmp"
- b.finish(tmp)
- os.replace(tmp, out)
- else:
- b.finish(out)
- print(f"保留 {kept} 个节点 -> {out} ({os.path.getsize(out)/1048576:.1f} MB)")
- if __name__ == "__main__":
- main()
|