본문 바로가기

프로그래밍/MaxSDK

[MAXSDK] 맥스 SDK의 기본 개념

원문 : MAX SDK 6.0 도움말, Fundamental Concepts of the MAX SDK

맥스 SDK의 기본 개념


같이 볼 것 : Must Read Section for All Developers, Advanced Topics

개관

이 섹션은 SDK를 사용하는 데 있어 필요한 기본적인 개념들에 대한 개관을 제공한다. 이것은 플러그인 응용프로그램을 생성하는 동안에 개발자가 다루게 될 기본 이슈들에 대한 많은 설명을 제공한다.

SDK 는 MAX에 있는 거의 모든 관점에 대한 엄청난 제어를 제공한다. 이런 이유를 위한 많은 정보들이 존재한다. 그러나 더 작은 분야로 쪼개질 수록, 그것들은(things) 복잡하지 않다. 이 섹션은 거의 대부분의 기본 이슈들을 간단하게 설명하며, 더욱 세부적인 정보들을 포함하고 있는 SDK 내부의 섹션에 대한 하이퍼링크를 보유한다.

맥스의 개체 지향 철학

3ds 맥스는 3D 그래픽을 위한 운영체제처럼 생각될 수도 있다. 맥스를 실행하고 있는 동안 사용자가 해야 할 것은 플러그인을 사용하는 것이다. 3ds 맥스에서 대부분의 영역은 개발자에게 공개되어 있으며, 3ds 맥스 프로그래머들은 third-party 개발자들과 같은 SDK 와 툴을 사용한다.

개발자가 생성한 플러그인 클래스의 인스턴스는 Objects 라 불리운다. 시스템과 같은 함수를 사용하기는 하지만 그것들이 다른 것들과 구분되어 새성될 수 있다는 점이 3ds 플러그인 아키텍처를 더욱 강력하게 만들어 준다. 개발자가 이 개체 지향 설계를 이용할 수 있다는 것의 가장 강력한 이점은 다른 플러그인이 그것의 작업을 수행하는 방식에 대해 알거나 걱정할 필요 없이 플러그인을 독립적으로 개발할 수 있다는 것이다. 그러나 개발자들은 3ds 맥스의 Reference Architecture 를 이해해야만 한다. (이 토픽에서 나중에 논의되는) Reference Architecture 는 모든 플러그인들이 대화할 수 있도록 허용해 주는 시스템이다.

플러그인의 유형

3ds 맥스에서 다음의 모든 영역은 플러그인으로서 구현된다; shape, spline, patch object, particle system, modifier, space wrap, light, camera, bitmap, texture map, material, image filter, compositor, animation controller, file import/export utility, atmospheric effect, renderer, sound support.

SDK 를 사용해 개발할 수 있는 모든 플러그인 유형의 리스트를 원한다면 Plug-In Types Overview 토픽을 참조하라.

맥스 플러그인 및 그것들을 생성하기 위한 도구들

이 섹션은 3ds 맥스 플러그인을 위해 사용되는 실행파일(excutable)의 유형과 그것들을 생성하기 위해 사용되는 도구들에 대해서 기술한다.

3ds 맥스를 위한 플러그인은 Microsoft Visual C++ 을 사용해 개발된다. 플러그인은 윈도우 동적 연결 라이브러리(DLL)로서 구현된다. 동적 연결 라이브러리는 함수의 공유 라이브러리로서 작동하는 실행가능한 파일이다. 동적 연결 라이브러리는 그것의 실행 코드의 일부가 아닌 함수를 호출하는 프로세스를 위한 방법을 제공한다. 함수에 대해 실행가능한 코드는 DLL에 위치하는데, 그것은 그것들을 사용하는 프로세스와는 독립적으로 컴파일되고 링크되고 저장되는 하나 이상의 함수를 포함한다.

Visual C++ 을 사용해 새로운 플러그인 프로젝트를 설정하는 방법에 대한 단계적 정보를 원한다면 Creating a New Plug-In Project 섹션을 참조하라(이것은 프로젝트를 빠르게 생성하기 위해서 이용 가능한 AppWizard 에 대한 정보를 포함한다). Visual C++ 디버거를 사용하여 플러그인을 디버깅하는 것에 대한 정보는 Debugging 토픽을 참조하라. 당신의 플러그인이 작동중이면, 당신은 속도면에서 그것을 최적화할 수 있다. 이 정보를 위해서는 Profiling Plug-in Performance 섹션을 참조하라.

C++ 소스 코드에서 특정 메서드에 대한 정보를 검색하고자 할 때 유용한 부가적인 도구들은 \MAXSDK\HELP\SDKLINK.ZIP 에 있다. 이 도구는 SDK 온라인 도움말을 실행하고, 선택된 메서드에 대한 레퍼런스 정보로 직접 건너 뛴다. 이 프로그램을 사용하기 위해서는 그것의 압축을 풀고, README.DOC 파일의 설치 및 사용 명령어를 살펴 보라.

