[번역 : AOSA Volume 1, 24장] VTK

이 내용은 AOSA(The Architecture of Open Source Applications) Volume 1의 24장을 번역한 내용입니다. 참고로, 오역이 상당히 많으니 원문을 꼭 참고해서 보시기를 강추합니다.

VTK(시각화 툴킷)는 데이터 처리와 시각화를 위해서 폭넓게 사용되는 소프트웨어 시스템이다. VTK는 과학 연산, 의료 영상 분석, 계산 기하학, 렌더링, 영상 처리와 정보과학(informatics)에서 사용한다. 이 장에서는 성공적인 시스템을 만드는 기본 디자인 패턴의 일부를 포함하는 VTK의 간략한 개요를 제공한다.

소프트웨어 시스템을 제대로 이해하려면, 소프트웨어가 해결하는 문제가 무엇인지 이해하는 것과 더불어, 소프트웨어가 등장하는 특정 문화의 이해가 필요하다. VTK의 경우, 표면적으로는 과학적 데이터를 위한 3D 시각화 시스템으로 개발했다. 소프트웨어가 등장하는 문화적 상황은 노력에 의미 있는 뒷이야기를 추가하고, 그 당시의 소프트웨어 설계 및 배포 이유를 설명하는데 도움을 준다.

VTK를 계획하고 개발할 당시에, 초창기 저자들(Will Schroeder, Ken Martin, BillLorensen)은 GE(R&D)의 연구원이었다. GE에서는 C 언어로 구현한 스몰토크(Smalltalk)와 비슷한 환경인 LYMB로 알려진 프리커서(precursor) 시스템에 매우 많이 투자했다. 그 당시에, LYMB가 대단한 시스템이긴 했지만, 연구원으로 일을 진행하려고 시도할 때, 계속 두 가지 장벽으로 인해 좌절했다: 1) IP 문제와 2) 비표준, 특허 소프트웨어. IP 이슈는 GE 외부에 소프트웨어를 배포하려는 시도는 회사 변호사가 관여하게 되면 거의 불가능했기 때문에 문제가 되었다.

두 번째로, GE 내부에 소프트웨어를 배포해도, 많은 직원(고객)들이 숙련된 직원이 회사를 그만둘 때, 숙련의 노력이 다른 직원으로 전달되지 않기 때문에, 독점 및 비표준 시스템을 배우는 것을 꺼렸고, 표준 도구 셋의 폭넓은 지원을 받지 못했다. 따라서 결국에는 VTK의 주요 동기는 쉽게 기술을 고객에게 전수할 수 있도록 하는 개방형 표준 혹은 협력 플랫폼(collaboration platform )을 개발하는 것이었다. 따라서 VTK에 대한 오픈 소스 라이선스 선택은 아마도, 우리가 한 디자인 결정 중에 가장 중요한 것이었다.

이 라이선스(GPL이 아닌 BSD)가 궁극적으로 VTK를 기반으로 서비스와 컨설팅 기반의 비즈니스를 활성화 시켜서 결국, Kitware(각주 필요)가 생겨났기에, 돌이켜 보면, 비상호주의(non-reciprocal), 관대한 라이선스 선택은 저자의 훌륭한 결정이었다. 그 당시에는 학계, 연구실, 그리고 회사와의 협력을 위한 장애물을 감소시키는 것이 주된 관심사였다. 상호주의 라이선스(reciprocal licenses)가 큰 손해를 입을 수 있는 잠재적인 위험 때문에 많은 조직이 기피한다는 것을 발견했다.

사실, 상호주의 라이선스(reciprocal licenses)가 오픈 소스 소프트웨어의 수용을 매우 더디게 한다고 생각하지만, 그것은 다음 논쟁거리이다. 요점은 다음과 같다: 특정 소프트웨어 시스템과 연관해서 해야 하는 주요 설계 결정 중의 하나가 저작권 라이선스의 선택이다. 프로젝트 목적을 검토하고 다음에 IP 문제를 적절히 해결하는 것이 중요하다.

24.1. VTK란 무엇인가?

처음에, VTK는 과학적 데이터 시각화 시스템으로 계획했다. 다른 분야의 사람들은 단순히 기하학 렌더링(가상 물체와 이것들의 상호작용을 시험하는)의 특정 형태로 생각한다. 이것도 확실히 시각화 일부이지만, 일반적으로 데이터 시각화는 데이터를 지각적 정보(sensory input)나, 일반적인 이미지뿐 아니라 촉감, 청각 그리고 다른 형태도 포함하고 있는 전체과정을 포함한다. 데이터 형태는 메시(mesh)나 복합적 공간 분해(complex spatial decompositions)와 같은 추상적 개념을 포함하는 기하학과 위상 구조로 구성한 것과 더불어, 스칼렛(scalars, 예로, 온도나 압력), 벡터(vectors, 예로, 속도), 텐서(tensors, 예로, 응력과 변형률)와 같은 핵심 구조에 법선 속도면(surface normal)과 텍스처 좌표(texture coordinate)와 같은 렌더링 속성도 추가한다.

일반적으로 시공간(spatial-temporal) 정보를 나타내는 데이터는 과학적 시각화의 일부로 여겨지는 것에 주의해라. 그러나 마케팅 인구 통계, 웹 페이지, 문서와 비구조화된 문서, 테이블, 그래프, 트리와 같은 추상적 관계(즉, 시공간이 아닌)로 나타낼 수 있는 또 다른 정보와 같은 더 많은 추상 데이터 형태가 있다. 일반적으로 이런 추상 데이터는 정보 시각화의 방법으로 해결한다. 현재, VTK는 커뮤니티의 도움으로, 과학과 정보 시각화 둘 다에서 사용할 수 있다.

시각화 시스템으로써, VTK의 역할은 궁극적으로 이런 형태의 데이터를 가져와서 인간의 감각으로 이해할 수 있는 형태로 데이터를 변환하는 것이다. 따라서 VTK의 핵심 요구사항 중의 하나는 데이터를 받고, 처리하고, 표현하고 궁극적으로 데이터를 렌더링할 수 있는 데이터 플로우 파이프라인(data flow pipelines)을 만드는 능력이다. 그러므로 툴킷은 필연적으로 유연한 시스템으로 설계되었고, 툴킷의 설계는 이를 다양한 레벨에서 반영한다. 예를 들면, 매우 다양한 데이터를 처리할 수 있는 교체 가능한 많은 컴포넌트를 가진 툴킷을 목표로 VTK를 설계했다.

24.2. 아키텍처 특징

