이것 저것 개발하고 만들어보기
article thumbnail

 

 

 

 

블렌더에 존재하는 UI를 직접 추가해 그 안에 버튼을 넣고, 버튼을 통해 여러가지 동작을 수행하는 가장 기본적인 기능부터 다뤄보려 합니다.

 

 

UI의 기본적인 작성 방법을 알면 기존에 자주 쓰던 기능을 가져와 패널에 정리하는 등 유용하게 사용 될 수 있습니다.

 

 

 

 

 

Panel 탭 작성

 

 

 

 

 

 

우선 블렌더에 존재하는 다양한 UI 중 우리는 Panel 이라고 불리는 뷰포트 우측에 있는 탭을 만들어 보겠습니다.

 

 

 

 

 

 

 

 

Text Editor 윈도우에서 Templates - Python - UI Panel Simple 을 통해서 프리셋을 불러 올 수 있습니다.

 

 

단축키 Alt P 를 입력하면 스크립트가 실행되고, 콘솔창이나 Info 창에 실행됐다는 메세지가 뜨면 성공입니다.

 

 

하지만 스크립트를 실행하더라도 뷰포트상의 패널이 추가되진 않습니다.

 

 

실제로 패널을 추가하고, 입력된 버튼이 동작되기 위해서는 조금 수정을 해 주어야 합니다.

 

 

 

 

 

import bpy

class TestControllerPanel(bpy.types.Panel):
    bl_label = "Hello TT Panel!"
    bl_idname = "PT_TestPanel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "TT_Panel"
    
    
    def draw(self,context):
        layout = self.layout
        
        row = layout.row()
        row.label(text = "Cube Generator", icon = "WORLD_DATA")
        row = layout.row()
        row.operator("mesh.primitive_cube_add")
        row = layout.row()
        row.label(text = "Sphere Generator", icon = "MESH_UVSPHERE")
        row.operator("mesh.primitive_uv_sphere_add")


def register():
    bpy.utils.register_class(TestControllerPanel)
    

def unregister():
    bpy.utils.unregister_class(TestControllerPanel)

if __name__ == "__main__":
    register()

 

 

 

수정한 코드를 통해서 패널이 어떻게 추가되고, 무엇을 입력해야 하는지 알아보려 합니다.

 

 

 

class

 

 

우선 BPY를 사용하고자 한다면 블렌더의 내장 메소드를 불러올 필요가 있고, 실제로 불러와야만 작동하기 때문에 첫줄 import bpy 를 입력합니다.


이후 클래스 코드를 마저 작성합니다.

 

 

class TestControllerPanel(bpy.types.Panel):
    
    bl_label = "Hello TT Panel!"
    bl_idname = "PT_TestPanel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "TT_Panel"

 

 

우리가 실질적으로 사용해야 할 패널의 핵심이 되는 부분이 이 class(클래스)입니다.



사용자 정의 클래스는 사용하기 위해 해당 클래스의 타입(types)을 지정해 주어야 합니다.



이전 시간에 우리는 블렌더 데이터를 알아봄으로써 블렌더 bpy에 존재하는 타입을 인포창에서 불러오고, 메뉴얼을 통해 알아 볼 수 있었습니다.


 

[Blender BPY] BPY DATA 알아보기

Blender 3.6 Python API Documentation — Blender Python API © Copyright Blender Foundation. Revision 0a13a7841c27 - 11/07/2023. docs.blender.org 블렌더는 블렌더 파이썬 API 이라는 메뉴얼이 존재합니다. 블렌더 뿐만 아니라 다른

tintana4168.tistory.com




우리는 이 중에서 뷰포트 우측에 존재하는 UI 패널을 만들기 위해서 클래스(bpy.types.panel)을 통해 상속받게 되면, 해당 클래스는 UI로써 기능을 할 수 있는 기초적인 데이터를 불러올 수 있습니다.

 


여기서 bl_idname과 bl_label은 사용자 정의된 클래스 타입 끼리의 구분을 짓기 위해 사용되는 변수입니다. 

 