USERTYPE.DAT 라는 파일은 사용자 Visual C++ 6.0 IDE 에서 사용자 정의 키워드들의 구문 강조(syntax highlighting)를 가능하게 하는데 사용된다. 이것은 코드를 살펴보거나 작성하는 것을 더욱 즐겁게 만들어 준다. 이 파일은 당신으로 하여금 모든 3ds 맥스 메서드들과 정의를 (색상이 칠해진 C/C++ 키워드처럼) Visual C++ 내부적으로 정의된 사용자 색상으로 강조하도록 해 준다.

이 도구를 추가하기 위해서는 \MAXSDK\HELP\USERTYPE.DAT 파일을 \DevStudio6\Common\MSDev98\Bin 디렉토리에 복사해야 한다. VC++ 을 재시작한 후에 Tools/Options/Format/Colors/User Defined Keywords 에서 수정된 색상으로 3ds 맥스 키워드의 색상을 변경할 수 있다. C++을 지정하는 Tools/Options/Format/Colors/Keywords 와 다른 색성을 할당하는 것을 권장한다. 서로 다른 색상 패턴은 코드를 이해하는 데 도움을 줄 것이다.

C++ 클래스 계층

이 섹션은 플러그인을 개발하는 데 사용되는 C++ 클래스 계층에 대해 기술한다. C++ 클래스들은 그 효율성 때문에 3ds 맥스에서 사용된다. 플러그인이 부모 프로그램으로 직접 연결될 때, 그것은 윈도우 DLL 의 형식이므로 프로그램 흐름은 3ds 맥스에서 플러그인으로 직접적으로 진행될 수 있다. 플러그인과 3ds 맥스는 메모리를 공유하며, 서로의 데이터에 직접 접근할 수 있다.

3ds 맥스 플러그인의 주요부분은 모델링, 애니메이션, 렌더링과 관련이 있다. 이들 플러그인은 Track View 에 나타나는 기능이나 어떤 개체가 수정되거나 변경될 때 다른 개체와 통신하기 위한 플러그인의 기능과 같은 공통적(일반적) 특성을 제공하는 일련의 기저 클래스들로부터 보통 상속된다. 


맥스 클래스 계층을 구성하는 세 개의 기저 클래스

이 계층의 최저 단계는 Animatable 이라는 애니메이션 관련 클래스이다. 이 클래스의 주요 메서드들은 Track View 에서의 외형(apperaing) 이나 memory management의 관리와 관련되어 있다. Animatable 에서 상속된 두 개의 클래스들은 맥스의 서로 다른 부분 간의 통신에서 사용된다.

이들은 ReferenceMarker 와 ReferenceTarget 이다. 이들 두 클래스들은 맥스에서 의존적인 오브젝트들 사이의 통신을 용이하게 하기 위해 사용된다. 이 오브젝트간 통신은 이 토픽의 뒷 부분에서 기술한다.

이들 클래스에서 상속되지 않는 플러그인들도 존재한다. 일반적으로 이들은 애니메이션과 직접 관련이 없는 요소(item)들이다. 예를 들어 import/export 플러그인은 단순히 데이터를 맥스의 내부로 가져오거나 바깥으로 보낸다. 그것들은 Track View 에 나타나지 않으며, 기능(function)이 다른 플러그인들에 대해 독립적이다.

전체 클래스 계층을 보고자 한다면 Plug-In Architecture Overview 를 참조하라. 이들 클래스의 주요 메서드들에 대한 요약은 Overview Of Principal Classes 에 있다.

플러그인이 맥스와 상호작용하는 방식

이 섹션은 3ds 맥스가 플러그인에 의해 제공되는 함수를 호출하는 방식과 플러그인이 맥스에 의해 제공되는 함수를 호출할 수 있는 방법에 대해서 논의한다.

플러그인은 맥스에 의해 제공되는 기저 클래스에 의해 상속된다. 예를 들어 기하 오브젝트 플러그인을 개발하고자 한다면, 다음과 같이 SimpleObject 클래스로부터 당신의 클래스를 상속하게 된다.

코드:
class MyGeomObject : public SimpleObject
{
    // ...
};


3ds 맥스 헤더 파일은 SimpleObject 클래스에 대한 정의를 포함한다. 당신의 플러그인에서 SimpleObject 에 요구되는 일부 메서드에 대한 구현을 제공하는 것은 프로그래머인 당신의 책임이다. 다른 말로 하자면 당신의 플러그인은 기저 클래스의 특정 메서드를 구현한다(그것을 위한 코드를 제공한다). 그리고 나서 3ds 맥스는 당신의 플러그인 상에서 이들 메서드들을 호출할 수 있다. SimpleObject 는 BuildMesh() 라는 메서드를 가진다. 이 메서드는 당신의 기하 오브젝트의 삼각형 메시 표현을 획득할 필요가 있을 때 3ds 맥스에 의해 호출된다. 당신이 구현한 SimpleObject::BuildMesh() 의 코드에서, 당신은 필요로 하는 메시를 생성한다. 3ds 맥스가 이 메시 표현을 요구할 때, 그것은 당신의 BuildMesh() 메서드를 호출한다.