VTK의 아키텍처 특징으로 들어가기 전에, 시스템 개발과 사용에 큰 영향을 주는 고 수준 개념들이 있다. 이런 개념들 중의 하나가 하이브리드 래퍼(hybrid wrapper) 기능이다. 이 기능은 자동으로 VTK의 C++ 구현(추가된 언어가 있을 수도 있다)에서 파이썬, 자바와 Tcl용의 언어 바인딩을 만든다.

실력 있는 상당수의 개발자는 C++로 작업할 것이다. 사용자와 애플리케이션 개발자는 C++를 사용할 수도 있지만, 종종 위에서 언급한 인터프리터 언어를 선호했다. 이런 하이브리드 컴파일/인터프리터 환경은 상반된 두 가지의 장점을 결합한다. 고성능 연산-집약적(compute-intensive)인 알고리즘과 애플리케이션을 프로토타이핑하거나 개발할 때의 유연성. 사실, 다중-언어(multi-language) 컴퓨팅에 대한 접근은 과학 컴퓨팅 커뮤니티에서 많은 것들과 함께 인기가 있었고, 종종 자신의 소프트웨어를 개발하기 위한 템플릿으로 VTK를 사용한다.

소프트웨어 프로세스에 대해서, VTK는 빌드를 제어하기 위해 CMake; 테스트를 위해 CDash/CTest; 크로스 플랫폼 배포를 위해 CPack을 사용한다. 실제로, VTK는 보통 원시 개발 환경으로 악명이 높은 슈퍼컴퓨터를 포함해서 대부분 컴퓨터에서 컴파일할 수 있다. 게다가, 웹 페이지, 위키, 메일링 리스트(사용자와 개발자), 문서 생성 기능(예로, Doxygen)과 버그 관리툴(Mantis)을 사용해서 개발 도구를 완성하게 한다.

24.2.1. 핵심 특징

VTK가 객체 지향 시스템이기에, 클래스와 객체 데이터 멤버의 접근을 조심해서 다루고 있다. 일반적으로, 모든 데이터 멤버는 protected이거나 private이다. 데이터에 대한 접근은 부울(Boolean) 데이터, 모달(modal) 데이터, 문자열과 벡터를 위한 특정 변수로, Set과 Get 메서드로 접근한다. 실제로 이 메서드 대부분은 클래스 헤더 파일에 매크로를 추가해서 만든다. 그래서, 예를 들면:

vtkSetMacro(Tolerance, double);
vtkGetMacro(Tolerance, double);

상세히 하면 아래가 된다:

virtual void SetTolerance(double);
virtual double GetTolerance();

단순히 코드의 명확함 이상으로, 이런 매크로를 사용하는 많은 이유가 있다. VTK에는 디버깅을 제어하고, 객체의 수정 시간(MTime)을 갱신하고, 적절히 참조 계수를 관리하는 중요한 데이터 멤버가 있다. 이 매크로들은 중요한 데이터를 정확하게 조작하고, 매크로의 사용을 강력하게 추천한다. 예로, VTK에서 객체의 수정 시간이 적절히 관리되지 않을 때, 특히 치명적인 버그가 생긴다. 이 경우의 코드는 수행해야 할 때 수행하지 않거나 너무 자주 수행할 수도 있다.

VTK의 강점 중의 하나가 데이터 표현과 관리 수단이 비교적 단순하다는 것이다. 일반적으로, 특정 타입의 다양한 데이터 배열(예로, vtkFloatArray)은 인접한 정보의 부분을 나타내는 데 사용한다. 예로, 세 개의 XYZ 포인트 리스트는 아홉 개 엔트리(x,y,z, x,y,z, 등)의 vtkFloatArray로 표현할 수 있다. 이 배열에는 튜플의 개념이 있어서, 3D 포인트는 3-튜플이고, 반면 대칭 3×3 텐서 매트릭스는 6-튜플로 나타낸다(대칭 공간 저장이 가능한).

이 설계는 과학 연산에서 배열을 조작하는 시스템(예로, 포트란)과 인터페이스로 연결하는 것이 일반적이기 때문에 의도적으로 적용되었고, 이는 크고 인접한 청크(chunk)에서 메모리를 할당하고 해제하는 데 있어 더 효율적이다.

게다가, 일반적으로 통신, 직렬화와 IO 수행은 인접한 데이터를 이용하면 훨씬 더 효율적이다. 이 핵심 데이터 배열(다양한 타입의)은 VTK에서 많은 데이터를 표현하고, 빠른 접근을 위한 메서드와 데이터를 추가할 때, 필요에 따라 메모리를 자동으로 할당하는 메서드를 포함해서 정보에 접근하고 입력하기 위한 여러 가지 편리한 메서드를 가지고 있다. 데이터 배열은 vtkDataArray 추상 클래스의 서브 클래스이고 이는 제네릭 가상 메서드(generic virtual methods)가 코딩을 단순화하는 데 사용될 수 있다는 것을 의미한다.

그러나 더 좋은 성능을 위해서 인접 데이터 배열을 연속적이고 직접 접근해서 타입 기반의 스위치(switch)를 사용하는 정적(static) 템플릿 함수를 사용한다.

일반적으로 C++ 템플릿은 성능의 이유로 널리 사용되지만, public 클래스 API에서는 볼 수 없다. 이것은 STL에도 해당된다: 일반적으로 사용자나 애플리케이션 개발자에게 템플릿 구현의 복잡함을 감추기 위해 PIMPL 디자인 패턴을 적용한다. 이는 이전에 설명한데로 래핑한 코드가 해석도니 코드가 될 때 특히 도움이 되었다. Public API에서 템플릿의 복잡성을 줄이는 것은, 애플리케이션 개발자 관점에서, VTK 구현이 데이터 타입 선택의 복잡성에서 거의 벗어난다는 것을 의미한다. 물론 후드(hood) 아래에서 코드 실행은 일반적으로 데이터에 접근할 때 런타임에 결정되는 데이터 타입으로 이루어진다.

일부 사용자는 VTK가 메모리 관리를 위해, 가비지 콜렉션과 같이 사용자에게 더 친숙한 방식을 사용하지 않고, 참조 계수를 사용하는 이유를 궁금해한다. 기본적인 대답은 데이터 크기가 거대할 수 있기에, 데이터를 삭제할 때 VTK의 완벽한 제어가 필요하다는 것이다. 예로, 바이트(byte) 데이터 1000×1000×1000의 볼륨 크기는 기가바이트(gigabyte) 크기이다. 가비지 콜렉터가 이 데이터를 해제할 건지 아닐지를 결정하는 동안 이 데이터를 남겨두는 것은 좋은 생각이 아니다. VTK에서 대부분 클래스(vtkObject의 서브클래스)는 참조 계수를 위한 내장 기능이 있다.