bl_space_type은 어떤 UI에 들어갈 것인지 정의해야 하는데, 우리는 현재 뷰포트 패널에 정렬하고 싶음으로 'VIEW_3D' 로 정의합니다.

 

 

 

 

 

 

 

 

블렌더 내 UI를 교체할 때 마찬가지로 Info창에 기록됨으로 블렌더 창의 타입을 알 수 있습니다.

 
bl_region_type을 통해서 우리는 VIEW_3D 창의 어떤 방향과 위치에 정의할지 지정해 줄 수 있습니다.
 

bl_category 는 카테고리의 이름을 지정해 주는데 Tab의 이름을 지정해 줄 수 있음으로 자신이 마음대로 지정하면 됩니다.

 
이들을 지정해 주지 않아도 되지만, 재설정 해주지 않으면 기본값을 가지게 됨으로 재설정 하는것이 좋습니다.

 

 

 

 

 

register , unregister

 

 

 

def register():
    bpy.utils.register_class(TestControllerPanel)


def unregister():
    bpy.utils.unregister_class(TestControllerPanel)

 

 

 

블렌더에 사용자가 정의한 class(혹은 정의한 여러 다른 메소드들)을 사용하기 위해 블렌더에 등록하는 메소드입니다. 

 

 

이 매소드 내부의 register_class와 unregister 인자에 TestControllerPanel 으로 정의했던 class 이름을 넘겨주면 됩니다.

 

 

register(레지스터) 와 unregister(언 레지스터)는 블렌더가 실행 될 때 실행이 되는 메소드인데, 언 레지스터가 먼저 실행되고 이후에 레지스터가 실행됩니다.

 

 

언 레지스터 메소드에는 클래스를 해제하여 그 클래스에 할당된 메모리들을 정리해주게 됩니다.

 

 

블렌더가 종료 시에는 언 레지스터만 동작해 등록했던 클래스나 기능들을 해제해 최적화 하는 방법중 하나로, 가급적이면  unregister까지 함께 시켜주는것이 바람직합니다.

 

 

 

 

 

class - def draw

 

 

 

    def draw(self,context):
        layout = self.layout
        
        row = layout.row()
        row.label(text = "Cube Generator", icon = "WORLD_DATA")
        row = layout.row()
        row.operator("mesh.primitive_cube_add")
        row = layout.row()
        row.label(text = "Sphere Generator", icon = "MESH_UVSPHERE")
        row.operator("mesh.primitive_uv_sphere_add")

 

 

 

우선 class 내부에 draw 메소드를 불러오는데 인자로 self, context 를 정의해줍니다.

 

 

클래스 내에 정의된 메소드의 첫번째 인자는 self를 넘겨주어야 합니다.

 

 

파이썬에서 self는 그 클래스의 객체를 가리키게 되는데, 이렇게 되면 다른 draw 레이아웃들과 구분이 가능해짐으로 self를 사용하게 됩니다.

 

 

BPY 특성상 인스턴스 메서드를 자주 호출하게 되는데, 파이썬은 인자를 호출할때 자동으로 전달하기 때문에 self 인자를 전달합니다.

 

 

마찬가지로 메소드 내에 정의된 변수 layout도 self.layout을 통해 다른 레이아웃과 구분되는 메소드를 만들어 줄 수 있습니다.

 

 

 

row = layout.row()
row.label(text = "Cube Generator", icon = "WORLD_DATA")

 

 

 

이제 행을 추가하기 위해 layout 에 row를 사용합니다. UI 타입인 이 row는 코드 줄에 따라 행을 추가합니다.

 

 

label 의 text 는 본인이 원하는 이름을 지정해 주면 되지만 icon 은 조금 다릅니다.

 

 

 

Add-ons 에서 icon 이라 검색하면 아이콘 기능을 활성화 할 수 있다.

 

 

 

아이콘은 해당 아이콘의 코드명을 받아와야 비로소 모양이 나타나게 되는데, 이 아이콘들은 블렌더 Addons 에서 활성화 한뒤,  블렌더 스크립트 에디터 창에서 Ctrl + T 로 열어줄 수 있습니다.

 

 