다른 경우에 메서드들은 기저 클래스로부터 (맥스에 의해) 제공된다. 즉 기저 클래스 자체적으로 구현을 제공한다. 이들 메서드들은 플러그인에 으해 호출될 수 있다. 이들 메서드들은 플러그인이 상속한 기저 클래스로부터 상속된다. 예를 들어 기하 오브젝트 프리미티브는 GeomObject 로부터 상속된다. 이 기하 프리미티브는 NotifyDependents() 를 호출할 수 있다. 이것은 그 프리미티브가 기저 클래스 계층을 통해 (GeomObject->Object->BaseObject->ReferenceTarget) 상속하는 ReferenceTarget 의 메서드이다.

SDK 도움말에서 플러그인이 구현하는 메서드들은 "Implemented by the Plug-in" 이라는 딱지가 붙어 있다. 3ds 맥스가 구현을 제공하는 것들은 "Implemented by the System" 이라는 딱지가 붙어 있다.

맥스에 의해 제공되는 메서드를 플러그인이 호출하는 다른 방법이 있다. 이것은 Interface Class 에 대한 포인터를 통해 수행된다. 인터페이스 클래스는 데이터 멤버 없이 순수 가상 함수만을 가진다. 이러한 클래스들은 본질적으로는 단지 함수 포인터의 테이블이다. 인터페이스 클래스는 3ds 맥스 프로그래밍을 하는 동안 매우 자주 사용된다. 이 가장 일반적인(역주 : 추상적인이란 의미인듯) 인터페이스 클래스는 Interface 라 불리며 그렇게만 불러도 논리적으로 충분하다. 이 클래스에 대한 포인터는 많은 메서드들로 전달되며, 플러그인은 그것을 사용해 맥스에 의해 제공되는 공통적인 연산을 수행하게 된다. 예를 들어 수정자 플러그인이 그것의 사용자 인터페이스를 커맨드 패널에 보여주고자 할 때, 그것은 AddRoollupPage() 라는 Interface 의 메서드를 호출하여 그것을 다룬다. 혹은 플러그인이 맥스의 프레임 슬라이더에 의해 지정된 현재 시간을 획득하고자 한다면, GetTime() 이라 불리는 Interface 메서드가 호출된다. 더 세부적인 내용에 대해 알고자 한다면 Advanced Topics 섹션의 Interface Classes 를 참조하라.

플러그인끼리 상호작용하는 방법 -- Reference Architecture

맥스의 개체 지향 패러다임에서 독립적인 플러그인 오브젝트들이 시스템의 전반적인 기능을 이용하기 위해서 함께 작동하는 한 오브젝트간 통신이 요구된다. Reference Architecture 는 이러한 통신을 다루기 위해 3ds 맥스가 사용하는 메커니즘이다. 왜 그것이 필요한지 알기 위해 다음의 예를 살펴 보자.

3ds 맥스 애니메이션 컨트롤러 플러그인 중 하나는 Look At Controller 라 불린다. 이것은 변환 컨트롤러이며 다시 말해 그것은 씬 내의 요소에 대한 위치, 회전, 스케일링을 다룬다는 것이다. Look At 컨트롤러는 그것이 할당받은 요소를 회전시키며, 그것은 항상 다른 오브젝트를 가리키게 (혹은 바라보게) 된다. 예를 들어 당신이 자유 카메라를 생성하고 Look At 컨트롤러를 카메라의 변환 컨트롤러로서 할당했다고 하자. 그리고 나서 당신은 씬 내의 상자를 Look At 컨트롤러의 대상으로서 선택한다. 이것은 자유 카메라로 하여금 그것의 뷰의 방향이 상자의 오른쪽을 가리키는 것처럼 회전하게 만들 것이다. 상자가 움직일 때마다 컨트롤러는 스스로를 재조정해 카메라가 그것을 가리키도록 유지시키게 될 것이다. 만약 상자가 씬에서 제거되면, 그 카메라는 이것을 인지하고 단순히 정지한 상태로 남아있게 될 것이다.