모든 객체는 객체가 만들어질 때 ‘1’로 초기화된 참조 계수를 포함한다. 매번 객체의 사용을 등록하고, 참조 계수는 하나씩 증가한다. 비슷하게, 객체의 사용을 등록하지 않을 때(또는 같은 객체가 삭제될 때) 참조 계수는 하나씩 감소한다. 결국, 객체의 참조 계수는 객체 자체가 소멸하는 것을 가리키는 ‘0’으로 감소한다. 일반적인 예제는 다음과 같다.

vtkCamera *camera = vtkCamera::New();   //reference count is 1
camera->Register(this);                 //reference count is 2
camera->Unregister(this);               //reference count is 1
renderer->SetActiveCamera(camera);      //reference count is 2
renderer->Delete();                     //ref count is 1 when renderer is deleted
camera->Delete();                       //camera self destructs

VTK에서 참조 계수가 중요한 또 다른 이유가 있다—참조 계수가 효율적으로 데이터를 복사하는 기능을 제공한다. 예를 들어, 점, 다각형, 색, 스칼렛(scalars)과 텍스처 좌표(texture coordinates)와 같은 많은 데이터 배열로 이루어진 데이터 객체 D1을 생각해보자. 이제 처음 데이터 배열에 벡터 데이터(점의 위치)를 추가한 새로운 데이터 객체 D2를 생성하기 위해 데이터 배열을 처리하는 것을 생각해 보자. 한 가지 비 효율적인 방식으로 D1을 복사(deep copy)해서 D2를 만들고, D2에 새로운 벡터 데이터 배열을 추가한다는 것이다.

그 대신에, 빈 D2를 만들고 다음에 데이터의 소유를 관리하기 위해 참조 계수를 사용해서, D1에서 D2로 배열을 복사(shallow copy)하고, 마지막으로 새로운 벡터 배열을 D2에 추가한다. 후자의 방식은 앞에서 살펴본 것처럼, 좋은 시각화 시스템에 필요한 데이터 복사를 방지한다. 이 장의 뒷부분을 보면 알겠지만, 데이터 처리 파이프라인은 알고리즘의 입력값에서 출력으로 데이터를 복사하는 것과 같은 동작을 반복해서 수행하기 때문에, 참조 계수는 VTK에 필수이다.

물론, 참조 계수도 잘 알려진 몇 가지 문제점이 있다. 때때로, 상호 지원하는 환경에서 서로 참조하는 객체(순환 참조하는)가 존재할 수 있다. 이 경우, 지능적인 중재가 필요하고, VTK의 경우에는 vtkGarbageCollector에서 주기에 연관된 객체를 관리하는 특별한 기능을 구현했다.

순환 클래스가 확인될 때(이것은 개발하는 동안 예상했다), 클래스는 가비지 콜렉터에 자신을 등록하고, 자신의 Register, UnRegister 메서드를 오버로드한다. 다음의 객체 삭제(또는 등록해제) 메서드는 서로 참조하는 객체의 분리된 객체(detached islands)를 찾기 위해 로컬 참조 계수 네트워크에서 위상 분석(topological analysis)을 수행한다. 그 다음에 가비지 콜렉터가 이것을 삭제한다.

VTK 대부분의 객체 초기화는 정적 클래스 멤버로 구현한 객체 팩토리(object factory)를 사용한다. 일반적인 문법은 다음과 같다:

vtkLight *a = vtkLight::New();

여기에서 알아야 하는 중요한 것은, 실제로 객체를 초기화하는 것이 vtkLight 가 아닐 수 있고, vtkLight의 서브클래스일 수 있다(즉, vtkOpenGLLight). 객체 팩토리를 사용하는 다양한 동기가 있지만, 가장 중요한 것은 애플리케이션의 이식성과 장치의 독립성이다.

예를 들면, 위에서 렌더링 된 화면에 조명을 만들고 있다. 특정 플랫폼의 애플리케이션에서, vtkLight::New는 결과로 OpenGL 라이트가 될 수 있지만, 다른 플랫폼에서 그래픽 시스템에서 라이트를 만들기 위해서 다른 렌더링 라이브러리나 메서드가 있을 가능성이 있다. 정확하게 파생된 클래스를 객체화하는 것은 런타임 시스템 정보의 기능이다. VTK 초기에는 gl, PHIGS, Starbase, XGL와 OpenGL을 포함해서 매우 많은 선택 사항이 있었다. 대부분의 이런 것들이 사라졌지만, DirectX와 GPU를 기반으로 한 접근 방법을 포함해서 새로운 접근 방식이 나타나고 있다.

시간이 지나면서, 개발자가 vtkLight 에 새로운 장치의 특정 서브 클래스와 진화중인 기술을 지원하기 위한 다른 렌더링 클래스의 구현으로 VTK로 개발한 애플리케이션을 변경할 필요가 없다. 객체 팩토리의 또 다른 중요한 사용은 성능-향상(performance-enhanced) 변화를 런타임에 교체할 수 있다는 것이다. 예로, vtkImageFFT 는 특수용 하드웨어나 수치 라이브러리에 접근하는 클래스로 교체될 수 있다.

24.2.2. 데이터 표현

VTK의 강점 중의 하나가 복잡한 데이터 형태를 표현하는 기능이다. 복잡한 데이터 형태는 단순한 테이블에서부터 유한요소 메쉬(finite element meshes)와 같은 복잡한 구조를 포함한다. 이런 데이터 형태는 전부 그림 24.1에서 보는 것과 같이 vtkDataObject의 서브 클래스이다(그림 24.1은 많은 데이터 객체 클래스의 부분적인 상속 도표임을 주의해라).

그림 24.1 데이터 객체 클래스

vtkDataObject의 가장 중요한 특징 중의 하나는 데이터 객체가 시각화 파이프라인에서 처리될 수 있다는 것이다(다음 절). 그림 24.2에서 볼 수 있는 많은 클래스에서, 대부분의 애플리케이션에서 사용하는 것은 일부이다. vtkDataSet과 파생된 클래스는 과학 시각화를 위해 사용된다(그림 24.2). 예를 들면, vtkPolyData는 다각형의 메쉬를 나타내는 데 사용하고, vtkUnstructuredGrid는 메쉬를 나타내고, vtkImageData는 2D와 3D 픽셀 그리고 3D 화소(voxel) 데이터를 나타낸다.

