
지난 번엔 공식적으로 제공되는 엔진을 ShotGrid Toolkit에 등록하는 방법에 대해 알아보았다.
그러나 Katana, Clarisse와 같이 공식적으로 지원되지 않는 DCC의 경우 사용자 혹은 개발자가 직접 엔진을 제작해야 한다.
완성된 tk-katana의 경우 여기에 있으니 참고하기 바라며,
이 포스팅에서는 자세한 코드 설명 보다는 전체적인 개발 흐름에 대해 정리하도록 하겠다.
엔진을 개발하기 위해서는 ShotGrid Toolkit 엔진이 어떤 방식으로 작동하는지 이해할 필요가 있다.
자세한 내용은 ShotGrid Toolkit 엔진이란?을 참고.
가장 좋은 방법은 이미 만들어진 엔진을 참고하는 것이다. tk-katana의 경우 tk-maya를 레퍼런스로 제작된 엔진이다.
엔진을 제작하려는 DCC가 어떤 특성을 가지고 있는지 개발 전 완벽하게 숙지하는 것이 좋다.
예를 들어, DCC 자체에 QT를 포함하고 있는 지 여부, DCC 실행 시 자동으로 불러오는 스크립트가 있는 지 여부 등을 파악해야 엔진 개발시 혼동을 줄일 수 있다.
자세한 내용은 공식 문서 참고
다음은 원활한 엔진 개발이 가능한 소프트웨어의 위시리스트이다.
Python 인터프리터 및 Qt, PySide가 내장된 소프트웨어:
ShotGrid Toolkit 앱의 경우 PySide 기반으로 작동하기 때문에 위의 조건을 만족하면 개발이 훨씬 편하다.
소프트웨어 시작/초기화 시 코드를 실행할 수 있는 능력:
Nuke의 init.py, Maya의 userSetup.py처럼 시작 시 스크립트를 실행할 수 있는지 확인해야 한다.
소프트웨어가 시작 및 실행되고 있을 때와 UI가 완전히 초기화되었을 때에 코드에 액세스하여 자동 실행할 수 있는 능력:
쉽게 말하면 스크립팅이 가능한지 여부를 말한다.
파일 시스템 상호 작용을 래핑하는 API:
말 그대로 API를 통해 열기, 저장 등 파일 시스템을 관리할 수 있는지 여부를 말한다.
UI 요소를 추가하기 위한 API:
ShotGrid 메뉴를 소프트웨어의 메뉴바에 생성하기 위해, UI와 관련된 API를 지원하는지 여부를 말한다.
비동기적 UI 실행 지원:
DCC 내에서 ShotGrid Toolkit 앱을 실행해도 메인 스레드가 멈추지 않도록 비동기적인 UI를 제공하는지 여부를 말한다.
커스텀 UI 창의 부모-자식 관계가 올바로 지정되도록 최상위 창에 핸들 제공:
말 그대로 UI의 종속 관계에 문제가 없도록 최상위 객체를 API에서 제공하는지 여부를 말한다.
업데이트가 지속되는 DCC라면 대부분 위의 조건을 만족할 것이다.
그러나 Qt의 경우 PySide와 PyQt를 동시에 지원하지 않는 경우도 있으니 주의하자. (Katana가 그렇다.)
먼저, 필수적인 폴더와 스크립트 파일을 생성하도록 하자.
tk-katana/
│
├── resources/
│ └── Katana
│ └── init.py
│
├── hooks/
│
├── python/
│ ├── startup/
│ └── bootstrap.py
│ └── tk-katana/
│ └── menu_generation.py
│
├── config/
│ └── env/
│ ├── includes/
│ ├── settings/
│ └── tk-katana.yml
│ └── engine_locations.yml
│ ├── asset_step.yml
│ └── shot_step.yml
│
├── startup.py
├── engine.py
├── info.yml
└── etc.
tk-katana의 파일 구조가 tk-maya의 파일 구조와 다른 점은 resources 디렉토리가 존재한다는 것이다.
그 이유는 DCC마다 시작될 때 호출하는 스크립트의 차이 때문인데,
예를 들어 Nuke는 시작 시 init.py를 인식하여 작업을 수행하며, Maya는 userSetup.py를 인식하여 작업을 수행한다.
이처럼 각 DCC에서 시작 시 호출하는 스크립트의 이름과 방식엔 차이가 있으니, 해당 DCC의 공식 문서를 참고하는 것이 가장 좋다.
Katana의 경우 KATANA_RESOURCES라는 환경변수에 등록된 디렉토리의 스크립트를 실행한다.
그렇기 때문에 /tk-katana/resources/Katana 디렉토리에 init.py를 생성한 것이다.
엔진을 구성하기 위해서는 info.yml을 작성해야 한다. 여기에는 엔진에 대한 기본적인 정보와 설정이 정의된다.
아래는 info.yml의 예시이다.
configuration:
debug_logging:
type: bool
description: Controls whether debug messages should be emitted to the logger
default_value: false
menu_favourites:
type: list
description: "Controls the favourites section on the main menu. This is a list
and each menu item is a dictionary with keys app_instance and name.
The app_instance parameter connects this entry to a particular
app instance defined in the environment configuration file. The name
is a menu name to make a favourite."
allows_empty: True
values:
type: dict
items:
name: { type: str }
app_instance: { type: str }
# the Shotgun fields that this engine needs in order to operate correctly
requires_shotgun_fields:
# More verbose description of this item
display_name: "Katana Engine"
description: "Shotgun Pipeline Toolkit integration in Katana"
# Required minimum versions for this item to run
requires_shotgun_version:
requires_core_version: "v0.12.5"
필자의 경우 크게 추가할 설정이 없어 간단하게 정의했다.
이제 개발을 하기위한 준비가 끝났다.
본격적으로 ShotGrid Toolkit 엔진을 구성하는 주요 스크립트를 작성해보자.
startup.py는 tk-katana에서 Katana 애플리케이션을 실행할 때 사용되는 초기화 및 부트스트랩 스크립트이다.
이 스크립트는 ShotGrid Toolkit과 Katana를 연결하고, Katana가 시작될 때 적절한 환경 설정을 통해 ShotGrid Toolkit이 올바르게 초기화되도록 한다.
KatanaLauncher 클래스는 ShotGrid Toolkit의 SoftwareLauncher 클래스를 상속받아 Katana 애플리케이션을 실행하고, Katana 세션이 ShotGrid Toolkit 엔진과 함께 시작되도록 설정하는 역할을 한다.
Katana 실행 파일 찾기:
EXECUTABLE_MATCH_TEMPLATES를 통해 각 운영 체제별로 Katana 실행 파일 경로를 정의하고,
_find_software 메서드를 통해 실제로 설치된 Katana 실행 파일을 찾는다.
_extract_products_from_path 메서드를 사용하여 발견된 실행 파일의 버전 및 제품 정보를 추출한다.
지원 여부 확인:
_is_supported 메서드를 통해 특정 Katana 버전이 지원되는지 확인한다.
Katana 실행 준비:
prepare_launch 메서드는 Katana를 실행할 때 필요한 환경 변수를 설정한다. 이 환경 변수에는 ShotGrid 컨텍스트와 엔진 정보가 포함된다.
required_env 딕셔너리에 ShotGrid 컨텍스트와 엔진 이름을 추가하여 Katana가 시작될 때 ShotGrid Toolkit과 연결될 수 있도록 한다.
Katana 실행:
prepare_launch 메서드는 최종적으로 LaunchInformation 객체를 반환하여 Katana 실행 파일 경로, 명령줄 인수, 그리고 필요한 환경 변수를 포함한다.
engine.py 는 Katana 엔진의 핵심 엔트리 포인트로, Katana와 ShotGrid Toolkit 간의 상호 작용을 관리하고 Katana 환경에서 Toolkit 기능을 활성화한다.
KatanaEngine 클래스는 ShotGrid Toolkit의 sgtk.platform.Engine 클래스를 상속받아 Katana와의 상호 작용을 정의한다.
버전 호환성 검사:
pre_app_init 메서드는 Katana가 초기화되기 전 호출되어 버전 호환성을 검사한다.
초기화:
__init__ 메서드에서 Katana가 UI 모드에서 실행 중인지 확인하고, has_ui 프로퍼티를 통해 bool을 반환한다.
메뉴 생성:
post_app_init 메서드에서는 Katana가 UI 모드에서 실행되었는지 검증 후 add_katana_menu 메서드를 통해 ShotGrid 메뉴를 생성한다.
만약 UI모드가 아니라면 callback을 통해 다시 확인한다.
종료 처리:
destroy_engine 메서드는 엔진이 종료될 때 호출되며, Katana 세션을 정리한다.
Qt 환경 재정의:
_define_qt_base 메서드는 PySide2 기반의 앱을 Katana에서 사용하기 위해 Qt 환경을 재정의 한다.
로깅:
log_debug, log_info, log_warning, log_error 메서드를 통해 다양한 수준의 로그 메시지를 ShotGrid 콘솔에 출력한다.
menu_generation.py는 engine.py에 의해 호출되며, Katana에서 ShotGrid Toolkit 메뉴를 생성하고 관리하는 기능을 포함하고 있다.
ShotGrid 메뉴 항목을 생성, 콜백을 연결, 그리고 사용자 인터페이스와의 상호 작용을 처리한다.
Katana 동작 생성:
ActionFactory 클래스는 Katana의 동작을 생성하고 관리한다.create_action: Katana 액션을 생성하고 메뉴에 추가한다._execute_callback: 액션이 트리거될 때 콜백을 실행한다.clear: 저장된 모든 액션을 제거한다.ShotGrid 메뉴 생성 및 관리
MenuGenerator 클래스는 Katana에서 ShotGrid 메뉴를 생성하고 관리한다.create_menu: ShotGrid 메뉴와 명령을 생성한다.destroy_menu: ShotGrid 메뉴를 제거한다.setup_root_menu: 루트 메뉴를 설정하거나 생성한다.__build_shotgun_menu: ShotGrid 메뉴를 생성한다.__build_context_menu: 현재 컨텍스트를 나타내는 메뉴를 생성한다._jump_to_sg: 현재 컨텍스트의 ShotGrid URL을 연다._jump_to_fs: 현재 컨텍스트의 파일 시스템 폴더를 연다.__build_app_menu: 애플리케이션 명령을 포함하는 서브메뉴를 생성한다.명령 실행
AppCommand 클래스는 개별 ShotGrid 명령을 나타내며, 명령을 메뉴에 추가하는 역할을 한다.get_app_name: 명령을 로드한 애플리케이션의 이름을 반환한다.get_app_instance_name: 명령을 로드한 애플리케이션 인스턴스의 이름을 반환한다.get_type: 명령의 유형을 반환한다.add_to_menu: 명령을 메뉴에 추가한다.bootstrap.py는 Katana 환경을 설정하는 스크립트로, Katana 실행에 필요한 리소스 경로를 설정하고 환경 변수를 업데이트하는 기능을 포함하고 있다.
필자의 경우 Rez를 활용해 KATANA_RESOURCES를 불러왔기 때문에 실질적으로 사용되지 않은 스크립트이다.
sgtk.platform.get_engine_path를 사용하여 지정된 엔진의 경로를 가져온다._get_resource_paths 함수를 호출하여 모든 앱의 리소스 경로를 가져와 startup_paths 리스트에 추가한다.startup_paths를 KATANA_RESOURCES 환경 변수에 추가하여 Katana가 시작될 때 사용할 수 있도록 설정한다.init.py는 ShotGrid Toolkit (sgtk)를 사용하여 주어진 컨텍스트와 엔진을 기반으로 ShotGrid 엔진을 시작한다.
주요 함수는 bootstrap으로, 환경 변수 설정 확인, sgtk 모듈 로드, 컨텍스트 역직렬화 및 엔진 시작을 포함한다.
이 스크립트 또한 필자는 사용하지 않은 스크립트이다.
환경 변수 확인:
SGTK_ENGINE과 SGTK_CONTEXT 환경 변수가 설정되어 있는지 확인한다.
설정되지 않았다면 오류 메시지를 기록하고 종료한다.
sgtk 모듈 임포트:
sgtk 모듈을 임포트하여 ShotGrid 엔진을 시작하기 위한 준비를 한다.
임포트에 실패하면 오류 메시지를 기록하고 sys.path를 출력한 후 종료한다.
컨텍스트 역직렬화:
직렬화된 컨텍스트를 역직렬화하여 ShotGrid 컨텍스트 객체를 생성한다.
실패 시 오류 메시지를 기록하고 종료한다.
엔진 시작:
지정된 엔진 이름과 컨텍스트를 사용하여 ShotGrid 엔진을 시작한다.
실패 시 오류 메시지를 기록하고 로그 파일에 기록한다.
임시 환경 변수 정리:
SGTK_ENGINE, SGTK_CONTEXT, SGTK_FILE_TO_OPEN 환경 변수를 제거하여 클린업을 수행한다.
이제 기본적인 엔진 개발은 마무리되었다.
이제 엔진과 앱을 ShotGrid Toolkit에 등록해서 직접 사용할 수 있다.
ShotGrid Toolkit에 엔진과 앱을 등록하는 방법은 여기를 참고하자.
추가적으로 본인이 사용하고자 하는 ShotGrid Toolkit 앱에 대한 hook나 설정을 추가하면서 커스터마이징하면 된다.