이제 이러한 요소(카메라, Look At 컨트롤러, 상자) 각각이 플러그인이라고 가정하자. 그리고 각각은 다른 오브젝트에 대한 어떠한 사전 지식도 없이 작성되었다. 어떻게 그들 오브젝트들이 통신해서 다른 것을 인식하도록 할 수 있을까? 예를 들어 카메라가 그것의 뷰 방향이 상자가 움질일 때 변경되어야 함을 알 수 있는 방법은 무엇일까? 혹은 Look At 컨트롤러가 상자가 씬에서 제거되었음을 인식할 수 있는 방법은 무엇일까? 그 대답은 이 오브젝트들이 Reference 라 불리는 것을 통해서 통신해야 한다는 것이다.

Reference 는 두 개의 요소를 연결하는 방식이다. 한 아이템은 다른 것에 대해 의존적인 것으로 간주된다. 위의 예제에서 Look At 컨트롤러는 상자에 대해 의존적이며, 카메라는 Look At 컨트롤러에 대해 의존적이다. 말하자면 상자가 어떠한 방식으로 변경되면 그것은 그것에 의존하는 다른 오브젝트로 하여금 그것이 변경되었음을 알도록 해줄 필요가 있다는 것이다. Reference 를 통해 컨트롤러는 상자가 변경되었음을 통지받는다. 그리고 컨트롤러는 그것에 의존하는 다른 요소들을 위해 같은 작업을 수행할 필요가 있다. 컨트롤러가 변경되면, 그것은 그것에 의존적인 것들에게 변경을 알아차리도록 한다. 즉 카메라가 통지를 받게 된다.

Reference 를 생성함으로써 오브젝트는 이 의존성 기록을 설정한다. 오브젝트가 reference 를 만들 때, 그것은 Reference Marker 라 불린다. 참조되는 오브젝트는 Reference Target 이라 불린다. 위의 예제에서 카메라는 Reference Marker 이다. 그것은 Look At 컨트롤러를 참조한다. Look At 컨트롤러는 카메라의 Reference Target 이다. Look At 컨트롤러도 Reference Marker 이다 -- 그것은 상자를 참조한다. 상자는 컨트롤러의 Reference Target 이다. 사실 상자는 자신만의 참조를 가지고 있다. 예를 들어 그것의 변환 컨트롤러를 가지고 있다.

Reference 를 통해 생성된 상호 의존성은 맥스 전반에 걸쳐 존재한다. 간단한 씬에서는 (아마도 맥스가 내부적으로 사용하는) 수십개의 reference 가 존재한다. 복잡한 씬에서는 수백 개의 reference 가 존재할 것이다.

Reference 가 오브젝트간 통신을 위해서 사용되는 방식에 대한 세부적인 사항을 원한다면 Advanced Topics 의 Reference 섹션을 참조하라. 또한 Viewing Reference Messages 라는 섹션의 하위 주제를 참조하라. 그것은 Reference Watcher 라 불리는 유틸리티 플러그인에 대해 논의한다. 이 플러그인은 선택된 요소의 reference 구조를 이해하고 그것이 보내는 reference 메시지를 모니터링하는 데 도움을 주기 위해 사용되었다. 이것은 맥스에서의 reference 사용에 대한 빠르고 가시적인 방식의 설명을 제공한다.

맥스 Objects 의 매개 법칙(Parametric Nature) 과 플러그인의 충격(Impact)

3ds 맥스에 의해 제공되는 기하 오브젝트는 parametric 오브젝트이다. 이것은 그것들이 메시 표변을 구성하는 정점과 면으로써 직접적으로 구성되기 보다는 사용자 인터페이스 파라미터(parameter)로서 정의되었음을 의미한다. 예를 들어서 구(Sphere) 프리미티브는 그것의 반지름(radius), 세그먼트 개수(segment count), 영역 설정(hemisphere settings)에 의해 정의된다. 이것들이 메모리에 저장되며, 구 오브젝트가 디스크에 작성될 때 3ds 맥스에 의해 저장된다. 구의 삼각형 메시(triangle mesh) 표현은 렌더링을 위해 요구되지만, 그것은 파라미터로부터 '몰래(on the fly)' 계산된 것이다. 반대로 DOS를 위한 예전의 3D Studio 에서는 그렇지 않다. 그것의 오브젝트는 parametric 하지 않았으며, 표면을 기술하는 정점과 면으로서만 존재했다. 3ds 맥스에서는 언제든지 단순히 세그먼트 카운트만을 변경할 수 있으며, 표면이 재생성될 수 있다.

그러나 기하 오브젝트는 렌더링을 위해서는 반드시 삼각형 메시로 변환되어야 한다. 3ds 맥스 렌더러는 메시 오브젝트만을 사용해 작동한다. 그래서 프리미티브(primitive), 불리언(boolean), loft object, 파티클(particle), 패치(patch), 넙스(NURBS) 표면은 모두 삼각형 메시로 변환된다.