그림 24.2 데이터 셋 클래스

24.2.3. 파이프라인 아키텍처

VTK은 여러 개의 주요 서브시스템으로 이루어진다. 아마도 시각화 패키지와 연관된 대부분 서브시스템은 데이터 플로우/파이프라인 아키텍처이다. 개념적으로, 파이프라인 아키텍처는 객체의 세 가지 기본 클래스로 이루어진다: 데이터를 나타내는 객체(위에서 살펴본 vtkDataObject), 하나의 형태에서 다른 형태로 데이터 객체의 처리, 변환, 필터 또는 연결(map)하는 객체(vtkAlgorithm) 그리고 인터리브드(interleaved) 데이터의 연결 그래프를 제어하고 객체를 처리하는, 파이프라인을 실행하기 위한 객체(vtkExecutive). 그림 24.3은 일반적인 파이프라인을 묘사한다.

그림 24.3 일반적인 파이프라인

개념적으로는 단순하지만, 실제로 파이프라인 아키텍처를 구현하는 것은 어렵다. 한 가지 이유가 데이터의 표현이 복잡할 수 있다는 것이다. 예로, 일부 데이터셋(dataset)은 계층 구조나 데이터 그룹으로 이뤄져서, 데이터 전체를 실행하는 것은 적지 않은 반복이나 재귀가 필요하다. 문제를 절충하기 위해, 병렬 처리(공유 메모리 또는 확장할 수 있는, 분산 방식을 사용할지)는 데이터를 조각으로 분리하는 것을 필요로 하고, 파생된 것과 같은 지속적으로 바운드리 정보를 연산하기 위해 조각들이 중첩될 필요가 있을 수 있다.

또한, 알고리즘 객체는 자신의 특수한 복잡성을 소개한다. 어떤 알고리즘은 다중 입력을 받고/또는 다른 타입으로 다중 출력을 만들 수도 있다. 막대 그래프를 계산하는 예에서, 일부는 근처에 데이터로 동작할(예로, 셀의 중심을 계산하는) 수 있지만, 다른 것은 전역 정보가 필요하다. 이런 모든 경우에, 알고리즘이 입력값들을 불변으로 다루어서 출력값을 만들기 위해서 단순히 입력값을 읽기만 한다. 이것은 데이터가 다중 알고리즘에 입력으로 사용할 수 있기 때문이고, 하나의 알고리즘이 다른 것의 입력을 무시하는 것은 좋은 생각이 아니다.

마지막으로, 관리(the executive)는 실행 전략에 따라 복잡해질 수 있다. 일부의 경우, 필터 사이에 중간 결과를 캐시 하도록 원할 수도 있다. 이것은 파이프라인에 있는 어떤 것이 변한다면 수행될 재연산의 양을 최소화한다. 반면에, 연산을 위해 더는 필요하지 않은 데이터를 해제하기 원하기 경우에, 시각화 데이터셋은 거대할 수 있다. 마지막으로, 파이프라인이 반복적인 방식으로 동작하는 것이 필요한, 데이터의 다중 해상도 처리와 같은 복잡한 실행 전략이 있다.

이런 개념의 일부 예를 보여주고 파이프라인 아키텍처를 더 설명하기 위해, 다음의 C++ 예제를 살펴보자.

vtkPExodusIIReader *reader = vtkPExodusIIReader::New();
reader->SetFileName("exampleFile.exo");
vtkContourFilter *cont = vtkContourFilter::New();
cont->SetInputConnection(reader->GetOutputPort());
cont->SetNumberOfContours(1);
cont->SetValue(0, 200);
vtkQuadricDecimation *deci = vtkQuadricDecimation::New();
deci->SetInputConnection(cont->GetOutputPort());
deci->SetTargetReduction( 0.75 );
vtkXMLPolyDataWriter *writer = vtkXMLPolyDataWriter::New();
writer->SetInputConnection(deci->GetOuputPort());
writer->SetFileName("outputFile.vtp");
writer->Write();

이 예에서, reader 객체는 크고 비구조화된 그리드(또는 메쉬) 데이터 파일을 읽는다. 다음 필터는 메쉬에서 등위면(isosurfac) 을 생성한다. vtkQuadricDecimation 필터는 약화시켜서, 다각형 데이터셋인 등위면의 크기를 줄인다(즉, 등위를 나타내는 삼각형의 개수를 줄이는 것). 마지막으로 감소시킨 후, 감소한 새로운 데이터 파일을 다시 디스크에 저장한다. 실제 파이프라인 실행은 writer가 Write() 메서드를 호출해서 발생한다(즉, 데이터에 대한 요구 시).

이 예제에서 설명한 것처럼, VTK의 파이프라인 실행 방법은 요구 주도(demand driven)이다. writer나 mapper(데이터 렌더링 객체)와 같은 싱크(sink)가 데이터가 필요할 때, 입력을 요청한다. 이미 입력 필터가 적절한 데이터를 가지고 있다면, 단순히 싱크에 실행 제어를 반환한다. 그러나 입력이 적절한 데이터를 가지고 있지 않다면, 그것을 계산할 필요가 있다. 따라서 데이터에 대한 입력을 처음에 요청해야 한다. 이 처리는 필터나 소스가 “적절한 데이터”를 가지거나 파이프라인이 시작에 도달할 때까지 업스트림이 파이프라인을 따라 계속될 것이다. 그리고 필터가 가리키는 곳은 정확한 순서로 실행할 것이고, 요청된 파이프라인이 가리키는 장소로 데이터가 흐를 것이다.

여기서 “적절한 데이터” 의미를 확장해야 한다. 기본적으로, VTK 소스나 필터를 실행한 후, 그 출력은 미래에 불필요한 실행을 피하려고 파이프라인으로 캐시한다. 이것은 메모리의 비용에서 연산(계산)과 I/O를 최소화하기 위한 것이고, 설정할 수 있는 행동이다. 파이프라인은 데이터 객체와 더불어 이런 데이터 객체가 만들어진 조건에 대한 메타데이터도 캐시한다. 이 메타데이터는 데이터 객체가 언제 연산 됐는지를 수집하는 타임스탬프(즉, 연산시간)를 포함한다.

그래서 가장 간단한 경우, “적절한 데이터”는 모든 업스트림 파이프라인 객체가 수정된 후 연산된 것이다. 다음의 예제를 고려해서, 이 행동을 예로 드는 것이 더 쉽다. 이전 VTK 프로그램의 끝에 다음을 추가해 보자:

