UV를 유지한 채로 Extrude 된 Face 기준으로 UV 확장 하는 법
3Ds MAX에는 shell uvs interpolation이라는 기능으로 PolyExtrude 한 면을 알아서 uv 상에서 늘려주는 기능이 있는 것 같다. 근데 Houdini에는 찾아봐도 안 나오고 자체적으로 들어있는 UV 자동화도 이런 걸 딱히 지원 안 하는 거 같다.
누군가 질문한 흔적은 있는데 답변도 안 나오고, 이 기능이 너무 원했는데 생각보다 다들 필요하지 않은듯 싶다. 왜지...
4일 정도 혼자서 씨름 했는데 결국 방법을 찾았다. 분명 더 간편하고 똑똑하게 해결하는 방법이 있을 텐데, 내가 바보인 건지 도저히 못 찾겠다. Houdini 도움말도 뒤져보고 UV 전용 프로그램인 Rizom UV도 뒤져봤는데 관련 기능이 도저히 없다.
그래서 Houdini로 만들었다. 노드 하나로 해결해줄 수 있는 건 아니지만... 그래도 나름 Procedural 하게 가능하지 싶다.
먼저 PolyExtrude를 하기 전에 vertices 클래스에 기존 버텍스인지 알 수 있도록 어트리뷰트를 추가해야 한다. 여기선 i@orig로 하겠다. 즉 지금 상태에선 모든 vertex가 i@orig = 1 상태다.
그 다음 필요한 만큼 1단계만 PolyExtrude 한다. 여러 곳에 PolyExtrude를 해도 되지만, Extrude가 진행되는 방향으론 1단계의 면만이 존재해야 하며, 즉 division을 늘려선 안 된다. 이건 나중에 해도 되니까 일단 진행. 참고로 여기서 side face를 그룹화 해주는 게 편하다.
그 다음 vertices 클래스에 s@outline = "0" 꼭 string이 아니어도 되는데 수정하기 귀찮아서 이대로 진행
point 클래스에 i@inside = 0 초기화
python 코드 추가.
node = hou.pwd()
geo = node.geometry()
for p in geo.iterPrims():
for v in p.vertices():
is_original = v.attribValue("orig") == 1
if is_original:
v.point().setAttribValue("inside", 1)
한 번 더 추가. 이건 기존 면에 포함된 vertex를 제외한 모든 새로 추가된 vertex에 s@outline = "1"을 설정해준다.
node = hou.pwd()
geo = node.geometry()
for pt in geo.iterPoints():
if pt.attribValue("inside") == 1: continue
for v in pt.vertices():
v.setAttribValue("outline", "1")
한 번 더 추가. 머리가 안 좋아서 그런지 어째서 방향을 90도 돌려야 하는지 잘 모르겠다...
import numpy as np
node = hou.pwd()
geo = node.geometry()
def normalize(v):
return v / np.linalg.norm(v) if np.linalg.norm(v) != 0 else v
def compute_uv_dir(v1, v2, uv1, uv2):
delta_u = uv2[0] - uv1[0]
delta_v = uv2[1] - uv1[1]
uv_f = normalize(np.array([-delta_v, delta_u]))
return uv_f;
def get_outline_vert(prim):
result = []
for vert in prim.vertices():
if vert.attribValue("outline") == 1:
result.append(vert)
return result
def move():
for p in geo.iterPrims():
out_verts = get_outline_vert(p)
l = len(out_verts)
if l == 2:
[a, b] = out_verts
a_v = a.point().position()
b_v = b.point().position()
a_uv = a.attribValue("uv")
b_uv = b.attribValue("uv")
dir = compute_uv_dir(a_v, b_v, a_uv, b_uv) * 0.001
a.setAttribValue("uv", [a_uv[0] + dir[0], a_uv[1] + dir[1], 0])
b.setAttribValue("uv", [b_uv[0] + dir[0], b_uv[1] + dir[1], 0])
move()
위에서 dir = compute_uv_dir(...) * 0.001 부분에 0.001을 수정하면 추가된 면의 uv 면적을 조절할 수 있다.
최종적으로 uv fuse.
이렇게 하면 나름 편하게 쓸 수 있다. 프로그래머인데 공부는 안 하고 맨날 자서 고생 좀 했다...
그룹화를 어떻게 잘 절차적으로 하도록 만들면 extrude 한 면이 여러 개여도 될 거 같긴한데...
일단 그걸 포함해서 몇 가지 문제가 더 있긴 한데 절차적인 작업엔 언제나 디테일이 아쉬워지는 부분이 있기 마련이니 이 정도로 만족한다.
마지막으로 참고 사항: Houdini에선 알기가 힘든데 UV가 뒤집어져있으면 UV가 펼쳐지는 방향이 반대다.
# 2025.03.09 수정: 필요 없는 노말 관련 코드 제거