부가적으로 절차적(procedural) 오브젝트에 대해 3ds 맥스는 엄청나게 많은 수정자 집합을 제공한다. 이들 중 다수는 기저에 놓인(underlying) 오브젝트에 대한 수정(modifying), 변형(deformation), 조작(manipulation), 편집(editing)을 위한 특정 형식(form)을 제공하기 위해 오브젝트에 적용된다. 또한 사용자는 Space Wrap 플러그인을 사용해 월드 공간 위치 상에 놓은 기하도형을 수정할 수 있다. 플러그인 개발자에 대해서 이 모든 것이 함축하고 있는 것은 parametric 오브젝트에서 수정된 삼각형 메시로의 변환 과정을 이해할 필요가 있다는 것이다.

3ds 맥스의 Geometry Pipeline System 이 이 과정과 변환을 다루기 위해 사용된다. 기하도형 파이프라인은 parametric 오브젝트들이 수정자에 의해 뷰포트에 디스플레이되고 렌더링하는데 적절한 삼각형 메시로 생성되는 것을 허용하기 위해 사용된다. 전체적인 세부사항을 원한다면 Advanced Topics 섹션의 Geometry Pipeline System 을 참조하라. 절차적 오브젝트와 수정자가 수정(modification)을 용이하게 하기 위해 함께 동작하는 방식에 대해 알고자 한다면 Object Modification 섹션을 참조하라.

플러그인 개발자들은 Collapse Utility 를 위한 코드를 학습하는 것이 도움이 될 것이다. 이 유틸리티는 사용자가 하나 이상의 선택된 오브젝트의 Stack 을 하나의 Editable Mesh 로 줄일 수 있도록 해 주고, 선택적으로 그것들 상에서 동시에 Boolean 연산을 수행하도록 해 준다. \MAXSDK\SAMPLES\UTILITIES\COLLAPSE.CPP 에 있는 코드를 참조하라.

씬 -- 노드

3ds 맥스 씬, 즉 오브젝트, 광원, 카메라, space wrap, 파티클 등은 각각 노드와 연결되어 있다. 씬과 노드의 각 요소 사이에는 1 대 1 관계가 존재한다. 노드는 단순히 그것의 관련 오브젝트를 씬에 존재하게 하기 위해서 필요한 정보를 관리하는 요소일 뿐이다. 이들은 변환 컨트롤러나 사용된 재질, 부모-자식 계층에 대한 데이터, 그룹화(grouping) 정보와 같은 것들이다.

노드의 변환 컨트롤러는 씬 내 오브젝트의 위치, 회전, 스케일링을 제어한다. 노드와 연결된 재질은 색상, 텍스처, 범프 등과 같은 표면 특징을 오브젝트에 부여하기 위해서 렌더러에 의해 사용된다. 계층 정보는 순/역 운동학(forward and inverse kinematics)를 위한 오브젝트의 linked/unlined 상태를 다루기 위해서 사용된다.

더 세부적인 정보를 원한다면 Advanced Topics 섹션인 Nodes, Working With Material and Textures, Working with Controllers 를 참조하라.

시간(Time)과 간격(Interval)

애니메이션을 취급하는 개발자는 특정 시간 지점과 특정 시간 간격을 지정할 필요가 있다. 이 섹션은 이들 각각에 대해 논의한다.

SDK 와 3ds 맥스에서 기본 시간 단위는 1/4800 초이다. 이 시간 길이는 TimeValue라 불리는 데이터형이다. TimeValue 는 특정 시간 단위 인스턴스가 지정될 필요가 있을 때 SDK 에서 클래스 메서드를 통해 사용된다. 예를 들어 당신의 플러그인이 (3ds 맥스 프레임 슬라이더의 위치에 있는) 현재 시스템 시간을 알 필요가 있을 때, 그것은 Interface::GetTime() 메서드를 호출할 것이다. 이 메서드는 TimeValue 값을 반환하는데, 그것은 현재 시간을 가리킨다(1/4800 초 단위로).

맥스에서 인터벌은 보통 오브젝트가 변경되지 않은 시간 간격을 정의하는 데 사용된다. 최대한 (프로그램을) 빠르게 하기 위해서 3ds 맥스는 가능한한 오브젝트를 재계산하는 것을 피한다. 만약 애니메이션되는 플러그인이 그것이 변경되지 않는 간격이 얼마인지를 지정할 수 있다면, 3ds 맥스는 그 시간 동안에 그 오브젝트를 재평가할 필요가 없음을 알 수 있을 것이다. 예를 들어 3ds 맥스는 수정자에 의해 수행되는 수정이 유효한 시간의 길이를 알 필요가 있다. Bend 수정자에서 사용자는 bend angle을 일정 시간동안 애니메이션 했다고 간주하자(0 부터 50 프레임까지는 구부려지지 않않고, 100 프레임에서 45도 구부려졌다). 그러면 3ds 맥스는 매프레임마다 수정자를 재평가할 필요가 없으며(0 부터 50 프레임까지는 구부려지지 않고 있다), 수정자는 3ds 맥스에 얼마나 오랫돈안 변형이 유효한지를 알려주는 Validity Interval 을 제공한다. 이 유효 인터벌은 특정 시간과 관련이 있다. 예를 들어 3ds 맥스가 수정자에게 프레임 0 에서 수정이 얼마나 오랫돈안 유효한지 질의했다고 하자. 수정은 프레임 0부터 50까지 유효하다. 만약 3ds 맥스가 프레임 50 과 75에서 수정이 얼마나 유효한지를 물으면, 대답은 단지 짧은 시간(single instant of time)일 것이다. 왜냐하면 프레임 50부터 100까지 수정자가 애니메이션되기 때문이다. 각 프레임에서 그것들은 서로 다르다(최종적인 45도를 향해서 좀 더 구부려진다). 결국 유효 인터벌은 단지 단일 시간 지점(a single point in time)(혹은 TimeValue)이다.