vtkXMLPolyDataWriter *writer2 = vtkXMLPolyDataWriter::New();
writer2->SetInputConnection(deci->GetOuputPort());
writer2->SetFileName("outputFile2.vtp");
writer2->Write();

앞에서 설명한 것처럼, 처음 writer->Write 호출은 전체 파이프라인의 실행을 유발한다. writer2->Write()를 호출할 때, 파이프라인은 감소(decimation) 필터, 윤곽(contour) 필터와 reader의 수정된 시간이 있는 캐시의 타임스탬프를 비교할 때, 감소 필터의 캐시 결과가 최신인지 알게 될 것이다. 따라서 데이터 요청은 이전 writer2를 전파할 필요가 없다. 이제, 다음 변화를 생각해보자.

cont->SetValue(0, 400);

vtkXMLPolyDataWriter *writer2 = vtkXMLPolyDataWriter::New();
writer2->SetInputConnection(deci->GetOuputPort());
writer2->SetFileName("outputFile2.vtp");
writer2->Write();

이제 파이프라인 관리는 윤곽과 감소 필터가 마지막으로 실행한 후에 윤곽 필터가 수정된 것을 알게 될 것이다. 따라서 이 두 개의 필터에 대한 캐시가 오래되었고, 두 필터는 다시 실행해야 한다. 그러나 reader는 윤곽 필터 이전에 수정되지 않아서, reader의 캐시가 유효하고 그러므로 reader는 다시 실행할 필요가 없다.

여기에 설명한 시나리오는 요구-주도(demand-driven) 파이프라인의 가장 간단한 예제이다. VTK의 파이프라인은 훨씬 더 정교하다. 필터나 싱크가 데이터가 필요할 때, 특정 데이터 서브셋을 요청하기 위해 부가적인 정보를 제공할 수 있다. 예를 들면, 필터는 데이터 스트리밍 조각으로 핵심에서 벗어난 분석을 수행할 수 있다. 예제를 설명하기 위해 이전 예제를 변경해 보자.

vtkXMLPolyDataWriter *writer = vtkXMLPolyDataWriter::New();
writer->SetInputConnection(deci->GetOuputPort());
writer->SetNumberOfPieces(2);
writer->SetWritePiece(0);
writer->SetFileName("outputFile0.vtp");
writer->Write();
writer->SetWritePiece(1);
writer->SetFileName("outputFile1.vtp");
writer->Write();

위의 writer는 독립적으로 스트림된 두 개의 조각에 데이터를 로드하고 처리하기 위해 업스트림 파이프라인을 요청한다. 이전에 설명한 간단한 실행 로직이 여기서는 동작하지 않으리라는 것을 알고 있을 것이다. 이 로직에 따라, 두 번째에 Write 함수를 호출한 때, 업스트림이 변경되지 않았기 때문에 파이프라인은 다시 실행할 필요가 없다.

따라서 더 복잡한 경우를 해결하기 위해, 관리는 이와 같은 조각 요청을 처리하기 위해 부가적인 로직을 가지고 있다. VTK의 파이프라인 실행은 실제로 다중 단계로 이루어진다. 실제로 데이터 객체의 연산은 가장 마지막 단계이다. 그전의 단계는 요청 단계이다. 이것은 싱크와 필터가 곧 있을 연산에서 원하는 것을 업스트림에 알릴 수 있다. 위의 예제에서, writer는 2개 중에 0번의 조각을 원하는 것을 업스트림의 입력으로 알릴 것이다. 이 요청은 실제로 reader에 완전히 전파할 것이다.

파이프라인이 실행할 때, reader는 데이터의 서브셋을 읽을 필요가 있다는 것을 알 것이다. 게다가, 캐시한 데이터에 해당하는 조각에 대한 정보는 객체를 위해 메타데이터에 저장된다. 다음번에 필터는 그것의 입력으로부터 데이터를 요청하고, 이 메타데이터는 현재 요청과 비교될 것이다. 따라서 이 예제에서 파이프라인은 다른 조각 요청을 처리하기 위해 다시 실행할 것이다.

필터가 만들 수 있는 여러 가지 더 많은 요청의 종류가 있다. 이 요청은 특정 시간 단계, 특정 구조화의 확장 또는 많은 유령 계층(즉, 이웃 정보를 연산하기 위한 바운드리 계층)에 대한 요청을 포함한다. 게다가, 요청 단계 중에, 각 필터는 다운스트림에서 요청을 수정하도록 한다. 예를 들어, 스트림(즉, 스트림라인 필터)할 수 없는 필터는 조각 요청을 무시하고 전체 데이터를 요청할 수 있다.

24.2.4. 서브시스템 렌더링

언뜻 보기에, VTK는 3D 화면을 만드는 컴포넌트에 해당하는 클래스로 간단한 객체-지향 렌더링 모델을 가지고 있다. 예를 들어, vtkActor는 vtkCamera, 아마 vtkRenderWindow에 있는 다중 vtkRenderer 들과 협력하는 vtkRenderer가 렌더링 하는 객체이다. 화면은 하나 이상의 vtkLight에서 빛을 받는다. 각 vtkActor의 위치는 vtkTransform이 제어하고, 액터(actor)의 모습은 vtkProperty로 명시한다.

마지막으로, 액터의 기하학적인 표현은 vtkMapper가 정의한다. 매퍼(Mapper)는 렌더링 시스템의 인터페이스와 더불어 데이터 처리 파이프라인 종료를 제공하는 중요한 역할을 한다. 데이터를 감소시키고 파일에 결과를 저장하고, 다음에 매퍼를 사용해서 결과를 시각화하거나 상호작용하는 예제를 생각해 보자:

vtkOBJReader *reader = vtkOBJReader::New();
reader->SetFileName("exampleFile.obj");
vtkTriangleFilter *tri = vtkTriangleFilter::New();
tri->SetInputConnection(reader->GetOutputPort());
vtkQuadricDecimation *deci = vtkQuadricDecimation::New();
deci->SetInputConnection(tri->GetOutputPort());
deci->SetTargetReduction( 0.75 );
vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
mapper->SetInputConnection(deci->GetOutputPort());
vtkActor *actor = vtkActor::New();
actor->SetMapper(mapper);
vtkRenderer *renderer = vtkRenderer::New();
renderer->AddActor(actor);
vtkRenderWindow *renWin = vtkRenderWindow::New();
renWin->AddRenderer(renderer);
vtkRenderWindowInteractor *interactor = vtkRenderWindowInteractor::New();
interactor->SetRenderWindow(renWin);
renWin->Render();

