본문 바로가기
이펙트 (FX)/이펙트 팁 : Houdini

[Houdini] hip파일 저장시 $JOB 자동 설정 파이썬 스크립트 (Python)

by Minkyu Lee 2025. 8. 8.

개요

사용자마다 다르겠지만,

나는 렌더, 익스포트, 캐시 등을 $HIP 경로가 아니라 $JOB 경로에 저장한다.

 

상위 폴더에 별도로 분리해서 만들면 추후 관리, 삭제가 편하기 때문이다.

예를 들면 hip파일만 빼낼 때 용이하다.

 

즉, 아래 그림과 같은 구조가 된다.

 

그런데 매번 JOB 경로를 지정해주는게 귀찮아서,

알아서 자동으로 지정해주는 파이썬 코드를 제미나이와 함께 작성했다.

 

방법

1. 내문서\houdini20.0(후디니버전)\scripts 폴더 생성

 

2. 456.py 를 생성하여 아래 코드를 입력

 

코드

import hou
import os

def job_setter_on_save(event_type, **kwargs):
    """
    '저장 후(AfterSave)' 이벤트 발생 시, $HIP의 상위 폴더를
    $JOB으로 설정하되, 기존 $JOB과 동일하면 건너뛰는 최종 핸들러.
    """
    # '저장 후' 이벤트일 때만 작동하도록 필터링합니다.
    if event_type == hou.hipFileEventType.AfterSave:
        
        # 현재 파일 경로가 'untitled.hip'으로 끝나는 경우, 아무 작업도 하지 않고 종료합니다.
        hip_path = hou.hipFile.path()
        if hip_path.endswith("untitled.hip"):
            return
        
        # 현재 .hip 파일이 있는 폴더($HIP)를 찾습니다.
        hip_dir = os.path.dirname(hip_path)

        if os.path.isdir(hip_dir):
            # 1. 목표 $JOB 경로를 계산합니다 ($HIP의 상위 폴더).
            new_job_path = os.path.dirname(hip_dir)
            
            # 2. 현재 $JOB 경로를 가져옵니다.
            current_job_path = hou.text.expandString("$JOB")

            # 3. 경로를 표준화(normalize)하여 비교합니다. 경로가 동일하면 아무것도 하지 않고 종료합니다.
            if os.path.normpath(new_job_path) == os.path.normpath(current_job_path):
                return

            # 4. 경로가 다를 경우에만 변수를 설정하고 알림창을 띄웁니다.
            hscript_command = f'set -g JOB = "{new_job_path}"'
            hou.hscript(hscript_command)
            
            hou.ui.displayMessage(
                f"$JOB 변수가 새로운 경로로 설정되었습니다:\n\n{new_job_path}",
                title="JOB 변수 설정 완료"
            )

# --- Houdini 시작 시 이벤트 핸들러 등록 ---
try:
    hou.hipFile.removeEventCallback(job_setter_on_save)
except:
    pass

hou.hipFile.addEventCallback(job_setter_on_save)

 

참고사항

456.py의 의미

후디니는 시작할 때 scripts 폴더에서 미리 약속된 특정 이름의 파일들을 순서대로 찾아 자동으로 실행한다.

대표적인 파일들이 바로 123.py와 456.py, 그리고 pythonrc.py이다.


123.py : 후디니 환경이 완전히 초기화되기 전에 먼저 실행
456.py : 후디니의 모든 환경(UI, 라이브러리 등)이 완전히 준비된 후에 실행

pythonrc.py : 456.py와 기능적으로 완전히 동일함 (사실상 456.py의 별명이다. 사용자 인식률 높이기 위함)

 

그런데 나는 pythonrc.py로 하면 제대로 작동이 안됐다.

대충 찾아보니 다른 경로에 같은 pythonrc.py가 있다면 중복 처리되어 스킵될 수도 있다고 한다.

딱히 더 알아보진 않고 456을 써서 해결했다.

 

456.py에서 콜백 등록에 대한 의미

`456.py` 스크립트는 이벤트가 발생할 때마다 실행되는 것이 아니라, 후디니 세션이 시작될 때 단 한 번만 실행됩니다.

대신, `456.py`를 사용해서 '이벤트를 감지할 함수(이벤트 콜백)'를 후디니에 등록하는 것입니다.
다음과 같은 순서로 동작합니다.

1.  후디니 시작: 사용자가 후디니를 실행합니다.
2.  초기화: 후디니 엔진과 UI가 순서대로 로드됩니다.
3.  `456.py` 실행 (단 1회)**: 이 스크립트 안에 다음과 같은 코드가 있다고 가정해 봅시다.

    ```python
    # HOUDINI_USER_PREF_DIR/scripts/456.py 파일 내용 예시

    import hou

    # 이벤트가 발생했을 때 '실제로 실행될 함수'를 정의
    def my_event_handler(**kwargs):
        node = kwargs.get('node')
        if node:
            print(f"이벤트 발생! 노드 '{node.name()}'가 생성되었습니다.")
            node.setColor(hou.Color((0.8, 0.5, 0.5))) # 생성된 노드를 붉은색으로 변경

    # 후디니의 이벤트 시스템에 위에서 정의한 함수를 '등록'함
    # 'OnCreated' 이벤트가 발생하면 'my_event_handler' 함수를 실행하라고 알려주는 것
    hou.addEventCallback(hou.nodeEventType.OnCreated, my_event_handler)

    print("--- 456.py 스크립트 실행 완료. 이벤트 콜백이 등록되었습니다. ---")
    ```

4.  이벤트 콜백 등록 완료: `456.py`의 실행이 끝나면, 후디니의 이벤트 루프(Event Loop)는 이제 `hou.nodeEventType.OnCreated` (노드가 생성되는 이벤트)가 발생하는지 계속 지켜보게 됩니다. 이것이 바로 사용자가 생각한 "백그라운드에서 감지"하는 부분입니다.

5.  이벤트 발생: 사용자가 작업 중에 새로운 노드(예: Box SOP)를 생성합니다.

6.  콜백 함수 실행: 후디니의 이벤트 루프가 '노드 생성' 이벤트를 감지하고, `456.py`에서 등록해 두었던 `my_event_handler` 함수를 호출합니다. 이때 `print`문이 실행되고 노드 색상이 변경됩니다.
이 과정은 후디니 세션이 종료될 때까지 계속 유지됩니다.

댓글