SDK에서 시간 간격은 Interval 오브젝트를 사용해 지정된다. 이 오브젝트는 시작 및 종료 시간, 그리고 간격을 사용해 작업할 수 있는 다양한 메서드를 소유한다. 맥스에서 유효 인터벌을 지정하기 위해서 플러그인이 구현하는 많은 메서드들이 존재한다. 위의 수정자 예제는 Modifier::LocalValidity() 메서드에서 그것을 수행할 것이다. SDK 에서의 Time 에 대한 더 많은 정보를 원한다면, Advanced Topics 섹션 Time 을 참조하라. 인터벌에 대한 더 많은 정보를 원한다면 Intervals 토픽에서 찾아볼 수 있다.

애니메이션 컨트롤러들

3ds 맥스에서 모든 애니메이션은 애니메이션 컨트롤러(또는 줄여서 컨트롤러)라 불리는 플러그인 유형에 의해 관리된다. 어떤 컨트롤러들은 키프레임 기반이다. 이것은 사용자가 시간 단위로 중요 (key) 지점에 컨트롤러에 대한 값을 설정한다는 것, 그리고 컨트롤러가 다른 시간대의 값을 키 값 사이의 보간을 통해 제공한다는 것을 의미한다. 그 외의 것들은 절차적이며, 이는 값이 미리 프로그래밍된 이펙트에 기반한 특정 시간에서 계산되다는 것을 의미한다(예를 들어 Noise 컨트롤러는 값을 계산하기 위해 fractal 함수를 사용한다).

그것들이 제어할 수 있는 데이터 유형에 기반해 여섯 개의 기본 컨트롤러 유형이 존재한다 : 부동소수점 값(float), 세 개의 부동소수점 값(Point3), 위치(Matrix3), 회전(Quat), 스케일링(ScaleValue), 변환(Matrix3). 개발자들은 SDK를 사용해 새로운 컨트롤러 유형을 생성하거나 현존하는 유형의 속성을 사용해 작업을 할 수 있다. 더 많은 정보를 원한다면 Working With Controllers 토픽을 참조하라.

많은 플러그인들이 애니메이션되는 파라미터를 사용하는데, 예를 들어 절차적 구의 애니메이션되는 반지름(radius) 파라미터이다. 3ds 맥스는 애니메이션되는 파라미터를 사용하기 원하는 개발자를 위해서 그것들을 매우 쉽게 관리할 수 있도록 해주는 도구들을 제공한다. 이들 중 두 개를 들면 Parameter Blocks 와 Parameter Maps 가 있다. Parameter Blocks 는 플러그인 파라미터에 대한 값을 저장하고 값의 보간이나 생성을 다루는 컨트롤러를 관리하는 메커니즘을 제공한다. Parameter Maps 는 플러그인의 사용자 인터페이스에 있는 컨트롤을 애니메이션된 값과 연관시키는 데 사용된다. 세부적인 사항을 원한다면 Advanced Topics의 섹션 Parameter Blocks and Maps in Release 3 and Later, Parameter Maps, Parameter Blocks 를 참조하라.

사용자 인터페이스 이슈

사용자는 command panel rollup/dialog, 마우스(또는 타블릿), 키보드, 3D 뷰포트를 통해 주로 3ds 맥스와 상호작용한다. SDK 는 개발자에게 사용자 상호작용에 대한 이러한 각 영역들을 제어할 수 있는 기능을 부여한다.

플러그인은 일반적으로 그것들의 사용자 인터페이스 컨트롤을 세 가지 중 하나의 방식으로 제공한다 : 하나 이상의 Command Panel 가지(branches)에서, Material Editor, Environment, Render dialog 에서 보이는 롤업(rollup)에서, 혹은 modal/modeless 다이얼로그로서... 이런 다이얼로그/롤업에서 보이는 많은 버튼, 스피너(spinner, 역주 : 윈도우 컨트롤 중에 스크롤바의 화살표 같은 거만 있는 모양), 에디트 필드 등은 3ds 맥스가 제공하는 Custom Controls 집합에서 생겨난 것이다. 이들은 플러그인의 UI를 다른 것에 대해서 외형적으로 일관되게 보이도록 하기 위해 사용된다. 이들 컨트롤에 대한 더 많은 정보나 그것들이 작동하는 방식에 대해 알고자 한다면 Custom User Interface Controls 를 참조하라.

