obj 파일의 정점을 평면에 올리기
볼록 껍질을 무작위 점 말고 실제 데이터에 써보려고 Stanford bunny의 obj 파일을 가져왔다. 정점 2503개, 면 4968개짜리다.
# OBJ file format with ext .obj
# vertex count = 2503
# face count = 4968
v -3.4101800e-003 1.3031957e-001 2.1754370e-002
...
f 1069 1647 1578
필요한 줄만 골라 읽기
with open('bunny.obj', 'r') as f:
for line in f:
if line.startswith('v'):
x, y = map(float, line.split()[1:3])
vertices.append((x, y))
elif line.startswith('f'):
faces.append(map(int, line.split()[1:]))
v 로 시작하면 정점이고 세 좌표가 따라온다. [1:3] 으로 앞의 두 개만 가져와 z를 버린다. 평면 문제로 만들려면 한 축을 없애야 하고, 여기서는 그냥 정면에서 본 그림자를 택했다.
f 로 시작하면 면이고 정점 번호들이 따라온다. obj의 번호는 1부터 시작하므로 쓸 때 1을 빼야 한다.
startswith('v') 는 이 파일에서만 안전하다. obj에는 vn(법선), vt(텍스처 좌표)도 있고 그것들도 v 로 시작한다. 이 파일에는 둘 다 없어서 문제가 안 됐다. line.split()[0] == 'v' 로 봤어야 한다.
면도 마찬가지다. 이 파일은 f 1069 1647 1578 처럼 번호만 있지만, obj는 f 1/2/3 형태도 흔하다. 그러면 int() 에서 바로 멈춘다.
화면 크기에 맞추기
ratio = 700 / (max(vertices)[0] - min(vertices)[0])
좌표가 소수점 이하 값이라 그대로 찍으면 한 점에 뭉친다. x 방향 폭이 700이 되도록 배율을 구해 전체에 곱한다.
max(vertices) 는 튜플끼리 비교하므로 x가 가장 큰 점을 준다. 거기서 [0] 을 꺼내면 최대 x다. 의도한 대로 동작하지만 max(v[0] for v in vertices) 가 읽기에는 낫다.
y는 y - 400 으로 아래로 내린다. 배율은 x 기준으로만 정했으므로 세로가 화면을 넘칠 수 있는데 이 모델에서는 들어맞았다.
아직 껍질을 씌우지는 않았다
이 파일은 정점을 찍고 면을 선으로 잇는 데서 끝난다. 앞서 만든 convex 를 부르는 곳이 없다.
정점 2503개는 앞에서 쓰던 무작위 점 30개와는 규모가 다르다. 데이터를 읽고 화면에 올리는 것까지 먼저 해둔 단계로 보인다.
껍질을 씌우면 토끼의 실루엣을 감싸는 다각형이 나올 텐데, 귀 사이의 오목한 부분이 잘려서 실제 윤곽과는 꽤 달라진다. 그걸 눈으로 보려던 것이 아니었을까 싶다.