여기 하나의 액터, 렌더러 그리고 윈도우 렌더는, 렌더링 시스템에 파이프라인을 연결하는 하나의 매퍼를 추가해서 생성한다. 또한, 마우스와 키보드 이벤트를 캡처하고 캡처한 데이터를 카메라 조작이나 다른 액션으로 변환하는 인스턴스인 vtkRenderWindowInteractor의 추가를 주의해라. 이 변환 과정은 vtkInteractorStyle을 통해서 정의한다(아래에서 더 살펴본다).

기본적으로, 많은 인스턴스와 데이터 값은 씬 내부에서 설정된다. 예를 들면, 단일 기본 (헤드)라이트와 속성뿐 아니라 단위 변환이 만들어 진다.

시간이 지남에 따라 이 객체 모델은 더 정교화되고 있다. 상당한 복잡도가 렌더링 처리의 측면에서 구체화하는 파생된 클래스를 개발하는 것에서 비롯된다. 현재 vtkActor는 vtkProp(무대에 발견하는 소품과 같은)의 구체화이고, 2D 오버레이 그래픽과 텍스트 렌더링, 구체화한 3D 객체 렌더링, 그리고 심지어 볼륨 렌더링(volume rendering)과 같은 고급 렌더링 기술 또는 GPU 구현을 지원하기 위한 이런 소품들이 아주 많이 있다(그림 24.4를 보라).

비슷하게도, VTK가 지원하는 데이터 모델이 증가하는 것과 마찬가지로, 데이터를 렌더링 시스템에 인터페이스하는 다양한 매퍼가 있다. 확장의 중요한 또 다른 영역은 변환 계층 구조이다. 원래 간단한 선형 4X4 변환 매트릭스가 TPS(thin-plate spline) 변환을 포함해서 비선형 변환을 지원하는 강력한 계층 구조가 되었다. 예로, vtkPolyDataMapper는 디바이스에 종속적인 서브클래스를 가진다(예로, vtkOpenGLPolyDataMapper). 최근에, 그림 24.4에서 보이는 “페인터(painter)” 파이프라인이라는 정교화된 그래픽 파이프라인으로 교체됐다.

TPS : 평면상의 점들에서 주어지는 데이터값을 보간하는 곡면을 찾는 방법, http://en.wikipedia.org/wiki/Thin_plate_spline

그림 24.4 디스플레이 클래스

페인터 설계는 특수한 렌더링 효과를 제공하기 위해 결합할 수 있는 렌더링 데이터를 위한 다양한 기술을 지원한다. 이 기능은 1994년에 처음으로 구현한 간단한 vtkPolyDataMapper를 크게 능가한다.

시각화 시스템의 또 다른 중요한 측면은 서브시스템의 선택이다. VTK에는 픽 기능(pick operation)후에 다양한 수준의 정보를 제공하는 객체뿐 아니라, 대략 소프트웨어 메서드(예로, 레이캐스팅 )에 비해 하드웨어 기반 메서드에 기반을 둔 vtkProp을 선택하는 객체로 분류하는 “픽커(pickers)” 계층 구조가 있다;

예를 들면, 일부 픽커는 단지 선택된 vtkProp의 지정 없이 XYZ 공간에서 위치를 제공한다; 다른 픽커는 선택된 vtkProp 뿐 아니라 프롭 기하학에서 정의한 메쉬를 구성하는 특정 포인트나 셀을 제공한다.

24.2.5. 이벤트와 상호작용

데이터와 상호작용하는 것은 시각화의 필수 부분이다. VTK에서 이것은 다양한 방법으로 발생한다. 가장 간단한 단계에서, 사용자는 이벤트를 관찰할 수 있고, 커맨드를 통해 적절하게 응답할 수 있다(커맨드/옵저버 디자인 패턴). vtkObject의 모든 서브 클래스는 객체로 자신을 등록한 옵저버 목록을 유지한다. 등록하는 동안, 이벤트가 발생하는 경우 옵저버는, 호출되는 연관 커맨드를 추가해서 흥미있는 특정 이벤트를 지정한다.

이것이 어떻게 동작하는 보기 위해, 세 가지 StartEvent, ProgressEvent와 EndEvent 이벤트를 관찰하는 옵저버를 가지고 있는 필터(다각형 감소 필터)에서 다음의 예제를 생각해보자. 이런 이벤트는 필터가 실행을 시작하고, 주기적으로 실행하는 내내, 다음에 실행을 완료한 때에 호출된다. 다음의 vtkCommand 클래스는 알고리즘을 실행하는 데 걸리는 시간에 관련된 적당한 정보를 출력하는 Execute 메서드를 가지고 있다.

classvtkProgressCommand : public vtkCommand
{public:
staticvtkProgressCommand *New() { return new vtkProgressCommand; }
virtual void Execute(vtkObject *caller, unsigned long, void *callData)
    {
double progress = *(static_cast<double*>(callData));
std::cout<< "Progress at "<< progress<<std::endl;     } }; vtkCommand* pobserver = vtkProgressCommand::New(); vtkDecimatePro *deci = vtkDecimatePro::New(); deci->SetInputConnection( byu->GetOutputPort() );
deci->SetTargetReduction( 0.75 );
deci->AddObserver( vtkCommand::ProgressEvent, pobserver );

이것은 상호작용의 기본적인 형태이지만, VTK를 사용하는 많은 애플리케이션에 기본적인 요소이다. 예를 들면, 위의 간단한 코드는 GUI 프로그레스 바를 보여주고 관리하기 위해서 쉽게 바꿀 수 있다. 또한, 이 커맨드/옵저버 서브시스템은 질의, 조작 그리고 데이터 편집을 위해 정교화한 상호 작용 객체인 3D 위젯의 핵심으로 다음에서 설명한다.

위 예제를 참조하면, VTK에서 미리 정의한 이벤트를 주의하는 것이 중요하지만, 사용자 정의 이벤트를 위한 백도어가 있다. vtkCommand 클래스는 미리 정의된 이벤트(즉, 위 예에서 vtkCommand::ProgressEvent)와 더불어 사용자 이벤트도 정의한다. 일반적으로, UserEvent는 간단한 필수적인 값이고, 이 값은 애플리케이션 사용자 정의 이벤트 셋의 오프셋(offset)의 시작값으로 사용된다. 그래서, 예들 들면, vtkCommand::UserEvent+100은 VTK가 정의한 이벤트 셋 이외에 특정 이벤트를 참조할 수도 있다.