custom control 에 대해 더 언급하자면, 마우스는 맥스와 상호작용을 위해 사용된다. 이러한 유형의 상호작용 방식은 SDK 에서 Command Modes라 불리는 것을 통해 다뤄진다. 더 많은 정보를 원한다면 Command Mode and Mouse Procs 섹션을 참조하라.

플러그인은 그들의 플러그인과 사용자의 상호작용 속도를 높이기 위해서 키보드를 사용하기도 한다. 이것은 Keyboard Accelerators 라 불리는 것을 등록함으로써 수행된다. 이들은 그들의 플러그인에 있는 기능들을 keystroke에 할당함으로써 사용자가 그것들을 실행할 수 있도록 허용한다. 이것이 수행되는 방식에 대한 더 많은 정보를 원한다면 Advanced Topics 섹션 Keyboard Accelerators and Dialog Messages 를 참조하라.

마지막으로 플러그인은 종종 그 자체나 그것의 'gizmo'를 보여주기 위해 3D 뷰포트에 그려질 필요가 있다. 이것은 interactive 렌더러 클래스인 GraphicsWindow 에 의해 제공되는 메서드를 사용해 수행될 수 있다. 이 렌더러를 사용해 작업하는 방법에 대해 알고자 한다면, Interactive Renderer : GraphicsWindow 를 참조하라.

모든 플러그인이 제공해야만 하는 함수들

