-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpreview.py
More file actions
78 lines (65 loc) · 2.51 KB
/
Copy pathpreview.py
File metadata and controls
78 lines (65 loc) · 2.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env python3
"""
Render a wireframe preview of a (quad) OBJ to a PNG, so you can eyeball the
topology without opening Blender.
python preview.py samples/blob_clean.obj -o samples/blob_clean.png
Edges are drawn per-face, so quads read as quads. No textures, no shading --
just the mesh flow.
"""
import argparse
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Line3DCollection
def load_obj(path):
verts, faces = [], []
with open(path) as f:
for line in f:
if line.startswith("v "):
verts.append([float(x) for x in line.split()[1:4]])
elif line.startswith("f "):
idx = [int(p.split("/")[0]) - 1 for p in line.split()[1:]]
faces.append(idx)
return np.array(verts, dtype="float64"), faces
def main():
ap = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("input")
ap.add_argument("-o", "--output", required=True)
ap.add_argument("--elev", type=float, default=22)
ap.add_argument("--azim", type=float, default=-60)
ap.add_argument("--size", type=int, default=1100)
a = ap.parse_args()
V, F = load_obj(a.input)
quads = sum(1 for f in F if len(f) == 4)
ratio = 100.0 * quads / max(len(F), 1)
# build unique edge segments
segs = set()
for f in F:
for i in range(len(f)):
e = (f[i], f[(i + 1) % len(f)])
segs.add((min(e), max(e)))
lines = [[V[a_], V[b_]] for a_, b_ in segs]
fig = plt.figure(figsize=(a.size / 100, a.size / 100), dpi=100)
ax = fig.add_subplot(111, projection="3d")
lc = Line3DCollection(lines, colors="#19c37d", linewidths=0.35, alpha=0.85)
ax.add_collection3d(lc)
c = V.mean(axis=0)
r = np.abs(V - c).max()
for setlim in (ax.set_xlim, ax.set_ylim, ax.set_zlim):
pass
ax.set_xlim(c[0] - r, c[0] + r)
ax.set_ylim(c[1] - r, c[1] + r)
ax.set_zlim(c[2] - r, c[2] + r)
ax.set_box_aspect((1, 1, 1))
ax.view_init(elev=a.elev, azim=a.azim)
ax.set_axis_off()
ax.set_facecolor("#0d1117")
fig.patch.set_facecolor("#0d1117")
ax.set_title(f"{a.input}\n{len(F):,} faces - {ratio:.0f}% quads",
color="#e6edf3", fontsize=11)
fig.savefig(a.output, facecolor="#0d1117", bbox_inches="tight")
print(f"wrote {a.output} ({len(F):,} faces, {ratio:.0f}% quads)")
if __name__ == "__main__":
main()