사용자 관점에서, VTK 위젯은 사용자가 핸들 조작이나 다른 기하학적인 기능으로 처리할 수 있는 것을 제외하면 씬에서 액터로 나타난다(핸들 조작과 기하학적 특징 처리는 앞에서 설명한 픽킹 기능을 기반으로 한다). 이 위젯과의 상호 작용은 꽤 직관적이다: 사용자는 구 모양의 핸들을 잡고 그것을 움직이거나, 선을 잡고 그것을 움직인다. 그러나 씬의 뒤에서는, 이벤트가 발생하고 적절히 개발된 애플리케이션은 이 이벤트를 관찰할 수 있고, 다음에 적절한 액션을 한다. 예를 들면, 이벤트들은 다음의 vtkCommand::InteractionEvent을 종종 실행시킨다.

vtkLW2Callback *myCallback = vtkLW2Callback::New();
myCallback->PolyData = seeds;    // streamlines seed points, updated on interaction
myCallback->Actor = streamline;  // streamline actor, made visible on interaction
vtkLineWidget2 *lineWidget = vtkLineWidget2::New();
lineWidget->SetInteractor(iren);
lineWidget->SetRepresentation(rep);
lineWidget->AddObserver(vtkCommand::InteractionEvent,myCallback);

실제로 VTK 위젯은 vtkInteractorObserver의 서브클래스와 vtkProp의 서브 클래스, 두 개의 객체를 사용해서 만든다. vtkInteractorObserver는 단순하게 랜더 윈도우(즉, 마우스와 키보드 이벤트)에서 사용자 상호 작용을 관찰하고 그것을 처리한다. vtkProp의 서브클래스(즉, 액터)는 vtkInteractorObserver가 간단하게 조작한다. 일반적으로 그런 조작은 하이라이트 처리, 커서 모습 변화, 그리고 데이터 변환을 포함해서 vtkProp의 기하학을 수정하도록 구성하고 있다. 물론, 특정 위젯은 위젯 행동의 뉘앙스를 제어하기 위해 서브클래스가 필요하고, 현재 시스템에는 50개 이상의 다른 위젯이 있다.

24.2.6. 라이브러리 요약

VTK는 큰 소프트웨어 툴킷이다. 최근에 시스템은 대략 150만 라인의 코드(주석은 포함하지만, 자동으로 만들어낸 래퍼 소프트웨어를 포함하지 않는다)와 대략 1,000개의 C++ 클래스로 이뤄져 있다. 시스템의 복잡성을 관리하고, 빌드 및 링크하는 시간을 줄이기 위해 시스템은 수십 개의 서브 디렉터리로 분할되었다. 표 24.1은 라이브러리가 제공하는 기능에 대한 간단한 요약 설명과 함께, 서브 디렉터리의 목록이다.

Common 핵심 VTK 클래스
Filtering 파이프라인 데이터플로우를 관리하는 데 사용하는 클래스
Rendering 렌더링, 픽킹, 이미지 뷰와 상호 작용
VolumeRendering 볼륨 렌더링 기술
Graphics 3D 기하학 처리
GenericFiltering 비선형 3D 기하학 처리
Imaging 이미지 파이프라인
Hybrid 그래픽과 이미징의 두 기능이 필요한 클래스
Widgets 정교한 상호 작용
IO VTK 입력과 출력
Infovis 정보 시각화
Parallel 병렬 처리(제어기와 통신기)
Wrapping Tcl, 파이썬 그리고 자바 래핑 지원
Examples 확장된, 잘 문서화된 예제
표 24.1 VTK 서브 디렉토리

24.3. 회고와 기대

VTK는 대단히 성공한 시스템이다. 1993년 처음 개발하기 시작했지만, VTK를 개발하는 내내 계속 강해지고 있고, 오히려 개발 속도는 증가하고 있다. 이 장에서는 몇 가지 교훈과 향후 도전에 대해서 살펴본다.

24.3.1. 성장 관리

VTK의 경험에서 가장 놀라운 면 중의 하나가 프로젝트가 오래 지속된다는 것이다. 개발 속도는 몇 개의 주요 요인에 달려있다.

• 새로운 알고리즘과 기능이 계속해서 추가된다. 예를 들어, 정보학 서브시스템은 최근에 중요하게 추가된 것이다(Titan, Sandia National Labs와 Kitware에서 주로 개발했다). 새로운 과학 데이터셋 타입을 위한 기능뿐 아니라, 추가적인 도표와 렌더링 클래스 또한 추가되었다. 또 다른 중요한 추가로 3D 상호 작용 위젯이 있다. 마지막으로, GPU 기반 렌더링의 지속적인 발전과 데이터 처리가 VTK에 새로운 기능을 만들어 내고 있다.
• VTK의 알려짐과 사용의 증가는 심지어 더 많은 사용자와 개발자를 커뮤니티에 추가하는 지속적인 프로세스이다. 예를 들어, ParaView는 VTK를 기반으로 한 가장 인기 있는 과학용 시각화 애플리케이션이고 고성능 컴퓨팅 커뮤니티에서 높이 평가하고 있다. 3D 슬라이서(3D Slicer)는 주로 VTK를 기반으로 하는 주요 생체 의학 컴퓨팅 플랫폼이고, 매년 수백만 달러의 재정 지원을 받는다.
• VTK의 개발 프로세스는 계속 발전하고 있다. 최근에, 소프트웨어 프로세스 도구인 CMake, CDash, CTest 그리고 CPack이 VTK 빌드 환경으로 통합되었다. 더 최근에는, VTK 코드 저장소를 Git로 이전했고, 작업 흐름이 더 정교해졌다. 이런 개선은 VTK가 과학용 컴퓨팅 커뮤니티에서 소프트웨어 개발의 선두에 있다는 것을 확신하게 한다.

성장은 흥미롭지만, 소프트웨어 시스템의 제품을 검증하고, VTK의 미래를 잘 예언하고, 제대로 관리하는 것은 매우 어려울 수 있다. 결과적으로, VTK의 가까운 시기의 미래는 소프트웨어와 더불어, 커뮤니티의 성장을 관리하는데 더 초점을 맞춘다. 이것과 관련해서 여러 단계를 취했다.

첫 번째, 공식화한 관리 구조를 만들었다. 아키텍처 리뷰 보드(Architecture Review Board)는 고수준에 주력하고, 전략적인 이슈, 커뮤니티와 기술의 개발을 도와주기 위해 만들었다. 또한, VTK 커뮤니티는 특정 VTK 서브시스템의 기술적 개발을 도와주기 위해 인정받은 토픽 리드(Topic Lead)팀을 만들었다.