이후 해당 아이콘을 클릭하게 되면 하단 info 메세지에 아이콘에 대한 문자열을 출력하는데 이 문자열을 icon 에 전달하면 해당 모양의 아이콘이 나타나게 됩니다.

 

 

 

 

Icon Viewer 탭 검색창에서 키워드를 통해 원하는 아이콘을  찾을 수도 있습니다.

 

 

 

 

Operator

 

 

 

 

 

 

layout의 lable까지만 작성하더라도, 패널 탭은 삽입할 수 있지만, 우리가 원하는 기능과 버튼은 추가해 주어야 합니다.

 

 

블렌더의 Operator는 블렌더 기능과 도구들에 엑세스 하기 위해 사용되며 구조체와 클래스 인자에 상속되거나 컨텍스트를 재정의, 혹은 전달해 다른 부분에서도 Operator를 실행할수도 있습니다.

 

 

인수로 호출되는 operator 는 O의 대소문자를 구별한다는 것을 알 수 있습니다.

 

 

operator를 통해서 우리는 블렌더의 기능중 Shift +A 를 눌러 나오는 Add Cube를 불러오려 합니다.

 

 

row.operator("mesh.primitive_cube_add")

 

 

불러온 "mesh.primitive_cube_add" 는 블렌더의 가장 기본이 되는 Cube를 뜻합니다. 

 

 

이 문장을 입력하게 되면 우리가 지정한 label 행에 Add Cube 버튼이 생기고, 이를 클릭하면 3D View에 큐브를 생성하게 됩니다.

 

 

 

 

 

 

    def draw(self,context):
        layout = self.layout
        
        row = layout.row()
        row.label( text = "Cube Generator", icon = "WORLD_DATA")
        row = layout.row()
        row.operator("mesh.primitive_cube_add")

 

 

중간에 행을 추가해서 다음과 같이 텍스트와 아이콘 버튼을 구분시켜줄 수도 있습니다.

 

 

 

 

 

 

def draw(self,context):
        layout = self.layout
        
        row = layout.row()
        row.label( text = "Cube Generator", icon = "WORLD_DATA")
        row = layout.row(align = True)
        row.operator("mesh.primitive_cube_add")
        row.operator("mesh.primitive_cylinder_add")
        row.operator("mesh.primitive_monkey_add")

 

 

행에 여러 Add mesh 버튼들을 추가해 줄 수 있으며, 매개변수 align를 이용하여 버튼들을 가로 정렬 할 수 있습니다.

 

 

 

좌 : 매개변수를 비워뒀을때 우 : align 매개변수가 True 일때

 

 

 

완성하고 삭제하기

 

 

if __name__ == "__main__":
    register()

 

 

마지막으로 해당 코드를 맨 마지막 줄에 삽입해 줍니다.

 

 

이것은 파이썬의 모듈 구조에 쓰이는 코드로 현재 모듈의 네임 스페이스가 __main__ 에 해당한다면, 직접 실행되는 경우에 if 문 이하를 실행하라는 뜻이 됩니다.

 

 

다른 파일에 해당 파일을 임포트 할 때, 디버깅을 위한 print 출력까지 전부 출력 될 수 있음으로 해당 파일만 실행할 때 해당 구문이 동작하게끔 만들어주는 것이라, 굳이 쓰지 않아도 괜찮습니다.

 

 

 

 

 

 

코드가 잘 작성됐다면, Alt P를 눌러서 스크립트를 실행하고, 뷰포트 오른쪽에 있는 커스텀 패널을 열어 버튼이 동작하는지 확인합니다.

 

 

 

 

 

 

만약 블렌더 재시작 후에도 패널이 계속 남아 삭제하길 원한다면, bpy_struct.driver_remove(클래스 이름) 을 통해서 삭제해 줄 수도 있습니다.

 

 

def unregister() : 에 bpy_struct.driver_remove(TestControllerPanel) 를 추가해서 3D Panel을 강제로 삭제해 줄 수도 있습니다.

 

 

이후 블렌더를 재실행하면, panel 탭이 원래대로 돌아와 있는것을 확인할 수 있습니다.

 

 

 

 

 

 

 

 

 

profile

이것 저것 개발하고 만들어보기

@Tintana'k