이 섹션은 모든 플러그인 DLL 에서 요구되는 다섯 개의 함수 집합에 대해 기술한다. 또한 오브젝트 개발자가 각 플러그인 클래스를 위해 제공할 필요가 있는 것에 대한 아웃라인을 제공한다.

    모든 플러그인 개발자는 네 개의 Lib 함수와 DllMain 함수에 대한 코드를 제공해야만 한다. 각각은 아래에 간단히 기술되어 있다 :

    초기화를 다루기 위해 호출되는 함수

      DllMain() -- 이 함수는 DLL을 초기화하기 위해 윈도우에 의해 사용되는 훅(hook)이다. 3ds 맥스 플러그인은 그것을 사용해 공통 컨트롤 라이브러리와 맥스의 사용자 컨트롤을 초기화한다.


    목록을 만들고 DLL에서 플러그인을 분류하기 위해 맥스에 의해 사용되는 함수들


      LibNumberClasses() -- 이 함수는 DLL 에 포함된 플러그인 클래스들의 개수를 반환한다.
      LibVersion() -- 이 함수는 시스템으로 하여금 플러그인 DLL의 쓸모없는(obsolete) 버전을 다루도록 한다.
      LibDescription() -- 이 함수는 DLL 이 이용 불가능할 때 사용자에게 제출할 텍스트 문자열을 반환한다.
      LibClassDesc() -- 이 함수는 DLL 의 각 플러그인 클래스에 대해 Class Descriptor 라 불리는 오브젝트에 대한 포인터를 반환한다. 이 Class Descriptor 오브젝트는 각 플러그인 클래스의 속성과 메모리에 클래스의 인스턴스를 할당하는 방식을 기술한다. 다음 섹션은 이들 Class Descriptor 에 대해 기술한다.


    플러그인 클래스의 인스턴스를 생성하고 분류하기

    위에서 기술된 Class Descriptor 는 ClassDesc 클래스로부터 상속된 오브젝트이다. 그것은 몇 가지 중요한 목적을 가지고 있다. 두 개의 주요한 것은 플러그인의 오브젝트 유형을 분류하는 것과 관련이 있으며, 플러그인의 오브젝트의 인스턴스를 위한 메모리를 할당하는 것과 관련이 있다. Class Descriptor 에 대한 전체 세부 사항을 기술할 수도 있지만, 세 가지 중요한 메서드만 아래에 기술했다.

    모든 유형의 플러그인은 3ds 맥스 시스템 오브젝트를 생성한다. 이들은 씬에 보이는 3D 오브젝트가 아니라, C++ 관점의 오브젝트이다. 각 플러그인 시스템 오브젝트와 관련한 두 개의 ID 가 있다. 이것들은 Super Class ID 와 Class ID 이다. Super Class ID 는 플러그인 클래스가 3ds 맥스의 상위 클래스의 하위클래스임을 가리킨다. Class ID 는 상위 클래스를 위한 다양한 플러그인 사이의 차이점을 식별한다. 예를 들어 Sphere 오브젝트는 Class ID 를 가지고 있으며, 그것을 단일하게 식별한다. 이것은 단지 플러그인 클래스를 단일하게 식별하는 SDK 에 의해 제공된 프로그램을 사용하여 생성된 ID일 뿐이다(그것은 \MAXSDK\HELP\GENCID.EXE 에 있다). 모든 기하 오브젝트에 의해 공유되는 그것의 Super Class ID는 GEOMOBJECT_CLASS_ID 이다. 이 Super Class ID 는 맥스에 의해 정의된다. 그리고 각 플러그인은 이러한 기정의된 카테고리중 하나로 분류된다. 예를 들어 모든 Texture Map 플러그인들은 같은 Super Class ID 인 TEXMAP_CLASS_ID 를 공유한다. 그러나 개별 텍스처 매핑 플러그인들은 각자 자신만의 단일 Class ID 를 가지고 있다. 즉 Super Class ID 는 어떤 종류의 오브젝트인지를 정의하고, Class ID 는 단일하게 특정 플러그인 클래스를 식별한다.
    Class Descriptor 메서드 ClassDesc::SuperClassID() 는 Super Class ID 를 반환한다. ClassDesc::ClassID() 는 Class ID 를 반환한다.

    Class Descriptor 의 다른 함수는 플러그인 클래스의 인스턴스를 할당하기 위한 것이다. 예를 들어 절차적(procedural) Sphere를 포함하는 3ds 맥스 파일이 로드될 때, 3ds 맥스는 Sphere 플러그인의 인스턴스를 생성하는 방식을 필요로 한다. 그것은 Sphere 의 Class Descriptor 의 메서드인 ClassDesc::Create() 를 호출한다. 이 메서드에 대해서는 다음 섹션에서 살펴 보자.

    위에서 약술한(outlined) 함수는 Advanced Topics 섹션 DLL/Lib Functions and Class Descripotrs 에서 더 세부적으로 다루고 있다.

    플러그인 클래스들의 메모리 할당과 해제

    위에서 논의했듯이, 플러그인 클래스들의 인스턴스는 Class Descriptor 의 Create 메서드(ClassDesc::Create())를 호출함으로써 생성된다. 이것은 SDK의 모든 플러그인 클래스에 대해 적용된다.

    이 메모리가 해제되는 방식은 플러그인이 어떤 클래스를 상속했느냐에 따라 다르다. 보통 그것은 플러그인 상에서 DeleteThis() 라는 메서드를 호출함으로써 수행된다. Animatable 클래스 계층의 일부분인 클래스에서는 이것은 Animatable 의 메서드이다. 그래서 이러한 플러그인을 위해서 메모리는 ClassDesc::Create() 메서드에 의해 할당되고, Animatable::DeleteThis() 에 의해 해제된다.

    Animatable 로부터 상속되지 않은 다른 플러그인들에 대해서는 플러그인 자체적으로 DeleteThis() 메서드를 제공해야 한다. 예를 들어 Bitmap 클래스는 Animatable 로부터 상속되지 않는다. 그러나 그것은 자신의 DeleteThis() 메서드를 제공해 ClassDesc::Create() 에 의해 생성된 메모리를 해제한다.

    그 외의 경우에 메모리는 그것이 플러그인을 사용해 수행될 때 3ds 맥스 자체에 의해 자동적으로 해제된다(In other cases, memory is freed automatically by 3ds max itself when it is done with the plug-in). 예를 들어 Video Post 에서 사용되는 image processing effect 를 생성하기 위해 사용되는 ImageFilter 클래스는 3ds 맥스 자체에 의해 헤제되는 메모리를 소유한다(delete 연산자를 사용한다).

    세부적인 사항을 원한다면 Advanced Topics 섹션 Memory Allocation 을 참조하라.
 


요약

이 토픽은 3ds 맥스 플러그인을 생성하기 위해서 개발자가 이해할 필요가 있는 기초적인 이슈들에 대해서 살펴보기 위한 것이다. SDK 에 있는 Advanced Topics 섹션은 API 의 많은 관점에 대한 세부적인 정보를 제공한다. 특정 플러그인 유형에 대한 SDK의 관련 부분을 살펴보고 싶으면 Must Read Section by Plug-In Type 섹션을 참조하라.
 


 

[출처] - 라이푸님의 http://blog.naver.com/lifeisforu 네이버 블로그

'프로그래밍 > MaxSDK' 카테고리의 다른 글

[MAXSDK] 기하 파이프라인 시스템  (0) 2009.12.03
[MAXSDK] 인터벌  (0) 2009.11.30
[MAXSDK] 메모리 할당  (0) 2009.11.30
[MAXSDK] DLL, 라이브러리 함수, 클래스 기술자  (0) 2009.11.30
[MAXSDK] SDK 일반 용어  (0) 2009.11.30