다음으로, 일반적으로 사용자와 개발자가 툴킷의 작은 서브시스템으로 작업하기를 원하고 전체 패키지에 대해 빌드와 링크를 원하지 않다는 것을 알고 있을 뿐 아니라, git가 소개하는 워크플로우 기능에 부분적으로 대응하도록, 툴킷을 더 모듈화할 계획이 있다. 게다가, 성장하는 커뮤니티를 지원하기 위해, 툴킷의 핵심 부분이 아니더라도, 새로운 기능의 기여와 서브 시스템의 지원은 중요하다. 느슨하고, 모듈화된 모듈의 컬렉션을 만들어서, 핵심 안정성을 유지하면서 주변에 상당히 많은 기여를 수용하는 것이 가능하다.

24.3.2. 기술 혁신

소프트웨어 프로세스 외에, 파이프라인 개발에 많은 기술적인 혁신이 있다.

• 공동 처리(Co-processing)는 시각화 엔진을 시뮬레이션 코드에 통합하는 기능이고, 주기적으로 시각화를 위해 추출한 데이터를 만든다. 이 기술은 많은 양의 완전한 솔루션 데이터 출력의 필요성을 감소시킨다.
• VTK에서 데이터 처리 파이프라인은 여전히 너무 복잡하다. 서브시스템을 단순화하고 리팩토링이 진행중이다.
• 데이터와 직접 상호 작용하는 기능이 사용자에게 점점 인기를 얻고 있다. VTK에 많은 위젯 셋이 있지만, 터치 스크린 기반과 3D 메서드를 포함하는 더 많은 상호 작용 기술이 나타나고 있다. 상호 작용은 빠른 속도로 개발이 계속될 것이다.
• 컴퓨터 화학은 재료 디자이너와 엔지니어에게 중요도가 증가하고 있다. 화학 데이터를 시각화하고 상호 작용하는 기능이 추가되고 있다.
• VTK의 렌더링 시스템은 너무 복잡해서, 새로운 클래스를 확장하거나 새로운 렌더링 기술을 지원하는 것을 어렵게 만든다고 비판받고 있다. 게다가, 많은 사용자가 요구하는 어떤 것에 대해, 화면 그래프의 개념을 직접 지원하지 않는다.
• 마지막으로 새로운 형태의 데이터가 계속 나타나고 있다. 예를 들어, 의학 분야에서 다양한 해상도의 계층적인 볼륨 데이터셋(예로, 다중초점 형광현미경으로 일부 확대).

24.3.3. 오픈 과학

마지막으로, 키트웨어(Kitware)와 더 일반적인 VTK 커뮤니티가 오픈 과학에 헌신하고 있다. 실용적으로, 이것은 오픈 데이터, 오픈 발행, 그리고 오픈 소스를 널리 알리는 방법이다(재현할 수 있는 과학적 시스템을 만드는 것을 확인하는 필수 기능). 오픈 소스 그리고 오픈 데이터 시스템으로 VTK는 오랫동안 배포되었지만, 문서화는 부족하다.

좋은 책[Kit10,SML06]이 있지만, 새로운 소스 코드 기여를 포함해서 기술적인 발행을 수집하는 다양한 특별한 방법이 있다. 문서, 소스 코드, 데이터 그리고 유효한 테스트 이미지로 구성한 글이 가능한 VTK Journal과 같은 새로운 발행 방법을 개발해서 상황이 개선되고 있다. 또한, 저널은 제출된 글에 대한 사람의 리뷰와 더불어 자동화된 코드 리뷰가 가능하다(VTK의 질적인 소프트웨어 테스팅 프로세스를 사용해서).

24.3.4. 교훈

VTK가 성공적이지만, 좋지 않은 것들도 많다:

• 모듈화 설계: 클래스의 모듈화는 좋은 선택이었다. 예를 들어, 픽셀당 객체를 만드는 것과 같은 어리석은 것을 하지 않고, 후드 아래에서 픽셀 데이터의 데이터 배열을 다루는 고 수준의 vtkImageClass를 만들었다. 그러나 일부 경우에 vtkImageClass가 너무 고 수준이고 복잡했다. 많은 인스턴스를 더 작게 리팩토링 해야 하고, 이 리팩토링은 계속되고 있다. 하나의 주요한 예제는 데이터 처리 파이프라인이다. 처음에, 파이프라인은 데이터와 알고리즘 객체의 상호작용으로 암시적으로 구현했다. 결국에, 데이터와 알고리즘 사이의 상호작용을 조정하고, 다른 데이터 프로세싱 전략을 구현하기 위해 명시적인 파이프라인 실행 객체를 만들어야 한다는 것을 알게 되었다.
• 중요한 개념 실수: 일단 가장 큰 후회는 C++ 이터레이터(iterator)를 널리 사용하지 않았다는 것이다. VTK에서 데이터 순회의 많은 경우 과학 프로그래밍 언어 포트란과 비슷하다. 이터레이터의 추가적인 유연성은 시스템에 중요한 장점이 됐을 것이다. 예를 들어, 이터레이터는 데이터의 로컬 지역 또는 일부 반복 기준에 맞는 데이터만 처리하는데 매우 유리하다.
• 설계 문제: 물론 최상의 안이 아닐 수 있지만, 설계 결정의 오랜 목록이 있다. 더 좋은 설계를 만들 때마다, 여러 세대에 이어서 데이터 실행 파이프라인과 싸워왔다. 렌더링 시스템은 너무 복잡하고 그것에서 확장하는 것은 어렵다. 또 다른 도전은 VTK의 초기 개념에서 발생한다: 데이터를 보기 위한 시각화 시스템이 읽기 전용이라는 것을 알았다. 그러나 요즘 고객은 주요하게 다른 데이터 구조가 필요한 데이터를 편집할 수 있기를 자주 원한다.

VTK와 같은 오픈 소스 시스템에 대한 좋은 것 중의 하나가 실수의 많은 것들이 고쳐질 것이라는데 있다. 우리의 활동적이고, 유능한 개발 커뮤니티는 매일 시스템을 개선하고 가까운 미래에도 계속되기를 기대한다.

[번역 : AOSA Volume 1, 24장] VTK”에 대한 1개의 생각

  1. Johne54

    Very interesting subject , appreciate it for posting . All human beings should try to learn before they die what they are running from, and to, and why. by James Thurber. aeecceeedekc

    응답

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.