51 lines
1.9 KiB
Python
51 lines
1.9 KiB
Python
|
|
"""Crop an OBJ to the faces fully inside a sphere, so clay renders can frame the hand
|
||
|
|
instead of the whole arm. Keeps vertex order stable across files (same face set in/out)
|
||
|
|
only when the inputs share topology, so pass --like to reuse a reference file's face mask.
|
||
|
|
|
||
|
|
usage: obj_crop.py in.obj out.obj CX CY CZ R (metres)
|
||
|
|
obj_crop.py in.obj out.obj --mask mask.txt
|
||
|
|
obj_crop.py in.obj --write-mask mask.txt CX CY CZ R
|
||
|
|
"""
|
||
|
|
import sys, math
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
|
||
|
|
def load(path):
|
||
|
|
vs, faces = [], []
|
||
|
|
for line in Path(path).read_text().splitlines():
|
||
|
|
if line.startswith("v "):
|
||
|
|
p = line.split()
|
||
|
|
vs.append((float(p[1]), float(p[2]), float(p[3])))
|
||
|
|
elif line.startswith("f "):
|
||
|
|
faces.append([int(t.split("/")[0]) - 1 for t in line.split()[1:]])
|
||
|
|
return vs, faces
|
||
|
|
|
||
|
|
|
||
|
|
args = sys.argv[1:]
|
||
|
|
src = args[0]
|
||
|
|
vs, faces = load(src)
|
||
|
|
|
||
|
|
if "--write-mask" in args:
|
||
|
|
maskfile = args[args.index("--write-mask") + 1]
|
||
|
|
cx, cy, cz, r = (float(x) for x in args[-4:])
|
||
|
|
keep = [i for i, f in enumerate(faces)
|
||
|
|
if all(math.dist(vs[k], (cx, cy, cz)) <= r for k in f)]
|
||
|
|
Path(maskfile).write_text("\n".join(map(str, keep)))
|
||
|
|
print(f"mask {len(keep)}/{len(faces)} faces -> {maskfile}")
|
||
|
|
sys.exit()
|
||
|
|
|
||
|
|
dst = args[1]
|
||
|
|
if "--mask" in args:
|
||
|
|
keep = [int(x) for x in Path(args[args.index("--mask") + 1]).read_text().split()]
|
||
|
|
else:
|
||
|
|
cx, cy, cz, r = (float(x) for x in args[-4:])
|
||
|
|
keep = [i for i, f in enumerate(faces)
|
||
|
|
if all(math.dist(vs[k], (cx, cy, cz)) <= r for k in f)]
|
||
|
|
|
||
|
|
used = sorted({k for i in keep for k in faces[i]})
|
||
|
|
remap = {old: n + 1 for n, old in enumerate(used)}
|
||
|
|
out = [f"v {vs[o][0]:.6f} {vs[o][1]:.6f} {vs[o][2]:.6f}" for o in used]
|
||
|
|
out += ["f " + " ".join(str(remap[k]) for k in faces[i]) for i in keep]
|
||
|
|
Path(dst).write_text("\n".join(out) + "\n")
|
||
|
|
print(f"{Path(dst).name}: {len(used)} verts, {len(keep)} faces")
|