티스토리 뷰

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 수정: 필요 없는 노말 관련 코드 제거

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
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
글 보관함